Merge "Add Stable Charging Threshold for AppStandby" into pi-dev

am: b3972f9d23

Change-Id: Iacdddabdd58c0da6b53d997b08ddf70bef583392
This commit is contained in:
Michael Wachenschwanz
2018-05-01 17:35:00 -07:00
committed by android-build-merger
3 changed files with 174 additions and 26 deletions

View File

@@ -10619,18 +10619,30 @@ public final class Settings {
* App standby (app idle) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
* <p>
* "idle_duration=5000,parole_interval=4500"
* "idle_duration=5000,parole_interval=4500,screen_thresholds=0/0/60000/120000"
* <p>
* All durations are in millis.
* Array values are separated by forward slashes
* The following keys are supported:
*
* <pre>
* idle_duration2 (long)
* wallclock_threshold (long)
* parole_interval (long)
* parole_duration (long)
* parole_interval (long)
* parole_window (long)
* parole_duration (long)
* screen_thresholds (long[4])
* elapsed_thresholds (long[4])
* strong_usage_duration (long)
* notification_seen_duration (long)
* system_update_usage_duration (long)
* prediction_timeout (long)
* sync_adapter_duration (long)
* exempted_sync_duration (long)
* system_interaction_duration (long)
* stable_charging_threshold (long)
*
* idle_duration (long) // This is deprecated and used to circumvent b/26355386.
* idle_duration2 (long) // deprecated
* wallclock_threshold (long) // deprecated
* </pre>
*
* <p>

View File

@@ -46,6 +46,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.ContextWrapper;
@@ -74,6 +75,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Unit test for AppStandbyController.
@@ -101,6 +104,8 @@ public class AppStandbyControllerTests {
private static final long WORKING_SET_THRESHOLD = 12 * HOUR_MS;
private static final long FREQUENT_THRESHOLD = 24 * HOUR_MS;
private static final long RARE_THRESHOLD = 48 * HOUR_MS;
// Short STABLE_CHARGING_THRESHOLD for testing purposes
private static final long STABLE_CHARGING_THRESHOLD = 2000;
private MyInjector mInjector;
private AppStandbyController mController;
@@ -209,7 +214,8 @@ public class AppStandbyControllerTests {
return "screen_thresholds=0/0/0/" + HOUR_MS + ",elapsed_thresholds=0/"
+ WORKING_SET_THRESHOLD + "/"
+ FREQUENT_THRESHOLD + "/"
+ RARE_THRESHOLD;
+ RARE_THRESHOLD + ","
+ "stable_charging_threshold=" + STABLE_CHARGING_THRESHOLD;
}
// Internal methods
@@ -276,6 +282,10 @@ public class AppStandbyControllerTests {
return controller;
}
private long getCurrentTime() {
return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
}
@Before
public void setUp() throws Exception {
MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
@@ -284,21 +294,101 @@ public class AppStandbyControllerTests {
setChargingState(mController, false);
}
private class TestParoleListener extends UsageStatsManagerInternal.AppIdleStateChangeListener {
private boolean mOnParole = false;
private CountDownLatch mLatch;
private long mLastParoleChangeTime;
public boolean getParoleState() {
synchronized (this) {
return mOnParole;
}
}
public void rearmLatch() {
synchronized (this) {
mLatch = new CountDownLatch(1);
}
}
public void awaitOnLatch(long time) throws Exception {
mLatch.await(time, TimeUnit.MILLISECONDS);
}
public long getLastParoleChangeTime() {
synchronized (this) {
return mLastParoleChangeTime;
}
}
@Override
public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
int bucket, int reason) {
}
@Override
public void onParoleStateChanged(boolean isParoleOn) {
synchronized (this) {
// Only record information if it is being looked for
if (mLatch.getCount() > 0) {
mOnParole = isParoleOn;
mLastParoleChangeTime = getCurrentTime();
mLatch.countDown();
}
}
}
}
@Test
public void testCharging() throws Exception {
setChargingState(mController, true);
mInjector.mElapsedRealtime = RARE_THRESHOLD + 1;
assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID,
mInjector.mElapsedRealtime, false));
long startTime;
TestParoleListener paroleListener = new TestParoleListener();
long marginOfError = 200;
setChargingState(mController, false);
mInjector.mElapsedRealtime = 2 * RARE_THRESHOLD + 2;
mController.checkIdleStates(USER_ID);
assertTrue(mController.isAppIdleFilteredOrParoled(PACKAGE_1, USER_ID,
mInjector.mElapsedRealtime, false));
// Charging
paroleListener.rearmLatch();
mController.addListener(paroleListener);
startTime = getCurrentTime();
setChargingState(mController, true);
assertFalse(mController.isAppIdleFilteredOrParoled(PACKAGE_1,USER_ID,
mInjector.mElapsedRealtime, false));
paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
assertTrue(paroleListener.mOnParole);
// Parole will only be granted after device has been charging for a sufficient amount of
// time.
assertEquals(STABLE_CHARGING_THRESHOLD,
paroleListener.getLastParoleChangeTime() - startTime,
marginOfError);
// Discharging
paroleListener.rearmLatch();
startTime = getCurrentTime();
setChargingState(mController, false);
mController.checkIdleStates(USER_ID);
paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
assertFalse(paroleListener.getParoleState());
// Parole should be revoked immediately
assertEquals(0,
paroleListener.getLastParoleChangeTime() - startTime,
marginOfError);
// Brief Charging
paroleListener.rearmLatch();
setChargingState(mController, true);
setChargingState(mController, false);
// Device stopped charging before the stable charging threshold.
// Parole should not be granted at the end of the threshold
paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
assertFalse(paroleListener.getParoleState());
// Charging Again
paroleListener.rearmLatch();
startTime = getCurrentTime();
setChargingState(mController, true);
paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
assertTrue(paroleListener.getParoleState());
assertTrue(paroleListener.mOnParole);
assertEquals(STABLE_CHARGING_THRESHOLD,
paroleListener.getLastParoleChangeTime() - startTime,
marginOfError);
}
private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {

View File

@@ -192,6 +192,7 @@ public class AppStandbyController {
/** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
static final int MSG_REPORT_EXEMPTED_SYNC_START = 12;
static final int MSG_UPDATE_STABLE_CHARGING= 13;
long mCheckIdleIntervalMillis;
long mAppIdleParoleIntervalMillis;
@@ -213,10 +214,13 @@ public class AppStandbyController {
long mExemptedSyncAdapterTimeoutMillis;
/** Maximum time a system interaction should keep the buckets elevated. */
long mSystemInteractionTimeoutMillis;
/** The length of time phone must be charging before considered stable enough to run jobs */
long mStableChargingThresholdMillis;
volatile boolean mAppIdleEnabled;
boolean mAppIdleTempParoled;
boolean mCharging;
boolean mChargingStable;
private long mLastAppIdleParoledTime;
private boolean mSystemServicesReady = false;
// There was a system update, defaults need to be initialized after services are ready
@@ -297,7 +301,7 @@ public class AppStandbyController {
mPackageManager = mContext.getPackageManager();
mDeviceStateReceiver = new DeviceStateReceiver();
IntentFilter deviceStates = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
mContext.registerReceiver(mDeviceStateReceiver, deviceStates);
@@ -405,6 +409,27 @@ public class AppStandbyController {
synchronized (mAppIdleLock) {
if (mCharging != charging) {
mCharging = charging;
if (DEBUG) Slog.d(TAG, "Setting mCharging to " + charging);
if (charging) {
if (DEBUG) {
Slog.d(TAG, "Scheduling MSG_UPDATE_STABLE_CHARGING delay = "
+ mStableChargingThresholdMillis);
}
mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STABLE_CHARGING,
mStableChargingThresholdMillis);
} else {
mHandler.removeMessages(MSG_UPDATE_STABLE_CHARGING);
updateChargingStableState();
}
}
}
}
void updateChargingStableState() {
synchronized (mAppIdleLock) {
if (mChargingStable != mCharging) {
if (DEBUG) Slog.d(TAG, "Setting mChargingStable to " + mCharging);
mChargingStable = mCharging;
postParoleStateChanged();
}
}
@@ -431,7 +456,8 @@ public class AppStandbyController {
boolean isParoledOrCharging() {
if (!mAppIdleEnabled) return true;
synchronized (mAppIdleLock) {
return mAppIdleTempParoled || mCharging;
// Only consider stable charging when determining charge state.
return mAppIdleTempParoled || mChargingStable;
}
}
@@ -1371,11 +1397,15 @@ public class AppStandbyController {
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
pw.print(" mCharging="); pw.print(mCharging);
pw.print(" mChargingStable="); pw.print(mChargingStable);
pw.print(" mLastAppIdleParoledTime=");
TimeUtils.formatDuration(mLastAppIdleParoledTime, pw);
pw.println();
pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
pw.print("mStableChargingThresholdMillis=");
TimeUtils.formatDuration(mStableChargingThresholdMillis, pw);
pw.println();
}
/**
@@ -1549,7 +1579,7 @@ public class AppStandbyController {
case MSG_PAROLE_STATE_CHANGED:
if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled
+ ", Charging state:" + mCharging);
+ ", Charging state:" + mChargingStable);
informParoleStateChanged();
break;
case MSG_CHECK_PACKAGE_IDLE_STATE:
@@ -1561,6 +1591,10 @@ public class AppStandbyController {
reportExemptedSyncStart((String) msg.obj, msg.arg1);
break;
case MSG_UPDATE_STABLE_CHARGING:
updateChargingStableState();
break;
default:
super.handleMessage(msg);
break;
@@ -1572,11 +1606,16 @@ public class AppStandbyController {
private class DeviceStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
setChargingState(intent.getIntExtra("plugged", 0) != 0);
} else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
onDeviceIdleModeChanged();
switch (intent.getAction()) {
case BatteryManager.ACTION_CHARGING:
setChargingState(true);
break;
case BatteryManager.ACTION_DISCHARGING:
setChargingState(false);
break;
case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
onDeviceIdleModeChanged();
break;
}
}
}
@@ -1620,9 +1659,11 @@ public class AppStandbyController {
*/
@Deprecated
private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
@Deprecated
private static final String KEY_IDLE_DURATION = "idle_duration2";
@Deprecated
private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
private static final String KEY_PAROLE_INTERVAL = "parole_interval";
private static final String KEY_PAROLE_WINDOW = "parole_window";
private static final String KEY_PAROLE_DURATION = "parole_duration";
@@ -1638,12 +1679,14 @@ public class AppStandbyController {
private static final String KEY_EXEMPTED_SYNC_HOLD_DURATION = "exempted_sync_duration";
private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
"system_interaction_duration";
private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold";
public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
public static final long DEFAULT_EXEMPTED_SYNC_TIMEOUT = 10 * ONE_MINUTE;
public static final long DEFAULT_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -1733,6 +1776,9 @@ public class AppStandbyController {
mSystemInteractionTimeoutMillis = mParser.getDurationMillis
(KEY_SYSTEM_INTERACTION_HOLD_DURATION,
COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
mStableChargingThresholdMillis = mParser.getDurationMillis
(KEY_STABLE_CHARGING_THRESHOLD,
COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD);
}
}