Merge "Fix issue #26879170: Adjust doze maintenance windows..." into nyc-dev

This commit is contained in:
Dianne Hackborn
2016-04-08 19:29:00 +00:00
committed by Android (Google) Code Review
2 changed files with 193 additions and 55 deletions

View File

@@ -39,7 +39,9 @@ import android.location.LocationRequest;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.INetworkPolicyManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.BatteryStats;
import android.os.Binder;
@@ -114,6 +116,7 @@ public class DeviceIdleController extends SystemService
private IBatteryStats mBatteryStats;
private PowerManagerInternal mLocalPowerManager;
private PowerManager mPowerManager;
private ConnectivityService mConnectivityService;
private AlarmManagerService.LocalService mLocalAlarmManager;
private INetworkPolicyManager mNetworkPolicyManager;
private DisplayManager mDisplayManager;
@@ -128,6 +131,7 @@ public class DeviceIdleController extends SystemService
private boolean mLightEnabled;
private boolean mDeepEnabled;
private boolean mForceIdle;
private boolean mNetworkConnected;
private boolean mScreenOn;
private boolean mCharging;
private boolean mNotMoving;
@@ -173,16 +177,20 @@ public class DeviceIdleController extends SystemService
private static final int LIGHT_STATE_PRE_IDLE = 3;
/** Device is in the light idle state, trying to stay asleep as much as possible. */
private static final int LIGHT_STATE_IDLE = 4;
/** Device is in the light idle state, we want to go in to idle maintenance but are
* waiting for network connectivity before doing so. */
private static final int LIGHT_STATE_WAITING_FOR_NETWORK = 5;
/** Device is in the light idle state, but temporarily out of idle to do regular maintenance. */
private static final int LIGHT_STATE_IDLE_MAINTENANCE = 5;
private static final int LIGHT_STATE_IDLE_MAINTENANCE = 6;
/** Device light idle state is overriden, now applying deep doze state. */
private static final int LIGHT_STATE_OVERRIDE = 6;
private static final int LIGHT_STATE_OVERRIDE = 7;
private static String lightStateToString(int state) {
switch (state) {
case LIGHT_STATE_ACTIVE: return "ACTIVE";
case LIGHT_STATE_INACTIVE: return "INACTIVE";
case LIGHT_STATE_PRE_IDLE: return "PRE_IDLE";
case LIGHT_STATE_IDLE: return "IDLE";
case LIGHT_STATE_WAITING_FOR_NETWORK: return "WAITING_FOR_NETWORK";
case LIGHT_STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
case LIGHT_STATE_OVERRIDE: return "OVERRIDE";
default: return Integer.toString(state);
@@ -315,17 +323,27 @@ public class DeviceIdleController extends SystemService
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
int plugged = intent.getIntExtra("plugged", 0);
updateChargingLocked(plugged != 0);
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Uri data = intent.getData();
String ssp;
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
removePowerSaveWhitelistAppInternal(ssp);
switch (intent.getAction()) {
case ConnectivityManager.CONNECTIVITY_ACTION: {
synchronized (DeviceIdleController.this) {
updateConnectivityStateLocked(intent);
}
}
} break;
case Intent.ACTION_BATTERY_CHANGED: {
synchronized (DeviceIdleController.this) {
int plugged = intent.getIntExtra("plugged", 0);
updateChargingLocked(plugged != 0);
}
} break;
case Intent.ACTION_PACKAGE_REMOVED: {
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
Uri data = intent.getData();
String ssp;
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
removePowerSaveWhitelistAppInternal(ssp);
}
}
} break;
}
}
};
@@ -1318,6 +1336,7 @@ public class DeviceIdleController extends SystemService
readConfigFileLocked();
updateWhitelistAppIdsLocked();
mNetworkConnected = true;
mScreenOn = true;
// Start out assuming we are charging. If we aren't, we will at least get
// a battery update the next time the level drops.
@@ -1343,6 +1362,8 @@ public class DeviceIdleController extends SystemService
mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"deviceidle_maint");
mActiveIdleWakeLock.setReferenceCounted(false);
mConnectivityService = (ConnectivityService)ServiceManager.getService(
Context.CONNECTIVITY_SERVICE);
mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class);
mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
@@ -1395,11 +1416,14 @@ public class DeviceIdleController extends SystemService
filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
getContext().registerReceiver(mReceiver, filter);
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
mDisplayManager.registerDisplayListener(mDisplayListener, null);
updateConnectivityStateLocked(null);
updateDisplayLocked();
}
}
@@ -1680,6 +1704,35 @@ public class DeviceIdleController extends SystemService
}
}
void updateConnectivityStateLocked(Intent connIntent) {
if (mConnectivityService != null) {
NetworkInfo ni = mConnectivityService.getActiveNetworkInfo();
boolean conn;
if (ni == null) {
conn = false;
} else {
if (connIntent == null) {
conn = ni.isConnected();
} else {
final int networkType =
connIntent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
ConnectivityManager.TYPE_NONE);
if (ni.getType() != networkType) {
return;
}
conn = !connIntent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
false);
}
}
if (conn != mNetworkConnected) {
mNetworkConnected = conn;
if (conn && mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
stepLightIdleStateLocked("network");
}
}
}
}
void updateDisplayLocked() {
mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
// We consider any situation where the display is showing something to be it on,
@@ -1778,7 +1831,7 @@ public class DeviceIdleController extends SystemService
if (mForceIdle) {
mForceIdle = false;
if (mScreenOn || mCharging) {
becomeActiveLocked("exit-force-idle", Process.myUid());
becomeActiveLocked("exit-force", Process.myUid());
}
}
}
@@ -1834,22 +1887,33 @@ public class DeviceIdleController extends SystemService
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT);
break;
case LIGHT_STATE_IDLE:
// We have been idling long enough, now it is time to do some work.
mActiveIdleOpCount = 1;
mActiveIdleWakeLock.acquire();
mMaintenanceStartTime = SystemClock.elapsedRealtime();
if (mCurIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
} else if (mCurIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
case LIGHT_STATE_WAITING_FOR_NETWORK:
if (mNetworkConnected || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK) {
// We have been idling long enough, now it is time to do some work.
mActiveIdleOpCount = 1;
mActiveIdleWakeLock.acquire();
mMaintenanceStartTime = SystemClock.elapsedRealtime();
if (mCurIdleBudget < mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET) {
mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
} else if (mCurIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
mCurIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
}
scheduleLightAlarmLocked(mCurIdleBudget);
if (DEBUG) Slog.d(TAG,
"Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
addEvent(EVENT_LIGHT_MAINTENANCE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
} else {
// We'd like to do maintenance, but currently don't have network
// connectivity... let's try to wait until the network comes back.
// We'll only wait for another full idle period, however, and then give up.
scheduleLightAlarmLocked(mNextLightIdleDelay);
if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");
mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
}
scheduleLightAlarmLocked(mCurIdleBudget);
if (DEBUG) Slog.d(TAG,
"Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
addEvent(EVENT_LIGHT_MAINTENANCE);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
break;
}
}
@@ -2209,13 +2273,6 @@ public class DeviceIdleController extends SystemService
void scheduleLightAlarmLocked(long delay) {
if (DEBUG) Slog.d(TAG, "scheduleLightAlarmLocked(" + delay + ")");
if (mMotionSensor == null) {
// If there is no motion sensor on this device, then we won't schedule
// alarms, because we can't determine if the device is not moving. This effectively
// turns off normal execution of device idling, although it is still possible to
// manually poke it by pretending like the alarm is going off.
return;
}
mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextLightAlarmTime, "DeviceIdleController.light", mLightAlarmListener, mHandler);
@@ -2430,9 +2487,14 @@ public class DeviceIdleController extends SystemService
pw.println(" Print this help text.");
pw.println(" step [light|deep]");
pw.println(" Immediately step to next state, without waiting for alarm.");
pw.println(" force-idle");
pw.println(" force-idle [light|deep]");
pw.println(" Force directly into idle mode, regardless of other device state.");
pw.println(" Use \"step\" to get out.");
pw.println(" force-inactive");
pw.println(" Force to be inactive, ready to freely step idle states.");
pw.println(" unforce");
pw.println(" Resume normal functioning after force-idle or force-inactive.");
pw.println(" get [light|deep|force|screen|charging|network]");
pw.println(" Retrieve the current given state.");
pw.println(" disable [light|deep|all]");
pw.println(" Completely disable device idle mode.");
pw.println(" enable [light|deep|all]");
@@ -2472,12 +2534,10 @@ public class DeviceIdleController extends SystemService
String arg = shell.getNextArg();
try {
if (arg == null || "deep".equals(arg)) {
exitForceIdleLocked();
stepIdleStateLocked("s:shell");
pw.print("Stepped to deep: ");
pw.println(stateToString(mState));
} else if ("light".equals(arg)) {
exitForceIdleLocked();
stepLightIdleStateLocked("s:shell");
pw.print("Stepped to light: "); pw.println(lightStateToString(mLightState));
} else {
@@ -2492,29 +2552,104 @@ public class DeviceIdleController extends SystemService
null);
synchronized (this) {
long token = Binder.clearCallingIdentity();
String arg = shell.getNextArg();
try {
if (!mDeepEnabled) {
pw.println("Unable to go idle; not enabled");
return -1;
}
mForceIdle = true;
becomeInactiveIfAppropriateLocked();
int curState = mState;
while (curState != STATE_IDLE) {
stepIdleStateLocked("s:shell");
if (curState == mState) {
pw.print("Unable to go idle; stopped at ");
pw.println(stateToString(mState));
exitForceIdleLocked();
if (arg == null || "deep".equals(arg)) {
if (!mDeepEnabled) {
pw.println("Unable to go deep idle; not enabled");
return -1;
}
curState = mState;
mForceIdle = true;
becomeInactiveIfAppropriateLocked();
int curState = mState;
while (curState != STATE_IDLE) {
stepIdleStateLocked("s:shell");
if (curState == mState) {
pw.print("Unable to go deep idle; stopped at ");
pw.println(stateToString(mState));
exitForceIdleLocked();
return -1;
}
curState = mState;
}
pw.println("Now forced in to deep idle mode");
} else if ("light".equals(arg)) {
mForceIdle = true;
becomeInactiveIfAppropriateLocked();
int curLightState = mLightState;
while (curLightState != LIGHT_STATE_IDLE) {
stepIdleStateLocked("s:shell");
if (curLightState == mLightState) {
pw.print("Unable to go light idle; stopped at ");
pw.println(lightStateToString(mLightState));
exitForceIdleLocked();
return -1;
}
curLightState = mLightState;
}
pw.println("Now forced in to light idle mode");
} else {
pw.println("Unknown idle mode: " + arg);
}
pw.println("Now forced in to idle mode");
} finally {
Binder.restoreCallingIdentity(token);
}
}
} else if ("force-inactive".equals(cmd)) {
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
long token = Binder.clearCallingIdentity();
try {
mForceIdle = true;
becomeInactiveIfAppropriateLocked();
pw.print("Light state: ");
pw.print(lightStateToString(mLightState));
pw.print(", deep state: ");
pw.println(stateToString(mState));
} finally {
Binder.restoreCallingIdentity(token);
}
}
} else if ("unforce".equals(cmd)) {
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
long token = Binder.clearCallingIdentity();
try {
exitForceIdleLocked();
pw.print("Light state: ");
pw.print(lightStateToString(mLightState));
pw.print(", deep state: ");
pw.println(stateToString(mState));
} finally {
Binder.restoreCallingIdentity(token);
}
}
} else if ("get".equals(cmd)) {
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
String arg = shell.getNextArg();
if (arg != null) {
long token = Binder.clearCallingIdentity();
try {
switch (arg) {
case "light": pw.println(lightStateToString(mLightState)); break;
case "deep": pw.println(stateToString(mState)); break;
case "force": pw.println(mForceIdle); break;
case "screen": pw.println(mScreenOn); break;
case "charging": pw.println(mCharging); break;
case "network": pw.println(mNetworkConnected); break;
default: pw.println("Unknown get option: " + arg); break;
}
} finally {
Binder.restoreCallingIdentity(token);
}
} else {
pw.println("Argument required");
}
}
} else if ("disable".equals(cmd)) {
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
@@ -2829,6 +2964,7 @@ public class DeviceIdleController extends SystemService
pw.print(" mMotionSensor="); pw.println(mMotionSensor);
pw.print(" mCurDisplay="); pw.println(mCurDisplay);
pw.print(" mScreenOn="); pw.println(mScreenOn);
pw.print(" mNetworkConnected="); pw.println(mNetworkConnected);
pw.print(" mCharging="); pw.println(mCharging);
pw.print(" mMotionActive="); pw.println(mMotionListener.active);
pw.print(" mNotMoving="); pw.println(mNotMoving);

View File

@@ -77,8 +77,10 @@ public class ConnectivityController extends StateController implements
if (cs != null) {
if (cs.getActiveNetworkInfo() != null) {
mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
} else {
mNetworkConnected = mNetworkUnmetered = false;
}
mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
}
}