Merge "Move setAppStandby logic inside AppStandbyController."
This commit is contained in:
committed by
Android (Google) Code Review
commit
5049573e20
@@ -1,5 +1,6 @@
|
||||
package com.android.server.usage;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.usage.AppStandbyInfo;
|
||||
import android.app.usage.UsageEvents;
|
||||
@@ -99,8 +100,18 @@ public interface AppStandbyInternal {
|
||||
|
||||
List<AppStandbyInfo> getAppStandbyBuckets(int userId);
|
||||
|
||||
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
|
||||
int reason, long elapsedRealtime, boolean resetTimeout);
|
||||
/**
|
||||
* Changes an app's standby bucket to the provided value. The caller can only set the standby
|
||||
* bucket for a different app than itself.
|
||||
*/
|
||||
void setAppStandbyBucket(@NonNull String packageName, int bucket, int userId, int callingUid,
|
||||
int callingPid);
|
||||
|
||||
/**
|
||||
* Changes the app standby bucket for multiple apps at once.
|
||||
*/
|
||||
void setAppStandbyBuckets(@NonNull List<AppStandbyInfo> appBuckets, int userId, int callingUid,
|
||||
int callingPid);
|
||||
|
||||
void addActiveDeviceAdmin(String adminPkg, int userId);
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
|
||||
|
||||
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppGlobals;
|
||||
@@ -101,7 +102,6 @@ import com.android.internal.util.ConcurrentUtils;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.usage.AppIdleHistory.AppUsageHistory;
|
||||
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
@@ -109,6 +109,7 @@ import java.time.Duration;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -1014,14 +1015,57 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
|
||||
int reason, long elapsedRealtime) {
|
||||
setAppStandbyBucket(packageName, userId, newBucket, reason, elapsedRealtime, false);
|
||||
@Override
|
||||
public void setAppStandbyBucket(@NonNull String packageName, int bucket, int userId,
|
||||
int callingUid, int callingPid) {
|
||||
setAppStandbyBuckets(
|
||||
Collections.singletonList(new AppStandbyInfo(packageName, bucket)),
|
||||
userId, callingUid, callingPid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
|
||||
public void setAppStandbyBuckets(@NonNull List<AppStandbyInfo> appBuckets, int userId,
|
||||
int callingUid, int callingPid) {
|
||||
userId = ActivityManager.handleIncomingUser(
|
||||
callingPid, callingUid, userId, false, true, "setAppStandbyBucket", null);
|
||||
final boolean shellCaller = callingUid == Process.ROOT_UID
|
||||
|| callingUid == Process.SHELL_UID;
|
||||
final boolean systemCaller = UserHandle.isCore(callingUid);
|
||||
final int reason = systemCaller ? REASON_MAIN_FORCED : REASON_MAIN_PREDICTED;
|
||||
final int packageFlags = PackageManager.MATCH_ANY_USER
|
||||
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_AWARE;
|
||||
final int numApps = appBuckets.size();
|
||||
final long elapsedRealtime = mInjector.elapsedRealtime();
|
||||
for (int i = 0; i < numApps; ++i) {
|
||||
final AppStandbyInfo bucketInfo = appBuckets.get(i);
|
||||
final String packageName = bucketInfo.mPackageName;
|
||||
final int bucket = bucketInfo.mStandbyBucket;
|
||||
if (bucket < STANDBY_BUCKET_ACTIVE || bucket > STANDBY_BUCKET_NEVER) {
|
||||
throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket);
|
||||
}
|
||||
final int packageUid = mInjector.getPackageManagerInternal()
|
||||
.getPackageUid(packageName, packageFlags, userId);
|
||||
// Caller cannot set their own standby state
|
||||
if (packageUid == callingUid) {
|
||||
throw new IllegalArgumentException("Cannot set your own standby bucket");
|
||||
}
|
||||
if (packageUid < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set standby bucket for non existent package (" + packageName + ")");
|
||||
}
|
||||
setAppStandbyBucket(packageName, userId, bucket, reason, elapsedRealtime, shellCaller);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
|
||||
int reason) {
|
||||
setAppStandbyBucket(
|
||||
packageName, userId, newBucket, reason, mInjector.elapsedRealtime(), false);
|
||||
}
|
||||
|
||||
private void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
|
||||
int reason, long elapsedRealtime, boolean resetTimeout) {
|
||||
synchronized (mAppIdleLock) {
|
||||
// If the package is not installed, don't allow the bucket to be set.
|
||||
@@ -1444,6 +1488,10 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
mBatteryStats.noteEvent(event, packageName, uid);
|
||||
}
|
||||
|
||||
PackageManagerInternal getPackageManagerInternal() {
|
||||
return mPackageManagerInternal;
|
||||
}
|
||||
|
||||
boolean isPackageEphemeral(int userId, String packageName) {
|
||||
return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
|
||||
}
|
||||
|
||||
@@ -365,8 +365,9 @@ public class AppStandbyControllerTests {
|
||||
public void testSetAppStandbyBucket() throws Exception {
|
||||
// For a known package, standby bucket should be set properly
|
||||
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
|
||||
mInjector.mElapsedRealtime = HOUR_MS;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_MAIN_TIMEOUT, HOUR_MS);
|
||||
REASON_MAIN_TIMEOUT);
|
||||
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
|
||||
|
||||
// For an unknown package, standby bucket should not be set, hence NEVER is returned
|
||||
@@ -374,7 +375,7 @@ public class AppStandbyControllerTests {
|
||||
mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
|
||||
isPackageInstalled = false; // Mock package is not installed
|
||||
mController.setAppStandbyBucket(PACKAGE_UNKNOWN, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_MAIN_TIMEOUT, HOUR_MS);
|
||||
REASON_MAIN_TIMEOUT);
|
||||
isPackageInstalled = true; // Reset mocked variable for other tests
|
||||
assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
|
||||
}
|
||||
@@ -468,12 +469,13 @@ public class AppStandbyControllerTests {
|
||||
@Test
|
||||
public void testPredictionTimedout() throws Exception {
|
||||
// Set it to timeout or usage, so that prediction can override it
|
||||
mInjector.mElapsedRealtime = HOUR_MS;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
|
||||
REASON_MAIN_TIMEOUT, HOUR_MS);
|
||||
REASON_MAIN_TIMEOUT);
|
||||
assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
|
||||
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_MAIN_PREDICTED, HOUR_MS);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
|
||||
|
||||
// Fast forward 12 hours
|
||||
@@ -497,29 +499,31 @@ public class AppStandbyControllerTests {
|
||||
@Test
|
||||
public void testOverrides() throws Exception {
|
||||
// Can force to NEVER
|
||||
mInjector.mElapsedRealtime = HOUR_MS;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
|
||||
REASON_MAIN_FORCED, 1 * HOUR_MS);
|
||||
REASON_MAIN_FORCED);
|
||||
assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
|
||||
|
||||
// Prediction can't override FORCED reason
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_MAIN_FORCED, 1 * HOUR_MS);
|
||||
REASON_MAIN_FORCED);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
|
||||
REASON_MAIN_PREDICTED, 1 * HOUR_MS);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
|
||||
|
||||
// Prediction can't override NEVER
|
||||
mInjector.mElapsedRealtime = 2 * HOUR_MS;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
|
||||
REASON_MAIN_DEFAULT, 2 * HOUR_MS);
|
||||
REASON_MAIN_DEFAULT);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_MAIN_PREDICTED, 2 * HOUR_MS);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
|
||||
|
||||
// Prediction can't set to NEVER
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_MAIN_USAGE, 2 * HOUR_MS);
|
||||
REASON_MAIN_USAGE);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
|
||||
REASON_MAIN_PREDICTED, 2 * HOUR_MS);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
|
||||
}
|
||||
|
||||
@@ -530,7 +534,7 @@ public class AppStandbyControllerTests {
|
||||
|
||||
mInjector.mElapsedRealtime = 2000;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertBucket(STANDBY_BUCKET_ACTIVE);
|
||||
|
||||
// bucketing works after timeout
|
||||
@@ -554,15 +558,17 @@ public class AppStandbyControllerTests {
|
||||
assertBucket(STANDBY_BUCKET_ACTIVE);
|
||||
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
|
||||
REASON_MAIN_PREDICTED, 1000);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertBucket(STANDBY_BUCKET_ACTIVE);
|
||||
|
||||
mInjector.mElapsedRealtime = 2000 + mController.mStrongUsageTimeoutMillis;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_MAIN_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertBucket(STANDBY_BUCKET_WORKING_SET);
|
||||
|
||||
mInjector.mElapsedRealtime = 2000 + mController.mNotificationSeenTimeoutMillis;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_MAIN_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertBucket(STANDBY_BUCKET_FREQUENT);
|
||||
}
|
||||
|
||||
@@ -582,18 +588,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_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED);
|
||||
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_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertBucket(STANDBY_BUCKET_WORKING_SET);
|
||||
|
||||
mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertBucket(STANDBY_BUCKET_RARE);
|
||||
}
|
||||
|
||||
@@ -625,7 +631,7 @@ public class AppStandbyControllerTests {
|
||||
mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100;
|
||||
// Make sure app is in NEVER bucket
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
|
||||
REASON_MAIN_FORCED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_FORCED);
|
||||
mController.checkIdleStates(USER_ID);
|
||||
assertBucket(STANDBY_BUCKET_NEVER);
|
||||
|
||||
@@ -670,7 +676,7 @@ public class AppStandbyControllerTests {
|
||||
// Predict to ACTIVE
|
||||
mInjector.mElapsedRealtime += 1000;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertBucket(STANDBY_BUCKET_ACTIVE);
|
||||
|
||||
// CheckIdleStates should not change the prediction
|
||||
@@ -687,7 +693,7 @@ public class AppStandbyControllerTests {
|
||||
// Predict to FREQUENT
|
||||
mInjector.mElapsedRealtime = RARE_THRESHOLD;
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
|
||||
REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
|
||||
REASON_MAIN_PREDICTED);
|
||||
assertBucket(STANDBY_BUCKET_FREQUENT);
|
||||
|
||||
// Add a short timeout event
|
||||
|
||||
@@ -1568,44 +1568,16 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAppStandbyBucket(String packageName,
|
||||
int bucket, int userId) {
|
||||
public void setAppStandbyBucket(String packageName, int bucket, int userId) {
|
||||
getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
|
||||
"No permission to change app standby state");
|
||||
|
||||
if (bucket < UsageStatsManager.STANDBY_BUCKET_ACTIVE
|
||||
|| bucket > UsageStatsManager.STANDBY_BUCKET_NEVER) {
|
||||
throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket);
|
||||
}
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
try {
|
||||
userId = ActivityManager.getService().handleIncomingUser(
|
||||
Binder.getCallingPid(), callingUid, userId, false, true,
|
||||
"setAppStandbyBucket", null);
|
||||
} catch (RemoteException re) {
|
||||
throw re.rethrowFromSystemServer();
|
||||
}
|
||||
final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID;
|
||||
final boolean systemCaller = UserHandle.isCore(callingUid);
|
||||
final int reason = systemCaller
|
||||
? UsageStatsManager.REASON_MAIN_FORCED
|
||||
: UsageStatsManager.REASON_MAIN_PREDICTED;
|
||||
final int callingPid = Binder.getCallingPid();
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final int packageUid = mPackageManagerInternal.getPackageUid(packageName,
|
||||
PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_AWARE, userId);
|
||||
// Caller cannot set their own standby state
|
||||
if (packageUid == callingUid) {
|
||||
throw new IllegalArgumentException("Cannot set your own standby bucket");
|
||||
}
|
||||
if (packageUid < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set standby bucket for non existent package (" + packageName
|
||||
+ ")");
|
||||
}
|
||||
mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason,
|
||||
SystemClock.elapsedRealtime(), shellCaller);
|
||||
mAppStandby.setAppStandbyBucket(packageName, bucket, userId,
|
||||
callingUid, callingPid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -1643,37 +1615,11 @@ public class UsageStatsService extends SystemService implements
|
||||
"No permission to change app standby state");
|
||||
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
try {
|
||||
userId = ActivityManager.getService().handleIncomingUser(
|
||||
Binder.getCallingPid(), callingUid, userId, false, true,
|
||||
"setAppStandbyBucket", null);
|
||||
} catch (RemoteException re) {
|
||||
throw re.rethrowFromSystemServer();
|
||||
}
|
||||
final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID;
|
||||
final int reason = shellCaller
|
||||
? UsageStatsManager.REASON_MAIN_FORCED
|
||||
: UsageStatsManager.REASON_MAIN_PREDICTED;
|
||||
final int callingPid = Binder.getCallingPid();
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
List<AppStandbyInfo> bucketList = appBuckets.getList();
|
||||
for (AppStandbyInfo bucketInfo : bucketList) {
|
||||
final String packageName = bucketInfo.mPackageName;
|
||||
final int bucket = bucketInfo.mStandbyBucket;
|
||||
if (bucket < UsageStatsManager.STANDBY_BUCKET_ACTIVE
|
||||
|| bucket > UsageStatsManager.STANDBY_BUCKET_NEVER) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set the standby bucket to " + bucket);
|
||||
}
|
||||
// Caller cannot set their own standby state
|
||||
if (mPackageManagerInternal.getPackageUid(packageName,
|
||||
PackageManager.MATCH_ANY_USER, userId) == callingUid) {
|
||||
throw new IllegalArgumentException("Cannot set your own standby bucket");
|
||||
}
|
||||
mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason,
|
||||
elapsedRealtime, shellCaller);
|
||||
}
|
||||
mAppStandby.setAppStandbyBuckets(appBuckets.getList(), userId,
|
||||
callingUid, callingPid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user