ConnectivityService: simplify WakeLock management
This patch simplifies wakelock management by acknowledging that only one
acquisition at most is in flight at any time. This allows to remove the
serial number associated with wakelock acquisition and to avoid double
release when regaining a default network.
Example of $ adb shell dumpsys connectivity logs:
NetTransition WakeLock activity (most recent first):
03-31 00:15:13.816 - RELEASE (EVENT_CLEAR_NET_TRANSITION_WAKELOCK)
03-31 00:14:59.216 - ACQUIRE for NetworkAgentInfo [WIFI () - 101]
03-31 00:09:05.799 - RELEASE (EVENT_EXPIRE_NET_TRANSITION_WAKELOCK)
03-31 00:08:05.738 - ACQUIRE for NetworkAgentInfo [WIFI () - 100]
Test: watched wakelock section $ adb shell dumpsys connectivity while
turning on and off Wifi (with no other network).
Bug: 36703718
Change-Id: I899b0816c0e41b3991d9540e9b9a604914ff673a
This commit is contained in:
@@ -411,7 +411,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
private Intent mInitialBroadcast;
|
private Intent mInitialBroadcast;
|
||||||
|
|
||||||
private PowerManager.WakeLock mNetTransitionWakeLock;
|
private PowerManager.WakeLock mNetTransitionWakeLock;
|
||||||
private int mNetTransitionWakeLockSerialNumber;
|
|
||||||
private int mNetTransitionWakeLockTimeout;
|
private int mNetTransitionWakeLockTimeout;
|
||||||
private final PowerManager.WakeLock mPendingIntentWakeLock;
|
private final PowerManager.WakeLock mPendingIntentWakeLock;
|
||||||
|
|
||||||
@@ -2395,7 +2394,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
|
if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
|
||||||
removeDataActivityTracking(nai);
|
removeDataActivityTracking(nai);
|
||||||
notifyLockdownVpn(nai);
|
notifyLockdownVpn(nai);
|
||||||
requestNetworkTransitionWakelock(nai.name());
|
ensureNetworkTransitionWakelock(nai.name());
|
||||||
}
|
}
|
||||||
mLegacyTypeTracker.remove(nai, wasDefault);
|
mLegacyTypeTracker.remove(nai, wasDefault);
|
||||||
rematchAllNetworksAndRequests(null, 0);
|
rematchAllNetworksAndRequests(null, 0);
|
||||||
@@ -2842,7 +2841,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case EVENT_EXPIRE_NET_TRANSITION_WAKELOCK:
|
case EVENT_EXPIRE_NET_TRANSITION_WAKELOCK:
|
||||||
case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: {
|
case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: {
|
||||||
handleNetworkTransitionWakelockRelease(msg.what, msg.arg1);
|
handleReleaseNetworkTransitionWakelock(msg.what);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
|
case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
|
||||||
@@ -3065,44 +3064,46 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// This will automatically be cleared after X seconds or a new default network
|
// This will automatically be cleared after X seconds or a new default network
|
||||||
// becomes CONNECTED, whichever happens first. The timer is started by the
|
// becomes CONNECTED, whichever happens first. The timer is started by the
|
||||||
// first caller and not restarted by subsequent callers.
|
// first caller and not restarted by subsequent callers.
|
||||||
private void requestNetworkTransitionWakelock(String forWhom) {
|
private void ensureNetworkTransitionWakelock(String forWhom) {
|
||||||
int serialNum = 0;
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (mNetTransitionWakeLock.isHeld()) return;
|
if (mNetTransitionWakeLock.isHeld()) {
|
||||||
serialNum = ++mNetTransitionWakeLockSerialNumber;
|
return;
|
||||||
|
}
|
||||||
mNetTransitionWakeLock.acquire();
|
mNetTransitionWakeLock.acquire();
|
||||||
mWakelockLogs.log(String.format("ACQUIRE %d for %s", serialNum, forWhom));
|
|
||||||
}
|
}
|
||||||
mHandler.sendMessageDelayed(mHandler.obtainMessage(
|
mWakelockLogs.log("ACQUIRE for " + forWhom);
|
||||||
EVENT_EXPIRE_NET_TRANSITION_WAKELOCK, serialNum, 0),
|
Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
|
||||||
mNetTransitionWakeLockTimeout);
|
mHandler.sendMessageDelayed(msg, mNetTransitionWakeLockTimeout);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleNetworkTransitionWakelockRelease(int eventId, int wantSerialNumber) {
|
// Called when we gain a new default network to release the network transition wakelock in a
|
||||||
final int serialNumber;
|
// second, to allow a grace period for apps to reconnect over the new network. Pending expiry
|
||||||
final boolean isHeld;
|
// message is cancelled.
|
||||||
final boolean release;
|
private void scheduleReleaseNetworkTransitionWakelock() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
serialNumber = mNetTransitionWakeLockSerialNumber;
|
if (!mNetTransitionWakeLock.isHeld()) {
|
||||||
isHeld = mNetTransitionWakeLock.isHeld();
|
return; // expiry message released the lock first.
|
||||||
release = (wantSerialNumber == serialNumber) && isHeld;
|
|
||||||
if (release) {
|
|
||||||
mNetTransitionWakeLock.release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final String result;
|
// Cancel self timeout on wakelock hold.
|
||||||
if (release) {
|
mHandler.removeMessages(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
|
||||||
result = "released";
|
Message msg = mHandler.obtainMessage(EVENT_CLEAR_NET_TRANSITION_WAKELOCK);
|
||||||
} else if (!isHeld) {
|
mHandler.sendMessageDelayed(msg, 1000);
|
||||||
result = "already released";
|
}
|
||||||
} else {
|
|
||||||
result = String.format("not released (serial number was %d)", serialNumber);
|
// Called when either message of ensureNetworkTransitionWakelock or
|
||||||
|
// scheduleReleaseNetworkTransitionWakelock is processed.
|
||||||
|
private void handleReleaseNetworkTransitionWakelock(int eventId) {
|
||||||
|
String event = eventName(eventId);
|
||||||
|
synchronized (this) {
|
||||||
|
if (!mNetTransitionWakeLock.isHeld()) {
|
||||||
|
mWakelockLogs.log(String.format("RELEASE: already released (%s)", event));
|
||||||
|
Slog.w(TAG, "expected Net Transition WakeLock to be held");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mNetTransitionWakeLock.release();
|
||||||
}
|
}
|
||||||
String msg = String.format(
|
mWakelockLogs.log(String.format("RELEASE (%s)", event));
|
||||||
"RELEASE %d by %s: %s", wantSerialNumber, eventName(eventId), result);
|
|
||||||
mWakelockLogs.log(msg);
|
|
||||||
if (DBG) log(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 100 percent is full good, 0 is full bad.
|
// 100 percent is full good, 0 is full bad.
|
||||||
@@ -4925,17 +4926,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
makeDefault(newNetwork);
|
makeDefault(newNetwork);
|
||||||
// Log 0 -> X and Y -> X default network transitions, where X is the new default.
|
// Log 0 -> X and Y -> X default network transitions, where X is the new default.
|
||||||
logDefaultNetworkEvent(newNetwork, oldDefaultNetwork);
|
logDefaultNetworkEvent(newNetwork, oldDefaultNetwork);
|
||||||
synchronized (ConnectivityService.this) {
|
// Have a new default network, release the transition wakelock in
|
||||||
// have a new default network, release the transition wakelock in
|
scheduleReleaseNetworkTransitionWakelock();
|
||||||
// a second if it's held. The second pause is to allow apps
|
|
||||||
// to reconnect over the new network
|
|
||||||
if (mNetTransitionWakeLock.isHeld()) {
|
|
||||||
mHandler.sendMessageDelayed(mHandler.obtainMessage(
|
|
||||||
EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
|
|
||||||
mNetTransitionWakeLockSerialNumber, 0),
|
|
||||||
1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {
|
if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user