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:
Hugo Benichi
2017-03-30 23:18:10 +09:00
parent 4701121f3e
commit 471b62a6b8

View File

@@ -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;
mNetTransitionWakeLock.acquire();
mWakelockLogs.log(String.format("ACQUIRE %d for %s", serialNum, forWhom));
}
mHandler.sendMessageDelayed(mHandler.obtainMessage(
EVENT_EXPIRE_NET_TRANSITION_WAKELOCK, serialNum, 0),
mNetTransitionWakeLockTimeout);
return; return;
} }
mNetTransitionWakeLock.acquire();
}
mWakelockLogs.log("ACQUIRE for " + forWhom);
Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
mHandler.sendMessageDelayed(msg, mNetTransitionWakeLockTimeout);
}
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) { }
// Cancel self timeout on wakelock hold.
mHandler.removeMessages(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
Message msg = mHandler.obtainMessage(EVENT_CLEAR_NET_TRANSITION_WAKELOCK);
mHandler.sendMessageDelayed(msg, 1000);
}
// 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(); mNetTransitionWakeLock.release();
} }
} mWakelockLogs.log(String.format("RELEASE (%s)", event));
final String result;
if (release) {
result = "released";
} else if (!isHeld) {
result = "already released";
} else {
result = String.format("not released (serial number was %d)", serialNumber);
}
String msg = String.format(
"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)) {