Merge "Improve reporting of bucketing reason"
This commit is contained in:
committed by
Android (Google) Code Review
commit
b9cacbea94
@@ -109,7 +109,8 @@ public final class UsageEvents implements Parcelable {
|
||||
public static final int NOTIFICATION_SEEN = 10;
|
||||
|
||||
/**
|
||||
* An event type denoting a change in App Standby Bucket.
|
||||
* An event type denoting a change in App Standby Bucket. Additional bucket information
|
||||
* is contained in mBucketAndReason.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@@ -180,11 +181,12 @@ public final class UsageEvents implements Parcelable {
|
||||
public String[] mContentAnnotations;
|
||||
|
||||
/**
|
||||
* The app standby bucket assigned.
|
||||
* The app standby bucket assigned and reason. Bucket is the high order 16 bits, reason
|
||||
* is the low order 16 bits.
|
||||
* Only present for {@link #STANDBY_BUCKET_CHANGED} event types
|
||||
* {@hide}
|
||||
*/
|
||||
public int mBucket;
|
||||
public int mBucketAndReason;
|
||||
|
||||
/** @hide */
|
||||
@EventFlags
|
||||
@@ -205,7 +207,7 @@ public final class UsageEvents implements Parcelable {
|
||||
mContentType = orig.mContentType;
|
||||
mContentAnnotations = orig.mContentAnnotations;
|
||||
mFlags = orig.mFlags;
|
||||
mBucket = orig.mBucket;
|
||||
mBucketAndReason = orig.mBucketAndReason;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,7 +270,19 @@ public final class UsageEvents implements Parcelable {
|
||||
*/
|
||||
@SystemApi
|
||||
public int getStandbyBucket() {
|
||||
return mBucket;
|
||||
return (mBucketAndReason & 0xFFFF0000) >>> 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reason for the bucketing, if the event is of type
|
||||
* {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0. Reason values include
|
||||
* the main reason which is one of REASON_MAIN_*, OR'ed with REASON_SUB_*, if there
|
||||
* are sub-reasons for the main reason, such as REASON_SUB_USAGE_* when the main reason
|
||||
* is REASON_MAIN_USAGE.
|
||||
* @hide
|
||||
*/
|
||||
public int getStandbyReason() {
|
||||
return mBucketAndReason & 0x0000FFFF;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -428,7 +442,7 @@ public final class UsageEvents implements Parcelable {
|
||||
p.writeStringArray(event.mContentAnnotations);
|
||||
break;
|
||||
case Event.STANDBY_BUCKET_CHANGED:
|
||||
p.writeInt(event.mBucket);
|
||||
p.writeInt(event.mBucketAndReason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -474,7 +488,7 @@ public final class UsageEvents implements Parcelable {
|
||||
eventOut.mContentAnnotations = p.createStringArray();
|
||||
break;
|
||||
case Event.STANDBY_BUCKET_CHANGED:
|
||||
eventOut.mBucket = p.readInt();
|
||||
eventOut.mBucketAndReason = p.readInt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,24 +132,37 @@ public final class UsageStatsManager {
|
||||
@SystemApi
|
||||
public static final int STANDBY_BUCKET_NEVER = 50;
|
||||
|
||||
/** {@hide} Reason for bucketing -- default initial state */
|
||||
public static final String REASON_DEFAULT = "default";
|
||||
/** @hide */
|
||||
public static final int REASON_MAIN_MASK = 0xFF00;
|
||||
/** @hide */
|
||||
public static final int REASON_MAIN_DEFAULT = 0x0100;
|
||||
/** @hide */
|
||||
public static final int REASON_MAIN_TIMEOUT = 0x0200;
|
||||
/** @hide */
|
||||
public static final int REASON_MAIN_USAGE = 0x0300;
|
||||
/** @hide */
|
||||
public static final int REASON_MAIN_FORCED = 0x0400;
|
||||
/** @hide */
|
||||
public static final int REASON_MAIN_PREDICTED = 0x0500;
|
||||
|
||||
/** {@hide} Reason for bucketing -- timeout */
|
||||
public static final String REASON_TIMEOUT = "timeout";
|
||||
|
||||
/** {@hide} Reason for bucketing -- usage */
|
||||
public static final String REASON_USAGE = "usage";
|
||||
|
||||
/** {@hide} Reason for bucketing -- forced by user / shell command */
|
||||
public static final String REASON_FORCED = "forced";
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
* Reason for bucketing -- predicted. This is a prefix and the UID of the bucketeer will
|
||||
* be appended.
|
||||
*/
|
||||
public static final String REASON_PREDICTED = "predicted";
|
||||
/** @hide */
|
||||
public static final int REASON_SUB_MASK = 0x00FF;
|
||||
/** @hide */
|
||||
public static final int REASON_SUB_USAGE_SYSTEM_INTERACTION = 0x0001;
|
||||
/** @hide */
|
||||
public static final int REASON_SUB_USAGE_NOTIFICATION_SEEN = 0x0002;
|
||||
/** @hide */
|
||||
public static final int REASON_SUB_USAGE_USER_INTERACTION = 0x0003;
|
||||
/** @hide */
|
||||
public static final int REASON_SUB_USAGE_MOVE_TO_FOREGROUND = 0x0004;
|
||||
/** @hide */
|
||||
public static final int REASON_SUB_USAGE_MOVE_TO_BACKGROUND = 0x0005;
|
||||
/** @hide */
|
||||
public static final int REASON_SUB_USAGE_SYSTEM_UPDATE = 0x0006;
|
||||
/** @hide */
|
||||
public static final int REASON_SUB_USAGE_ACTIVE_TIMEOUT = 0x0007;
|
||||
/** @hide */
|
||||
public static final int REASON_SUB_USAGE_SYNC_ADAPTER = 0x0008;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = {
|
||||
@@ -427,6 +440,55 @@ public final class UsageStatsManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static String reasonToString(int standbyReason) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
switch (standbyReason & REASON_MAIN_MASK) {
|
||||
case REASON_MAIN_DEFAULT:
|
||||
sb.append("d");
|
||||
break;
|
||||
case REASON_MAIN_FORCED:
|
||||
sb.append("f");
|
||||
break;
|
||||
case REASON_MAIN_PREDICTED:
|
||||
sb.append("p");
|
||||
break;
|
||||
case REASON_MAIN_TIMEOUT:
|
||||
sb.append("t");
|
||||
break;
|
||||
case REASON_MAIN_USAGE:
|
||||
sb.append("u-");
|
||||
switch (standbyReason & REASON_SUB_MASK) {
|
||||
case REASON_SUB_USAGE_SYSTEM_INTERACTION:
|
||||
sb.append("si");
|
||||
break;
|
||||
case REASON_SUB_USAGE_NOTIFICATION_SEEN:
|
||||
sb.append("ns");
|
||||
break;
|
||||
case REASON_SUB_USAGE_USER_INTERACTION:
|
||||
sb.append("ui");
|
||||
break;
|
||||
case REASON_SUB_USAGE_MOVE_TO_FOREGROUND:
|
||||
sb.append("mf");
|
||||
break;
|
||||
case REASON_SUB_USAGE_MOVE_TO_BACKGROUND:
|
||||
sb.append("mb");
|
||||
break;
|
||||
case REASON_SUB_USAGE_SYSTEM_UPDATE:
|
||||
sb.append("su");
|
||||
break;
|
||||
case REASON_SUB_USAGE_ACTIVE_TIMEOUT:
|
||||
sb.append("at");
|
||||
break;
|
||||
case REASON_SUB_USAGE_SYNC_ADAPTER:
|
||||
sb.append("sa");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
* Temporarily whitelist the specified app for a short duration. This is to allow an app
|
||||
|
||||
@@ -139,7 +139,7 @@ public abstract class UsageStatsManagerInternal {
|
||||
|
||||
/** Callback to inform listeners that the idle state has changed to a new bucket. */
|
||||
public abstract void onAppIdleStateChanged(String packageName, @UserIdInt int userId,
|
||||
boolean idle, int bucket);
|
||||
boolean idle, int bucket, int reason);
|
||||
|
||||
/**
|
||||
* Callback to inform listeners that the parole state has changed. This means apps are
|
||||
|
||||
@@ -3860,7 +3860,7 @@ class AlarmManagerService extends SystemService {
|
||||
final class AppStandbyTracker extends UsageStatsManagerInternal.AppIdleStateChangeListener {
|
||||
@Override
|
||||
public void onAppIdleStateChanged(final String packageName, final @UserIdInt int userId,
|
||||
boolean idle, int bucket) {
|
||||
boolean idle, int bucket, int reason) {
|
||||
if (DEBUG_STANDBY) {
|
||||
Slog.d(TAG, "Package " + packageName + " for user " + userId + " now in bucket " +
|
||||
bucket);
|
||||
|
||||
@@ -678,7 +678,7 @@ public class AppStateTracker {
|
||||
final class StandbyTracker extends AppIdleStateChangeListener {
|
||||
@Override
|
||||
public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
|
||||
int bucket) {
|
||||
int bucket, int reason) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,"onAppIdleStateChanged: " + packageName + " u" + userId
|
||||
+ (idle ? " idle" : " active") + " " + bucket);
|
||||
|
||||
@@ -85,7 +85,7 @@ final class ActivityManagerConstants extends ContentObserver {
|
||||
private static final int DEFAULT_POWER_CHECK_MAX_CPU_3 = 10;
|
||||
private static final int DEFAULT_POWER_CHECK_MAX_CPU_4 = 2;
|
||||
private static final long DEFAULT_SERVICE_USAGE_INTERACTION_TIME = 30*60*1000;
|
||||
private static final long DEFAULT_USAGE_STATS_INTERACTION_INTERVAL = 24*60*60*1000L;
|
||||
private static final long DEFAULT_USAGE_STATS_INTERACTION_INTERVAL = 2*60*60*1000L;
|
||||
private static final long DEFAULT_SERVICE_RESTART_DURATION = 1*1000;
|
||||
private static final long DEFAULT_SERVICE_RESET_RUN_DURATION = 60*1000;
|
||||
private static final int DEFAULT_SERVICE_RESTART_DURATION_FACTOR = 4;
|
||||
|
||||
@@ -2240,7 +2240,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
||||
|
||||
@Override
|
||||
public void onAppIdleStateChanged(final String packageName, final @UserIdInt int userId,
|
||||
boolean idle, int bucket) {
|
||||
boolean idle, int bucket, int reason) {
|
||||
final int uid = mLocalPM.getPackageUid(packageName,
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
|
||||
if (uid < 0) {
|
||||
|
||||
@@ -186,7 +186,8 @@ public final class AppIdleController extends StateController {
|
||||
private final class AppIdleStateChangeListener
|
||||
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
|
||||
@Override
|
||||
public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket) {
|
||||
public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket,
|
||||
int reason) {
|
||||
boolean changed = false;
|
||||
synchronized (mLock) {
|
||||
if (mAppIdleParoleOn) {
|
||||
|
||||
@@ -3947,7 +3947,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
|
||||
|
||||
@Override
|
||||
public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket) {
|
||||
public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket,
|
||||
int reason) {
|
||||
try {
|
||||
final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package com.android.server;
|
||||
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
|
||||
|
||||
import static com.android.server.AppStateTracker.TARGET_OP;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -612,7 +615,7 @@ public class AppStateTrackerTest {
|
||||
|
||||
// Exempt package 2 on user-10.
|
||||
mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_2, /*user=*/ 10, false,
|
||||
UsageStatsManager.STANDBY_BUCKET_EXEMPTED);
|
||||
UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT);
|
||||
|
||||
areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
|
||||
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
|
||||
@@ -624,7 +627,7 @@ public class AppStateTrackerTest {
|
||||
|
||||
// Exempt package 1 on user-0.
|
||||
mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_1, /*user=*/ 0, false,
|
||||
UsageStatsManager.STANDBY_BUCKET_EXEMPTED);
|
||||
UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT);
|
||||
|
||||
areRestricted(instance, UID_1, PACKAGE_1, NONE);
|
||||
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
|
||||
@@ -632,7 +635,7 @@ public class AppStateTrackerTest {
|
||||
|
||||
// Unexempt package 2 on user-10.
|
||||
mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_2, /*user=*/ 10, false,
|
||||
UsageStatsManager.STANDBY_BUCKET_ACTIVE);
|
||||
UsageStatsManager.STANDBY_BUCKET_ACTIVE, REASON_MAIN_USAGE);
|
||||
|
||||
areRestricted(instance, UID_1, PACKAGE_1, NONE);
|
||||
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
|
||||
@@ -644,9 +647,9 @@ public class AppStateTrackerTest {
|
||||
mPowerSaveObserver.accept(getPowerSaveState());
|
||||
|
||||
mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_1, /*user=*/ 0, false,
|
||||
UsageStatsManager.STANDBY_BUCKET_EXEMPTED);
|
||||
UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT);
|
||||
mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_2, /*user=*/ 0, false,
|
||||
UsageStatsManager.STANDBY_BUCKET_EXEMPTED);
|
||||
UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT);
|
||||
|
||||
setAppOps(UID_1, PACKAGE_1, true);
|
||||
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package com.android.server.usage;
|
||||
|
||||
import static android.app.usage.UsageStatsManager.REASON_TIMEOUT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -92,18 +95,18 @@ public class AppIdleHistoryTests extends AndroidTestCase {
|
||||
AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
|
||||
|
||||
aih.setAppStandbyBucket(PACKAGE_1, USER_ID, 1000, STANDBY_BUCKET_ACTIVE,
|
||||
UsageStatsManager.REASON_USAGE);
|
||||
REASON_MAIN_USAGE);
|
||||
// ACTIVE means not idle
|
||||
assertFalse(aih.isIdle(PACKAGE_1, USER_ID, 2000));
|
||||
|
||||
aih.setAppStandbyBucket(PACKAGE_2, USER_ID, 2000, STANDBY_BUCKET_ACTIVE,
|
||||
UsageStatsManager.REASON_USAGE);
|
||||
REASON_MAIN_USAGE);
|
||||
aih.setAppStandbyBucket(PACKAGE_1, USER_ID, 3000, STANDBY_BUCKET_RARE,
|
||||
REASON_TIMEOUT);
|
||||
REASON_MAIN_TIMEOUT);
|
||||
|
||||
assertEquals(aih.getAppStandbyBucket(PACKAGE_1, USER_ID, 3000), STANDBY_BUCKET_RARE);
|
||||
assertEquals(aih.getAppStandbyBucket(PACKAGE_2, USER_ID, 3000), STANDBY_BUCKET_ACTIVE);
|
||||
assertEquals(aih.getAppStandbyReason(PACKAGE_1, USER_ID, 3000), REASON_TIMEOUT);
|
||||
assertEquals(aih.getAppStandbyReason(PACKAGE_1, USER_ID, 3000), REASON_MAIN_TIMEOUT);
|
||||
|
||||
// RARE is considered idle
|
||||
assertTrue(aih.isIdle(PACKAGE_1, USER_ID, 3000));
|
||||
@@ -115,7 +118,7 @@ public class AppIdleHistoryTests extends AndroidTestCase {
|
||||
aih = new AppIdleHistory(mStorageDir, 4000);
|
||||
assertEquals(aih.getAppStandbyBucket(PACKAGE_1, USER_ID, 5000), STANDBY_BUCKET_RARE);
|
||||
assertEquals(aih.getAppStandbyBucket(PACKAGE_2, USER_ID, 5000), STANDBY_BUCKET_ACTIVE);
|
||||
assertEquals(aih.getAppStandbyReason(PACKAGE_1, USER_ID, 5000), REASON_TIMEOUT);
|
||||
assertEquals(aih.getAppStandbyReason(PACKAGE_1, USER_ID, 5000), REASON_MAIN_TIMEOUT);
|
||||
|
||||
assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE));
|
||||
assertFalse(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE));
|
||||
@@ -133,4 +136,18 @@ public class AppIdleHistoryTests extends AndroidTestCase {
|
||||
assertEquals(1000, aih.getTimeSinceLastJobRun(PACKAGE_2, USER_ID, 7000));
|
||||
assertEquals(5000, aih.getTimeSinceLastJobRun(PACKAGE_1, USER_ID, 7000));
|
||||
}
|
||||
|
||||
public void testReason() throws Exception {
|
||||
AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
|
||||
aih.reportUsage(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_SUB_USAGE_MOVE_TO_FOREGROUND, 2000, 0);
|
||||
assertEquals(REASON_MAIN_USAGE | REASON_SUB_USAGE_MOVE_TO_FOREGROUND,
|
||||
aih.getAppStandbyReason(PACKAGE_1, USER_ID, 3000));
|
||||
aih.setAppStandbyBucket(PACKAGE_1, USER_ID, 4000, STANDBY_BUCKET_WORKING_SET,
|
||||
REASON_MAIN_TIMEOUT);
|
||||
aih.writeAppIdleTimes(USER_ID);
|
||||
|
||||
aih = new AppIdleHistory(mStorageDir, 5000);
|
||||
assertEquals(REASON_MAIN_TIMEOUT, aih.getAppStandbyReason(PACKAGE_1, USER_ID, 5000));
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,11 @@ package com.android.server.usage;
|
||||
|
||||
import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN;
|
||||
import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
|
||||
import static android.app.usage.UsageStatsManager.REASON_DEFAULT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_FORCED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_PREDICTED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_TIMEOUT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_USAGE;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
|
||||
@@ -410,11 +410,11 @@ public class AppStandbyControllerTests {
|
||||
setChargingState(mController, false);
|
||||
// Set it to timeout or usage, so that prediction can override it
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
|
||||
REASON_TIMEOUT, 1 * HOUR_MS);
|
||||
REASON_MAIN_TIMEOUT, 1 * HOUR_MS);
|
||||
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
|
||||
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_PREDICTED + ":CTS", 1 * HOUR_MS);
|
||||
REASON_MAIN_PREDICTED, 1 * HOUR_MS);
|
||||
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
|
||||
|
||||
// Fast forward 12 hours
|
||||
@@ -440,28 +440,28 @@ public class AppStandbyControllerTests {
|
||||
setChargingState(mController, false);
|
||||
// Can force to NEVER
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
|
||||
REASON_FORCED, 1 * HOUR_MS);
|
||||
REASON_MAIN_FORCED, 1 * HOUR_MS);
|
||||
assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController));
|
||||
|
||||
// Prediction can't override FORCED reason
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_FORCED, 1 * HOUR_MS);
|
||||
REASON_MAIN_FORCED, 1 * HOUR_MS);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
|
||||
REASON_PREDICTED, 1 * HOUR_MS);
|
||||
REASON_MAIN_PREDICTED, 1 * HOUR_MS);
|
||||
assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController));
|
||||
|
||||
// Prediction can't override NEVER
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
|
||||
REASON_DEFAULT, 2 * HOUR_MS);
|
||||
REASON_MAIN_DEFAULT, 2 * HOUR_MS);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_PREDICTED, 2 * HOUR_MS);
|
||||
REASON_MAIN_PREDICTED, 2 * HOUR_MS);
|
||||
assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController));
|
||||
|
||||
// Prediction can't set to NEVER
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_USAGE, 2 * HOUR_MS);
|
||||
REASON_MAIN_USAGE, 2 * HOUR_MS);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
|
||||
REASON_PREDICTED, 2 * HOUR_MS);
|
||||
REASON_MAIN_PREDICTED, 2 * HOUR_MS);
|
||||
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
|
||||
}
|
||||
|
||||
@@ -474,7 +474,7 @@ public class AppStandbyControllerTests {
|
||||
|
||||
mInjector.mElapsedRealtime = 2000;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
assertBucket(STANDBY_BUCKET_ACTIVE);
|
||||
|
||||
// bucketing works after timeout
|
||||
@@ -483,7 +483,7 @@ public class AppStandbyControllerTests {
|
||||
assertBucket(STANDBY_BUCKET_WORKING_SET);
|
||||
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
assertBucket(STANDBY_BUCKET_FREQUENT);
|
||||
}
|
||||
|
||||
@@ -498,15 +498,15 @@ public class AppStandbyControllerTests {
|
||||
assertBucket(STANDBY_BUCKET_ACTIVE);
|
||||
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
|
||||
REASON_PREDICTED, 1000);
|
||||
REASON_MAIN_PREDICTED, 1000);
|
||||
assertBucket(STANDBY_BUCKET_ACTIVE);
|
||||
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
|
||||
REASON_MAIN_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
|
||||
assertBucket(STANDBY_BUCKET_WORKING_SET);
|
||||
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
|
||||
REASON_MAIN_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
|
||||
assertBucket(STANDBY_BUCKET_FREQUENT);
|
||||
}
|
||||
|
||||
@@ -527,18 +527,18 @@ public class AppStandbyControllerTests {
|
||||
// Still in ACTIVE after first USER_INTERACTION times out
|
||||
mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
assertBucket(STANDBY_BUCKET_ACTIVE);
|
||||
|
||||
// Both timed out, so NOTIFICATION_SEEN timeout should be effective
|
||||
mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
assertBucket(STANDBY_BUCKET_WORKING_SET);
|
||||
|
||||
mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
|
||||
REASON_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
assertBucket(STANDBY_BUCKET_RARE);
|
||||
}
|
||||
|
||||
@@ -561,7 +561,7 @@ public class AppStandbyControllerTests {
|
||||
// Predict to ACTIVE
|
||||
mInjector.mElapsedRealtime += 1000;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
assertBucket(STANDBY_BUCKET_ACTIVE);
|
||||
|
||||
// CheckIdleStates should not change the prediction
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
package com.android.server.usage;
|
||||
|
||||
import static android.app.usage.UsageStatsManager.REASON_DEFAULT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_FORCED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_PREDICTED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_USAGE;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
|
||||
@@ -112,8 +114,10 @@ public class AppIdleHistory {
|
||||
// Standby bucket
|
||||
@UsageStatsManager.StandbyBuckets
|
||||
int currentBucket;
|
||||
// Reason for setting the standby bucket. TODO: Switch to int.
|
||||
String bucketingReason;
|
||||
// Reason for setting the standby bucket. The value here is a combination of
|
||||
// one of UsageStatsManager.REASON_MAIN_* and one (or none) of
|
||||
// UsageStatsManager.REASON_SUB_*. Also see REASON_MAIN_MASK and REASON_SUB_MASK.
|
||||
int bucketingReason;
|
||||
// In-memory only, last bucket for which the listeners were informed
|
||||
int lastInformedBucket;
|
||||
// The last time a job was run for this app, using elapsed timebase
|
||||
@@ -212,13 +216,14 @@ public class AppIdleHistory {
|
||||
* @param appUsageHistory the usage record for the app being updated
|
||||
* @param packageName name of the app being updated, for logging purposes
|
||||
* @param newBucket the bucket to set the app to
|
||||
* @param usageReason the sub-reason for usage, one of REASON_SUB_USAGE_*
|
||||
* @param elapsedRealtime mark as used time if non-zero
|
||||
* @param timeout set the timeout of the specified bucket, if non-zero. Can only be used
|
||||
* with bucket values of ACTIVE and WORKING_SET.
|
||||
* @return
|
||||
*/
|
||||
public AppUsageHistory reportUsage(AppUsageHistory appUsageHistory, String packageName,
|
||||
int newBucket, long elapsedRealtime, long timeout) {
|
||||
int newBucket, int usageReason, long elapsedRealtime, long timeout) {
|
||||
// Set the timeout if applicable
|
||||
if (timeout > elapsedRealtime) {
|
||||
// Convert to elapsed timebase
|
||||
@@ -246,10 +251,10 @@ public class AppIdleHistory {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory
|
||||
.currentBucket
|
||||
+ ", reason=" + appUsageHistory.bucketingReason);
|
||||
+ ", reason=0x0" + Integer.toHexString(appUsageHistory.bucketingReason));
|
||||
}
|
||||
}
|
||||
appUsageHistory.bucketingReason = REASON_USAGE;
|
||||
appUsageHistory.bucketingReason = REASON_MAIN_USAGE | usageReason;
|
||||
|
||||
return appUsageHistory;
|
||||
}
|
||||
@@ -262,16 +267,17 @@ public class AppIdleHistory {
|
||||
* @param packageName
|
||||
* @param userId
|
||||
* @param newBucket the bucket to set the app to
|
||||
* @param elapsedRealtime mark as used time if non-zero
|
||||
* @param usageReason sub reason for usage
|
||||
* @param nowElapsed mark as used time if non-zero
|
||||
* @param timeout set the timeout of the specified bucket, if non-zero. Can only be used
|
||||
* with bucket values of ACTIVE and WORKING_SET.
|
||||
* @return
|
||||
*/
|
||||
public AppUsageHistory reportUsage(String packageName, int userId, int newBucket,
|
||||
long nowElapsed, long timeout) {
|
||||
int usageReason, long nowElapsed, long timeout) {
|
||||
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
|
||||
AppUsageHistory history = getPackageHistory(userHistory, packageName, nowElapsed, true);
|
||||
return reportUsage(history, packageName, newBucket, nowElapsed, timeout);
|
||||
return reportUsage(history, packageName, newBucket, usageReason, nowElapsed, timeout);
|
||||
}
|
||||
|
||||
private ArrayMap<String, AppUsageHistory> getUserHistory(int userId) {
|
||||
@@ -293,7 +299,7 @@ public class AppIdleHistory {
|
||||
appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
|
||||
appUsageHistory.lastPredictedTime = getElapsedTime(0);
|
||||
appUsageHistory.currentBucket = STANDBY_BUCKET_NEVER;
|
||||
appUsageHistory.bucketingReason = REASON_DEFAULT;
|
||||
appUsageHistory.bucketingReason = REASON_MAIN_DEFAULT;
|
||||
appUsageHistory.lastInformedBucket = -1;
|
||||
appUsageHistory.lastJobRunTime = Long.MIN_VALUE; // long long time ago
|
||||
userHistory.put(packageName, appUsageHistory);
|
||||
@@ -328,18 +334,18 @@ public class AppIdleHistory {
|
||||
}
|
||||
|
||||
public void setAppStandbyBucket(String packageName, int userId, long elapsedRealtime,
|
||||
int bucket, String reason) {
|
||||
int bucket, int reason) {
|
||||
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
|
||||
AppUsageHistory appUsageHistory =
|
||||
getPackageHistory(userHistory, packageName, elapsedRealtime, true);
|
||||
appUsageHistory.currentBucket = bucket;
|
||||
appUsageHistory.bucketingReason = reason;
|
||||
if (reason.startsWith(REASON_PREDICTED)) {
|
||||
if ((reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED) {
|
||||
appUsageHistory.lastPredictedTime = getElapsedTime(elapsedRealtime);
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
|
||||
+ ", reason=" + appUsageHistory.bucketingReason);
|
||||
+ ", reason=0x0" + Integer.toHexString(appUsageHistory.bucketingReason));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,11 +399,11 @@ public class AppIdleHistory {
|
||||
return buckets;
|
||||
}
|
||||
|
||||
public String getAppStandbyReason(String packageName, int userId, long elapsedRealtime) {
|
||||
public int getAppStandbyReason(String packageName, int userId, long elapsedRealtime) {
|
||||
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
|
||||
AppUsageHistory appUsageHistory =
|
||||
getPackageHistory(userHistory, packageName, elapsedRealtime, false);
|
||||
return appUsageHistory != null ? appUsageHistory.bucketingReason : null;
|
||||
return appUsageHistory != null ? appUsageHistory.bucketingReason : 0;
|
||||
}
|
||||
|
||||
public long getElapsedTime(long elapsedRealtime) {
|
||||
@@ -411,11 +417,11 @@ public class AppIdleHistory {
|
||||
elapsedRealtime, true);
|
||||
if (idle) {
|
||||
appUsageHistory.currentBucket = STANDBY_BUCKET_RARE;
|
||||
appUsageHistory.bucketingReason = REASON_FORCED;
|
||||
appUsageHistory.bucketingReason = REASON_MAIN_FORCED;
|
||||
} else {
|
||||
appUsageHistory.currentBucket = STANDBY_BUCKET_ACTIVE;
|
||||
// This is to pretend that the app was just used, don't freeze the state anymore.
|
||||
appUsageHistory.bucketingReason = REASON_USAGE;
|
||||
appUsageHistory.bucketingReason = REASON_MAIN_USAGE | REASON_SUB_USAGE_USER_INTERACTION;
|
||||
}
|
||||
return appUsageHistory.currentBucket;
|
||||
}
|
||||
@@ -516,7 +522,7 @@ public class AppIdleHistory {
|
||||
appUsageHistory.currentBucket = currentBucketString == null
|
||||
? STANDBY_BUCKET_ACTIVE
|
||||
: Integer.parseInt(currentBucketString);
|
||||
appUsageHistory.bucketingReason =
|
||||
String bucketingReason =
|
||||
parser.getAttributeValue(null, ATTR_BUCKETING_REASON);
|
||||
appUsageHistory.lastJobRunTime = getLongValue(parser,
|
||||
ATTR_LAST_RUN_JOB_TIME, Long.MIN_VALUE);
|
||||
@@ -524,8 +530,13 @@ public class AppIdleHistory {
|
||||
ATTR_BUCKET_ACTIVE_TIMEOUT_TIME, 0L);
|
||||
appUsageHistory.bucketWorkingSetTimeoutTime = getLongValue(parser,
|
||||
ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME, 0L);
|
||||
if (appUsageHistory.bucketingReason == null) {
|
||||
appUsageHistory.bucketingReason = REASON_DEFAULT;
|
||||
appUsageHistory.bucketingReason = REASON_MAIN_DEFAULT;
|
||||
if (bucketingReason != null) {
|
||||
try {
|
||||
appUsageHistory.bucketingReason =
|
||||
Integer.parseInt(bucketingReason, 16);
|
||||
} catch (NumberFormatException nfe) {
|
||||
}
|
||||
}
|
||||
appUsageHistory.lastInformedBucket = -1;
|
||||
userHistory.put(packageName, appUsageHistory);
|
||||
@@ -574,7 +585,8 @@ public class AppIdleHistory {
|
||||
Long.toString(history.lastPredictedTime));
|
||||
xml.attribute(null, ATTR_CURRENT_BUCKET,
|
||||
Integer.toString(history.currentBucket));
|
||||
xml.attribute(null, ATTR_BUCKETING_REASON, history.bucketingReason);
|
||||
xml.attribute(null, ATTR_BUCKETING_REASON,
|
||||
Integer.toHexString(history.bucketingReason));
|
||||
if (history.bucketActiveTimeoutTime > 0) {
|
||||
xml.attribute(null, ATTR_BUCKET_ACTIVE_TIMEOUT_TIME, Long.toString(history
|
||||
.bucketActiveTimeoutTime));
|
||||
@@ -600,7 +612,7 @@ public class AppIdleHistory {
|
||||
}
|
||||
|
||||
public void dump(IndentingPrintWriter idpw, int userId, String pkg) {
|
||||
idpw.println("Package idle stats:");
|
||||
idpw.println("App Standby States:");
|
||||
idpw.increaseIndent();
|
||||
ArrayMap<String, AppUsageHistory> userHistory = mIdleHistory.get(userId);
|
||||
final long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
@@ -615,24 +627,25 @@ public class AppIdleHistory {
|
||||
continue;
|
||||
}
|
||||
idpw.print("package=" + packageName);
|
||||
idpw.print(" userId=" + userId);
|
||||
idpw.print(" lastUsedElapsed=");
|
||||
idpw.print(" u=" + userId);
|
||||
idpw.print(" bucket=" + appUsageHistory.currentBucket
|
||||
+ " reason="
|
||||
+ UsageStatsManager.reasonToString(appUsageHistory.bucketingReason));
|
||||
idpw.print(" used=");
|
||||
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
|
||||
idpw.print(" lastUsedScreenOn=");
|
||||
idpw.print(" usedScr=");
|
||||
TimeUtils.formatDuration(screenOnTime - appUsageHistory.lastUsedScreenTime, idpw);
|
||||
idpw.print(" lastPredictedTime=");
|
||||
idpw.print(" lastPred=");
|
||||
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastPredictedTime, idpw);
|
||||
idpw.print(" bucketActiveTimeoutTime=");
|
||||
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketActiveTimeoutTime,
|
||||
idpw.print(" activeLeft=");
|
||||
TimeUtils.formatDuration(appUsageHistory.bucketActiveTimeoutTime - totalElapsedTime,
|
||||
idpw);
|
||||
idpw.print(" bucketWorkingSetTimeoutTime=");
|
||||
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketWorkingSetTimeoutTime,
|
||||
idpw.print(" wsLeft=");
|
||||
TimeUtils.formatDuration(appUsageHistory.bucketWorkingSetTimeoutTime - totalElapsedTime,
|
||||
idpw);
|
||||
idpw.print(" lastJobRunTime=");
|
||||
idpw.print(" lastJob=");
|
||||
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastJobRunTime, idpw);
|
||||
idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
|
||||
idpw.print(" bucket=" + appUsageHistory.currentBucket
|
||||
+ " reason=" + appUsageHistory.bucketingReason);
|
||||
idpw.println();
|
||||
}
|
||||
idpw.println();
|
||||
|
||||
@@ -16,11 +16,20 @@
|
||||
|
||||
package com.android.server.usage;
|
||||
|
||||
import static android.app.usage.UsageStatsManager.REASON_DEFAULT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_FORCED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_PREDICTED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_TIMEOUT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_USAGE;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
|
||||
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
|
||||
@@ -129,8 +138,8 @@ public class AppStandbyController {
|
||||
STANDBY_BUCKET_RARE
|
||||
};
|
||||
|
||||
// Expiration time for predicted bucket
|
||||
private static final long PREDICTION_TIMEOUT = 12 * ONE_HOUR;
|
||||
/** Default expiration time for bucket prediction. After this, use thresholds to downgrade. */
|
||||
private static final long DEFAULT_PREDICTION_TIMEOUT = 12 * ONE_HOUR;
|
||||
|
||||
/**
|
||||
* Indicates the maximum wait time for admin data to be available;
|
||||
@@ -187,6 +196,8 @@ public class AppStandbyController {
|
||||
long mNotificationSeenTimeoutMillis;
|
||||
/** Minimum time a system update event should keep the buckets elevated. */
|
||||
long mSystemUpdateUsageTimeoutMillis;
|
||||
/** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */
|
||||
long mPredictionTimeoutMillis;
|
||||
|
||||
volatile boolean mAppIdleEnabled;
|
||||
boolean mAppIdleTempParoled;
|
||||
@@ -223,24 +234,30 @@ public class AppStandbyController {
|
||||
// Whether the bucket change is because the user has started interacting with the app
|
||||
boolean isUserInteraction;
|
||||
|
||||
StandbyUpdateRecord(String pkgName, int userId, int bucket, boolean isInteraction) {
|
||||
// Reason for bucket change
|
||||
int reason;
|
||||
|
||||
StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason,
|
||||
boolean isInteraction) {
|
||||
this.packageName = pkgName;
|
||||
this.userId = userId;
|
||||
this.bucket = bucket;
|
||||
this.reason = reason;
|
||||
this.isUserInteraction = isInteraction;
|
||||
}
|
||||
|
||||
public static StandbyUpdateRecord obtain(String pkgName, int userId,
|
||||
int bucket, boolean isInteraction) {
|
||||
int bucket, int reason, boolean isInteraction) {
|
||||
synchronized (sStandbyUpdatePool) {
|
||||
final int size = sStandbyUpdatePool.size();
|
||||
if (size < 1) {
|
||||
return new StandbyUpdateRecord(pkgName, userId, bucket, isInteraction);
|
||||
return new StandbyUpdateRecord(pkgName, userId, bucket, reason, isInteraction);
|
||||
}
|
||||
StandbyUpdateRecord r = sStandbyUpdatePool.remove(size - 1);
|
||||
r.packageName = pkgName;
|
||||
r.userId = userId;
|
||||
r.bucket = bucket;
|
||||
r.reason = reason;
|
||||
r.isUserInteraction = isInteraction;
|
||||
return r;
|
||||
}
|
||||
@@ -339,10 +356,11 @@ public class AppStandbyController {
|
||||
if (!packageName.equals(providerPkgName)) {
|
||||
synchronized (mAppIdleLock) {
|
||||
AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
|
||||
STANDBY_BUCKET_ACTIVE, elapsedRealtime,
|
||||
STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER,
|
||||
elapsedRealtime,
|
||||
elapsedRealtime + mStrongUsageTimeoutMillis);
|
||||
maybeInformListeners(packageName, userId, elapsedRealtime,
|
||||
appUsage.currentBucket, false);
|
||||
appUsage.currentBucket, appUsage.bucketingReason, false);
|
||||
}
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
@@ -497,50 +515,54 @@ public class AppStandbyController {
|
||||
if (isSpecial) {
|
||||
synchronized (mAppIdleLock) {
|
||||
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
|
||||
STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
|
||||
STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT);
|
||||
}
|
||||
maybeInformListeners(packageName, userId, elapsedRealtime,
|
||||
STANDBY_BUCKET_EXEMPTED, false);
|
||||
STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT, false);
|
||||
} else {
|
||||
synchronized (mAppIdleLock) {
|
||||
final AppIdleHistory.AppUsageHistory app =
|
||||
mAppIdleHistory.getAppUsageHistory(packageName,
|
||||
userId, elapsedRealtime);
|
||||
String reason = app.bucketingReason;
|
||||
int reason = app.bucketingReason;
|
||||
final int oldMainReason = reason & REASON_MAIN_MASK;
|
||||
|
||||
// If the bucket was forced by the user/developer, leave it alone.
|
||||
// A usage event will be the only way to bring it out of this forced state
|
||||
if (REASON_FORCED.equals(app.bucketingReason)) {
|
||||
if (oldMainReason == REASON_MAIN_FORCED) {
|
||||
return;
|
||||
}
|
||||
final int oldBucket = app.currentBucket;
|
||||
int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
|
||||
boolean predictionLate = false;
|
||||
// Compute age-based bucket
|
||||
if (REASON_DEFAULT.equals(app.bucketingReason)
|
||||
|| REASON_USAGE.equals(app.bucketingReason)
|
||||
|| REASON_TIMEOUT.equals(app.bucketingReason)
|
||||
if (oldMainReason == REASON_MAIN_DEFAULT
|
||||
|| oldMainReason == REASON_MAIN_USAGE
|
||||
|| oldMainReason == REASON_MAIN_TIMEOUT
|
||||
|| (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
|
||||
newBucket = getBucketForLocked(packageName, userId,
|
||||
elapsedRealtime);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
|
||||
}
|
||||
reason = REASON_TIMEOUT;
|
||||
reason = REASON_MAIN_TIMEOUT;
|
||||
}
|
||||
// Check if the app is within one of the timeouts for forced bucket elevation
|
||||
final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
|
||||
if (newBucket >= STANDBY_BUCKET_ACTIVE
|
||||
&& app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
|
||||
newBucket = STANDBY_BUCKET_ACTIVE;
|
||||
reason = REASON_USAGE;
|
||||
reason = app.bucketingReason;
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
|
||||
}
|
||||
} else if (newBucket >= STANDBY_BUCKET_WORKING_SET
|
||||
&& app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
|
||||
newBucket = STANDBY_BUCKET_WORKING_SET;
|
||||
reason = REASON_USAGE;
|
||||
// If it was already there, keep the reason, else assume timeout to WS
|
||||
reason = (newBucket == oldBucket)
|
||||
? app.bucketingReason
|
||||
: REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
|
||||
}
|
||||
@@ -553,43 +575,41 @@ public class AppStandbyController {
|
||||
mAppIdleHistory.setAppStandbyBucket(packageName, userId,
|
||||
elapsedRealtime, newBucket, reason);
|
||||
maybeInformListeners(packageName, userId, elapsedRealtime,
|
||||
newBucket, false);
|
||||
newBucket, reason, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if there hasn't been a prediction for the app in a while. */
|
||||
private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
|
||||
return app.bucketingReason != null
|
||||
&& app.bucketingReason.startsWith(REASON_PREDICTED)
|
||||
return (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED
|
||||
&& app.lastPredictedTime > 0
|
||||
&& mAppIdleHistory.getElapsedTime(elapsedRealtime)
|
||||
- app.lastPredictedTime > PREDICTION_TIMEOUT;
|
||||
}
|
||||
|
||||
private boolean hasBucketTimeoutPassed(AppIdleHistory.AppUsageHistory app,
|
||||
long elapsedRealtime) {
|
||||
final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
|
||||
return app.bucketActiveTimeoutTime < elapsedTimeAdjusted
|
||||
&& app.bucketWorkingSetTimeoutTime < elapsedTimeAdjusted;
|
||||
- app.lastPredictedTime > mPredictionTimeoutMillis;
|
||||
}
|
||||
|
||||
/** Inform listeners if the bucket has changed since it was last reported to listeners */
|
||||
private void maybeInformListeners(String packageName, int userId,
|
||||
long elapsedRealtime, int bucket, boolean userStartedInteracting) {
|
||||
long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting) {
|
||||
synchronized (mAppIdleLock) {
|
||||
// TODO: fold these into one call + lookup for efficiency if needed
|
||||
if (mAppIdleHistory.shouldInformListeners(packageName, userId,
|
||||
elapsedRealtime, bucket)) {
|
||||
StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId,
|
||||
bucket, userStartedInteracting);
|
||||
final StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId,
|
||||
bucket, reason, userStartedInteracting);
|
||||
if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket);
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
|
||||
StandbyUpdateRecord.obtain(packageName, userId,
|
||||
bucket, userStartedInteracting)));
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates next bucket based on time since last used and the bucketing thresholds.
|
||||
* @param packageName the app
|
||||
* @param userId the user
|
||||
* @param elapsedRealtime as the name suggests, current elapsed time
|
||||
* @return the bucket for the app, based on time since last used
|
||||
*/
|
||||
@GuardedBy("mAppIdleLock")
|
||||
@StandbyBuckets int getBucketForLocked(String packageName, int userId,
|
||||
long elapsedRealtime) {
|
||||
@@ -675,17 +695,20 @@ public class AppStandbyController {
|
||||
final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory(
|
||||
event.mPackage, userId, elapsedRealtime);
|
||||
final int prevBucket = appHistory.currentBucket;
|
||||
final String prevBucketReason = appHistory.bucketingReason;
|
||||
final int prevBucketReason = appHistory.bucketingReason;
|
||||
final long nextCheckTime;
|
||||
final int subReason = usageEventToSubReason(event.mEventType);
|
||||
final int reason = REASON_MAIN_USAGE | subReason;
|
||||
if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) {
|
||||
// Mild usage elevates to WORKING_SET but doesn't change usage time.
|
||||
mAppIdleHistory.reportUsage(appHistory, event.mPackage,
|
||||
STANDBY_BUCKET_WORKING_SET,
|
||||
STANDBY_BUCKET_WORKING_SET, subReason,
|
||||
0, elapsedRealtime + mNotificationSeenTimeoutMillis);
|
||||
nextCheckTime = mNotificationSeenTimeoutMillis;
|
||||
|
||||
} else {
|
||||
mAppIdleHistory.reportUsage(appHistory, event.mPackage,
|
||||
STANDBY_BUCKET_ACTIVE,
|
||||
STANDBY_BUCKET_ACTIVE, subReason,
|
||||
elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
|
||||
nextCheckTime = mStrongUsageTimeoutMillis;
|
||||
}
|
||||
@@ -695,9 +718,9 @@ public class AppStandbyController {
|
||||
final boolean userStartedInteracting =
|
||||
appHistory.currentBucket == STANDBY_BUCKET_ACTIVE &&
|
||||
prevBucket != appHistory.currentBucket &&
|
||||
prevBucketReason != REASON_USAGE;
|
||||
(prevBucketReason & REASON_MAIN_MASK) != REASON_MAIN_USAGE;
|
||||
maybeInformListeners(event.mPackage, userId, elapsedRealtime,
|
||||
appHistory.currentBucket, userStartedInteracting);
|
||||
appHistory.currentBucket, reason, userStartedInteracting);
|
||||
|
||||
if (previouslyIdle) {
|
||||
notifyBatteryStats(event.mPackage, userId, false);
|
||||
@@ -706,6 +729,17 @@ public class AppStandbyController {
|
||||
}
|
||||
}
|
||||
|
||||
private int usageEventToSubReason(int eventType) {
|
||||
switch (eventType) {
|
||||
case UsageEvents.Event.MOVE_TO_FOREGROUND: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
|
||||
case UsageEvents.Event.MOVE_TO_BACKGROUND: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
|
||||
case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION;
|
||||
case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION;
|
||||
case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle,
|
||||
* then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind
|
||||
@@ -731,7 +765,8 @@ public class AppStandbyController {
|
||||
userId, elapsedRealtime);
|
||||
// Inform listeners if necessary
|
||||
if (previouslyIdle != stillIdle) {
|
||||
maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket, false);
|
||||
maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket,
|
||||
REASON_MAIN_FORCED, false);
|
||||
if (!stillIdle) {
|
||||
notifyBatteryStats(packageName, userId, idle);
|
||||
}
|
||||
@@ -962,11 +997,11 @@ public class AppStandbyController {
|
||||
}
|
||||
|
||||
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
|
||||
String reason, long elapsedRealtime) {
|
||||
int reason, long elapsedRealtime) {
|
||||
synchronized (mAppIdleLock) {
|
||||
AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
|
||||
userId, elapsedRealtime);
|
||||
boolean predicted = reason != null && reason.startsWith(REASON_PREDICTED);
|
||||
boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED;
|
||||
|
||||
// Don't allow changing bucket if higher than ACTIVE
|
||||
if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return;
|
||||
@@ -979,7 +1014,7 @@ public class AppStandbyController {
|
||||
}
|
||||
|
||||
// If the bucket was forced, don't allow prediction to override
|
||||
if (app.bucketingReason.equals(REASON_FORCED) && predicted) return;
|
||||
if ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED && predicted) return;
|
||||
|
||||
// If the bucket is required to stay in a higher state for a specified duration, don't
|
||||
// override unless the duration has passed
|
||||
@@ -989,14 +1024,18 @@ public class AppStandbyController {
|
||||
if (newBucket > STANDBY_BUCKET_ACTIVE
|
||||
&& app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
|
||||
newBucket = STANDBY_BUCKET_ACTIVE;
|
||||
reason = REASON_USAGE;
|
||||
reason = app.bucketingReason;
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
|
||||
}
|
||||
} else if (newBucket > STANDBY_BUCKET_WORKING_SET
|
||||
&& app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
|
||||
newBucket = STANDBY_BUCKET_WORKING_SET;
|
||||
reason = REASON_USAGE;
|
||||
if (app.currentBucket != newBucket) {
|
||||
reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
|
||||
} else {
|
||||
reason = app.bucketingReason;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
|
||||
}
|
||||
@@ -1006,7 +1045,7 @@ public class AppStandbyController {
|
||||
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
|
||||
reason);
|
||||
}
|
||||
maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, false);
|
||||
maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -1106,11 +1145,12 @@ public class AppStandbyController {
|
||||
return packageName != null && packageName.equals(activeScorer);
|
||||
}
|
||||
|
||||
void informListeners(String packageName, int userId, int bucket, boolean userInteraction) {
|
||||
void informListeners(String packageName, int userId, int bucket, int reason,
|
||||
boolean userInteraction) {
|
||||
final boolean idle = bucket >= STANDBY_BUCKET_RARE;
|
||||
synchronized (mPackageAccessListeners) {
|
||||
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
|
||||
listener.onAppIdleStateChanged(packageName, userId, idle, bucket);
|
||||
listener.onAppIdleStateChanged(packageName, userId, idle, bucket, reason);
|
||||
if (userInteraction) {
|
||||
listener.onUserInteractionStarted(packageName, userId);
|
||||
}
|
||||
@@ -1188,7 +1228,8 @@ public class AppStandbyController {
|
||||
if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
|
||||
// Mark app as used for 2 hours. After that it can timeout to whatever the
|
||||
// past usage pattern was.
|
||||
mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 0,
|
||||
mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_SUB_USAGE_SYSTEM_UPDATE, 0,
|
||||
elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
|
||||
}
|
||||
}
|
||||
@@ -1369,7 +1410,8 @@ public class AppStandbyController {
|
||||
switch (msg.what) {
|
||||
case MSG_INFORM_LISTENERS:
|
||||
StandbyUpdateRecord r = (StandbyUpdateRecord) msg.obj;
|
||||
informListeners(r.packageName, r.userId, r.bucket, r.isUserInteraction);
|
||||
informListeners(r.packageName, r.userId, r.bucket, r.reason,
|
||||
r.isUserInteraction);
|
||||
r.recycle();
|
||||
break;
|
||||
|
||||
@@ -1477,7 +1519,7 @@ public class AppStandbyController {
|
||||
"notification_seen_duration";
|
||||
private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION =
|
||||
"system_update_usage_duration";
|
||||
|
||||
private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
|
||||
|
||||
private final KeyValueListParser mParser = new KeyValueListParser(',');
|
||||
|
||||
@@ -1547,6 +1589,9 @@ public class AppStandbyController {
|
||||
mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis
|
||||
(KEY_SYSTEM_UPDATE_HOLD_DURATION,
|
||||
COMPRESS_TIME ? 2 * ONE_MINUTE : 2 * ONE_HOUR);
|
||||
mPredictionTimeoutMillis = mParser.getDurationMillis
|
||||
(KEY_PREDICTION_TIMEOUT,
|
||||
COMPRESS_TIME ? 10 * ONE_MINUTE : DEFAULT_PREDICTION_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -120,10 +120,10 @@ public class UsageStatsService extends SystemService implements
|
||||
new UsageStatsManagerInternal.AppIdleStateChangeListener() {
|
||||
@Override
|
||||
public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
|
||||
int bucket) {
|
||||
int bucket, int reason) {
|
||||
Event event = new Event();
|
||||
event.mEventType = Event.STANDBY_BUCKET_CHANGED;
|
||||
event.mBucket = bucket;
|
||||
event.mBucketAndReason = (bucket << 16) | (reason & 0xFFFF);
|
||||
event.mPackage = packageName;
|
||||
// This will later be converted to system time.
|
||||
event.mTimeStamp = SystemClock.elapsedRealtime();
|
||||
@@ -741,9 +741,9 @@ public class UsageStatsService extends SystemService implements
|
||||
throw re.rethrowFromSystemServer();
|
||||
}
|
||||
final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID;
|
||||
final String reason = shellCaller
|
||||
? UsageStatsManager.REASON_FORCED
|
||||
: UsageStatsManager.REASON_PREDICTED + ":" + callingUid;
|
||||
final int reason = shellCaller
|
||||
? UsageStatsManager.REASON_MAIN_FORCED
|
||||
: UsageStatsManager.REASON_MAIN_PREDICTED;
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
// Caller cannot set their own standby state
|
||||
@@ -798,9 +798,9 @@ public class UsageStatsService extends SystemService implements
|
||||
throw re.rethrowFromSystemServer();
|
||||
}
|
||||
final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID;
|
||||
final String reason = shellCaller
|
||||
? UsageStatsManager.REASON_FORCED
|
||||
: UsageStatsManager.REASON_PREDICTED + ":" + callingUid;
|
||||
final int reason = shellCaller
|
||||
? UsageStatsManager.REASON_MAIN_FORCED
|
||||
: UsageStatsManager.REASON_MAIN_PREDICTED;
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
|
||||
@@ -26,10 +26,7 @@ import android.app.usage.TimeSparseArray;
|
||||
import android.app.usage.UsageEvents;
|
||||
import android.app.usage.UsageStats;
|
||||
import android.content.res.Configuration;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.LogWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ProtocolException;
|
||||
@@ -175,7 +172,7 @@ final class UsageStatsXmlV1 {
|
||||
event.mShortcutId = (id != null) ? id.intern() : null;
|
||||
break;
|
||||
case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
|
||||
event.mBucket = XmlUtils.readIntAttribute(parser, STANDBY_BUCKET_ATTR, 0);
|
||||
event.mBucketAndReason = XmlUtils.readIntAttribute(parser, STANDBY_BUCKET_ATTR, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -281,8 +278,8 @@ final class UsageStatsXmlV1 {
|
||||
}
|
||||
break;
|
||||
case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
|
||||
if (event.mBucket != 0) {
|
||||
XmlUtils.writeIntAttribute(xml, STANDBY_BUCKET_ATTR, event.mBucket);
|
||||
if (event.mBucketAndReason != 0) {
|
||||
XmlUtils.writeIntAttribute(xml, STANDBY_BUCKET_ATTR, event.mBucketAndReason);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -520,7 +520,8 @@ class UserUsageStatsService {
|
||||
pw.printPair("shortcutId", event.mShortcutId);
|
||||
}
|
||||
if (event.mEventType == UsageEvents.Event.STANDBY_BUCKET_CHANGED) {
|
||||
pw.printPair("standbyBucket", event.mBucket);
|
||||
pw.printPair("standbyBucket", event.getStandbyBucket());
|
||||
pw.printPair("reason", UsageStatsManager.reasonToString(event.getStandbyReason()));
|
||||
}
|
||||
pw.printHexPair("flags", event.mFlags);
|
||||
pw.println();
|
||||
|
||||
Reference in New Issue
Block a user