MoveAppStandbyController to the jobscheduler module

Bug: 137763703
Test: boot
Test: atest AppStandbyControllerTests
Change-Id: I03799c976f6c8b3e775a1a6321885a9cb069a0a0
This commit is contained in:
Makoto Onuki
2019-10-03 11:10:45 -07:00
parent c779915902
commit a72e04fcd9
5 changed files with 204 additions and 70 deletions

View File

@@ -0,0 +1,112 @@
package com.android.server.usage;
import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
import android.content.Context;
import android.os.Looper;
import com.android.internal.util.IndentingPrintWriter;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Set;
public interface AppStandbyInternal {
/**
* TODO AppStandbyController should probably be a binder service, and then we shouldn't need
* this method.
*/
static AppStandbyInternal newAppStandbyController(ClassLoader loader, Context context,
Looper looper) {
try {
final Class<?> clazz = Class.forName("com.android.server.usage.AppStandbyController",
true, loader);
final Constructor<?> ctor = clazz.getConstructor(Context.class, Looper.class);
return (AppStandbyInternal) ctor.newInstance(context, looper);
} catch (NoSuchMethodException | InstantiationException
| IllegalAccessException | InvocationTargetException | ClassNotFoundException e) {
throw new RuntimeException("Unable to instantiate AppStandbyController!", e);
}
}
void onBootPhase(int phase);
boolean isParoledOrCharging();
void postCheckIdleStates(int userId);
/**
* We send a different message to check idle states once, otherwise we would end up
* scheduling a series of repeating checkIdleStates each time we fired off one.
*/
void postOneTimeCheckIdleStates();
void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId);
void setLastJobRunTime(String packageName, int userId, long elapsedRealtime);
long getTimeSinceLastJobRun(String packageName, int userId);
void onUserRemoved(int userId);
void addListener(AppIdleStateChangeListener listener);
void removeListener(AppIdleStateChangeListener listener);
int getAppId(String packageName);
boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime,
boolean shouldObfuscateInstantApps);
/**
* Checks if an app has been idle for a while and filters out apps that are excluded.
* It returns false if the current system state allows all apps to be considered active.
* This happens if the device is plugged in or temporarily allowed to make exceptions.
* Called by interface impls.
*/
boolean isAppIdleFiltered(String packageName, int appId, int userId,
long elapsedRealtime);
int[] getIdleUidsForUser(int userId);
void setAppIdleAsync(String packageName, boolean idle, int userId);
@StandbyBuckets
int getAppStandbyBucket(String packageName, int userId,
long elapsedRealtime, boolean shouldObfuscateInstantApps);
List<AppStandbyInfo> getAppStandbyBuckets(int userId);
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
int reason, long elapsedRealtime, boolean resetTimeout);
void addActiveDeviceAdmin(String adminPkg, int userId);
void setActiveAdminApps(Set<String> adminPkgs, int userId);
void onAdminDataAvailable();
void clearCarrierPrivilegedApps();
void flushToDisk(int userId);
void flushDurationsToDisk();
void initializeDefaultsForSystemApps(int userId);
void postReportContentProviderUsage(String name, String packageName, int userId);
void postReportSyncScheduled(String packageName, int userId, boolean exempted);
void postReportExemptedSyncStart(String packageName, int userId);
void dumpUser(IndentingPrintWriter idpw, int userId, String pkg);
void dumpState(String[] args, PrintWriter pw);
boolean isAppIdleEnabled();
}

View File

@@ -120,9 +120,9 @@ import java.util.concurrent.CountDownLatch;
* Manages the standby state of an app, listening to various events.
*
* Unit test:
atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
atest com.android.server.usage.AppStandbyControllerTests
*/
public class AppStandbyController {
public class AppStandbyController implements AppStandbyInternal {
private static final String TAG = "AppStandbyController";
static final boolean DEBUG = false;
@@ -247,7 +247,7 @@ public class AppStandbyController {
/** The length of time phone must be charging before considered stable enough to run jobs */
long mStableChargingThresholdMillis;
volatile boolean mAppIdleEnabled;
private volatile boolean mAppIdleEnabled;
boolean mAppIdleTempParoled;
boolean mCharging;
boolean mChargingStable;
@@ -320,7 +320,7 @@ public class AppStandbyController {
}
}
AppStandbyController(Context context, Looper looper) {
public AppStandbyController(Context context, Looper looper) {
this(new Injector(context, looper));
}
@@ -351,6 +351,7 @@ public class AppStandbyController {
null, mHandler);
}
@VisibleForTesting
void setAppIdleEnabled(boolean enabled) {
synchronized (mAppIdleLock) {
if (mAppIdleEnabled != enabled) {
@@ -363,6 +364,12 @@ public class AppStandbyController {
}
}
@Override
public boolean isAppIdleEnabled() {
return mAppIdleEnabled;
}
@Override
public void onBootPhase(int phase) {
mInjector.onBootPhase(phase);
if (phase == PHASE_SYSTEM_SERVICES_READY) {
@@ -400,7 +407,7 @@ public class AppStandbyController {
}
}
void reportContentProviderUsage(String authority, String providerPkgName, int userId) {
private void reportContentProviderUsage(String authority, String providerPkgName, int userId) {
if (!mAppIdleEnabled) return;
// Get sync adapters for the authority
@@ -432,7 +439,7 @@ public class AppStandbyController {
}
}
void reportExemptedSyncScheduled(String packageName, int userId) {
private void reportExemptedSyncScheduled(String packageName, int userId) {
if (!mAppIdleEnabled) return;
final int bucketToPromote;
@@ -463,7 +470,7 @@ public class AppStandbyController {
}
}
void reportUnexemptedSyncScheduled(String packageName, int userId) {
private void reportUnexemptedSyncScheduled(String packageName, int userId) {
if (!mAppIdleEnabled) return;
final long elapsedRealtime = mInjector.elapsedRealtime();
@@ -482,7 +489,7 @@ public class AppStandbyController {
}
}
void reportExemptedSyncStart(String packageName, int userId) {
private void reportExemptedSyncStart(String packageName, int userId) {
if (!mAppIdleEnabled) return;
final long elapsedRealtime = mInjector.elapsedRealtime();
@@ -497,6 +504,7 @@ public class AppStandbyController {
}
}
@VisibleForTesting
void setChargingState(boolean charging) {
synchronized (mAppIdleLock) {
if (mCharging != charging) {
@@ -517,7 +525,7 @@ public class AppStandbyController {
}
}
void updateChargingStableState() {
private void updateChargingStableState() {
synchronized (mAppIdleLock) {
if (mChargingStable != mCharging) {
if (DEBUG) Slog.d(TAG, "Setting mChargingStable to " + mCharging);
@@ -527,8 +535,7 @@ public class AppStandbyController {
}
}
/** Paroled here means temporary pardon from being inactive */
void setAppIdleParoled(boolean paroled) {
private void setAppIdleParoled(boolean paroled) {
synchronized (mAppIdleLock) {
final long now = mInjector.currentTimeMillis();
if (mAppIdleTempParoled != paroled) {
@@ -545,7 +552,8 @@ public class AppStandbyController {
}
}
boolean isParoledOrCharging() {
@Override
public boolean isParoledOrCharging() {
if (!mAppIdleEnabled) return true;
synchronized (mAppIdleLock) {
// Only consider stable charging when determining charge state.
@@ -583,15 +591,13 @@ public class AppStandbyController {
mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
}
void postCheckIdleStates(int userId) {
@Override
public void postCheckIdleStates(int userId) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
/**
* We send a different message to check idle states once, otherwise we would end up
* scheduling a series of repeating checkIdleStates each time we fired off one.
*/
void postOneTimeCheckIdleStates() {
@Override
public void postOneTimeCheckIdleStates() {
if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) {
// Not booted yet; wait for it!
mPendingOneTimeCheckIdleStates = true;
@@ -601,10 +607,7 @@ public class AppStandbyController {
}
}
/**
* Check all running users' or specified user's apps to see if they enter an idle state.
* @return Returns whether checking should continue periodically.
*/
@VisibleForTesting
boolean checkIdleStates(int checkUserId) {
if (!mAppIdleEnabled) {
return false;
@@ -776,19 +779,15 @@ public class AppStandbyController {
* @return the bucket for the app, based on time since last used
*/
@GuardedBy("mAppIdleLock")
@StandbyBuckets int getBucketForLocked(String packageName, int userId,
@StandbyBuckets
private int getBucketForLocked(String packageName, int userId,
long elapsedRealtime) {
int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId,
elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds);
return THRESHOLD_BUCKETS[bucketIndex];
}
/**
* Check if it's been a while since last parole and let idle apps do some work.
* If network is not available, delay parole until it is available up until the end of the
* parole window. Force the parole to be set if end of the parole window is reached.
*/
void checkParoleTimeout() {
private void checkParoleTimeout() {
boolean setParoled = false;
boolean waitForNetwork = false;
NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo();
@@ -845,7 +844,7 @@ public class AppStandbyController {
}
}
void onDeviceIdleModeChanged() {
private void onDeviceIdleModeChanged() {
final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
boolean paroled = false;
@@ -869,7 +868,8 @@ public class AppStandbyController {
setAppIdleParoled(paroled);
}
void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) {
@Override
public void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) {
if (!mAppIdleEnabled) return;
synchronized (mAppIdleLock) {
// TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
@@ -950,14 +950,7 @@ public class AppStandbyController {
}
}
/**
* 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
* the threshold for idle.
*
* This method is always called from the handler thread, so not much synchronization is
* required.
*/
@VisibleForTesting
void forceIdleState(String packageName, int userId, boolean idle) {
if (!mAppIdleEnabled) return;
@@ -983,12 +976,14 @@ public class AppStandbyController {
}
}
@Override
public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) {
synchronized (mAppIdleLock) {
mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime);
}
}
@Override
public long getTimeSinceLastJobRun(String packageName, int userId) {
final long elapsedRealtime = mInjector.elapsedRealtime();
synchronized (mAppIdleLock) {
@@ -996,6 +991,7 @@ public class AppStandbyController {
}
}
@Override
public void onUserRemoved(int userId) {
synchronized (mAppIdleLock) {
mAppIdleHistory.onUserRemoved(userId);
@@ -1011,7 +1007,8 @@ public class AppStandbyController {
}
}
void addListener(AppIdleStateChangeListener listener) {
@Override
public void addListener(AppIdleStateChangeListener listener) {
synchronized (mPackageAccessListeners) {
if (!mPackageAccessListeners.contains(listener)) {
mPackageAccessListeners.add(listener);
@@ -1019,13 +1016,15 @@ public class AppStandbyController {
}
}
void removeListener(AppIdleStateChangeListener listener) {
@Override
public void removeListener(AppIdleStateChangeListener listener) {
synchronized (mPackageAccessListeners) {
mPackageAccessListeners.remove(listener);
}
}
int getAppId(String packageName) {
@Override
public int getAppId(String packageName) {
try {
ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
PackageManager.MATCH_ANY_USER
@@ -1036,7 +1035,8 @@ public class AppStandbyController {
}
}
boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime,
@Override
public boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime,
boolean shouldObfuscateInstantApps) {
if (isParoledOrCharging()) {
return false;
@@ -1048,8 +1048,7 @@ public class AppStandbyController {
return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
}
/** Returns true if this app should be whitelisted for some reason, to never go into standby */
boolean isAppSpecial(String packageName, int appId, int userId) {
private boolean isAppSpecial(String packageName, int appId, int userId) {
if (packageName == null) return false;
// If not enabled at all, of course nobody is ever idle.
if (!mAppIdleEnabled) {
@@ -1102,13 +1101,8 @@ public class AppStandbyController {
return false;
}
/**
* Checks if an app has been idle for a while and filters out apps that are excluded.
* It returns false if the current system state allows all apps to be considered active.
* This happens if the device is plugged in or temporarily allowed to make exceptions.
* Called by interface impls.
*/
boolean isAppIdleFiltered(String packageName, int appId, int userId,
@Override
public boolean isAppIdleFiltered(String packageName, int appId, int userId,
long elapsedRealtime) {
if (isAppSpecial(packageName, appId, userId)) {
return false;
@@ -1117,7 +1111,8 @@ public class AppStandbyController {
}
}
int[] getIdleUidsForUser(int userId) {
@Override
public int[] getIdleUidsForUser(int userId) {
if (!mAppIdleEnabled) {
return new int[0];
}
@@ -1181,13 +1176,15 @@ public class AppStandbyController {
return res;
}
void setAppIdleAsync(String packageName, boolean idle, int userId) {
@Override
public void setAppIdleAsync(String packageName, boolean idle, int userId) {
if (packageName == null || !mAppIdleEnabled) return;
mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
.sendToTarget();
}
@Override
@StandbyBuckets public int getAppStandbyBucket(String packageName, int userId,
long elapsedRealtime, boolean shouldObfuscateInstantApps) {
if (!mAppIdleEnabled || (shouldObfuscateInstantApps
@@ -1200,18 +1197,21 @@ public class AppStandbyController {
}
}
@Override
public List<AppStandbyInfo> getAppStandbyBuckets(int userId) {
synchronized (mAppIdleLock) {
return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled);
}
}
@VisibleForTesting
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
int reason, long elapsedRealtime) {
setAppStandbyBucket(packageName, userId, newBucket, reason, elapsedRealtime, false);
}
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
@Override
public 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.
@@ -1279,6 +1279,7 @@ public class AppStandbyController {
}
}
@Override
public void addActiveDeviceAdmin(String adminPkg, int userId) {
synchronized (mActiveAdminApps) {
Set<String> adminPkgs = mActiveAdminApps.get(userId);
@@ -1290,6 +1291,7 @@ public class AppStandbyController {
}
}
@Override
public void setActiveAdminApps(Set<String> adminPkgs, int userId) {
synchronized (mActiveAdminApps) {
if (adminPkgs == null) {
@@ -1300,6 +1302,7 @@ public class AppStandbyController {
}
}
@Override
public void onAdminDataAvailable() {
mAdminDataAvailableLatch.countDown();
}
@@ -1314,6 +1317,7 @@ public class AppStandbyController {
}
}
@VisibleForTesting
Set<String> getActiveAdminAppsForTest(int userId) {
synchronized (mActiveAdminApps) {
return mActiveAdminApps.get(userId);
@@ -1342,7 +1346,8 @@ public class AppStandbyController {
}
}
void clearCarrierPrivilegedApps() {
@Override
public void clearCarrierPrivilegedApps() {
if (DEBUG) {
Slog.i(TAG, "Clearing carrier privileged apps list");
}
@@ -1368,7 +1373,7 @@ public class AppStandbyController {
return packageName != null && packageName.equals(activeScorer);
}
void informListeners(String packageName, int userId, int bucket, int reason,
private void informListeners(String packageName, int userId, int bucket, int reason,
boolean userInteraction) {
final boolean idle = bucket >= STANDBY_BUCKET_RARE;
synchronized (mPackageAccessListeners) {
@@ -1381,7 +1386,7 @@ public class AppStandbyController {
}
}
void informParoleStateChanged() {
private void informParoleStateChanged() {
final boolean paroled = isParoledOrCharging();
synchronized (mPackageAccessListeners) {
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
@@ -1390,13 +1395,15 @@ public class AppStandbyController {
}
}
void flushToDisk(int userId) {
@Override
public void flushToDisk(int userId) {
synchronized (mAppIdleLock) {
mAppIdleHistory.writeAppIdleTimes(userId);
}
}
void flushDurationsToDisk() {
@Override
public void flushDurationsToDisk() {
// Persist elapsed and screen on time. If this fails for whatever reason, the apps will be
// considered not-idle, which is the safest outcome in such an event.
synchronized (mAppIdleLock) {
@@ -1404,10 +1411,11 @@ public class AppStandbyController {
}
}
boolean isDisplayOn() {
private boolean isDisplayOn() {
return mInjector.isDefaultDisplayOn();
}
@VisibleForTesting
void clearAppIdleForPackage(String packageName, int userId) {
synchronized (mAppIdleLock) {
mAppIdleHistory.clearUsage(packageName, userId);
@@ -1431,7 +1439,8 @@ public class AppStandbyController {
}
}
void initializeDefaultsForSystemApps(int userId) {
@Override
public void initializeDefaultsForSystemApps(int userId) {
if (!mSystemServicesReady) {
// Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled
mPendingInitializeDefaults = true;
@@ -1461,7 +1470,8 @@ public class AppStandbyController {
}
}
void postReportContentProviderUsage(String name, String packageName, int userId) {
@Override
public void postReportContentProviderUsage(String name, String packageName, int userId) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = name;
args.arg2 = packageName;
@@ -1470,23 +1480,27 @@ public class AppStandbyController {
.sendToTarget();
}
void postReportSyncScheduled(String packageName, int userId, boolean exempted) {
@Override
public void postReportSyncScheduled(String packageName, int userId, boolean exempted) {
mHandler.obtainMessage(MSG_REPORT_SYNC_SCHEDULED, userId, exempted ? 1 : 0, packageName)
.sendToTarget();
}
void postReportExemptedSyncStart(String packageName, int userId) {
@Override
public void postReportExemptedSyncStart(String packageName, int userId) {
mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
.sendToTarget();
}
void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) {
@Override
public void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) {
synchronized (mAppIdleLock) {
mAppIdleHistory.dump(idpw, userId, pkg);
}
}
void dumpState(String[] args, PrintWriter pw) {
@Override
public void dumpState(String[] args, PrintWriter pw) {
synchronized (mAppIdleLock) {
pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
+ "): " + mCarrierPrivilegedApps);

View File

@@ -22,6 +22,10 @@ import android.os.Parcelable;
/**
* A pair of {package, bucket} to denote the app standby bucket for a given package.
* Used as a vehicle of data across the binder IPC.
*
* Note we're not moving this class to the jobscheduler apex, because it's consumed by
* UsageStatsManager, which is not updatable anyway, so making this updatable isn't really
* beneficial.
* @hide
*/
public final class AppStandbyInfo implements Parcelable {

View File

@@ -97,6 +97,8 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
@@ -159,7 +161,7 @@ public class UsageStatsService extends SystemService implements
int mUsageSource;
/** Manages the standby state of apps. */
AppStandbyController mAppStandby;
AppStandbyInternal mAppStandby;
/** Manages app time limit observers */
AppTimeLimitController mAppTimeLimit;
@@ -208,7 +210,9 @@ public class UsageStatsService extends SystemService implements
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mHandler = new H(BackgroundThread.get().getLooper());
mAppStandby = new AppStandbyController(getContext(), BackgroundThread.get().getLooper());
mAppStandby = AppStandbyInternal.newAppStandbyController(
UsageStatsService.class.getClassLoader(), getContext(),
BackgroundThread.get().getLooper());
mAppTimeLimit = new AppTimeLimitController(
new AppTimeLimitController.TimeLimitCallbackListener() {
@@ -1010,7 +1014,7 @@ public class UsageStatsService extends SystemService implements
pw.println("Flushed stats to disk");
return;
} else if ("is-app-standby-enabled".equals(arg)) {
pw.println(mAppStandby.mAppIdleEnabled);
pw.println(mAppStandby.isAppIdleEnabled());
return;
} else if ("apptimelimit".equals(arg)) {
if (i + 1 >= args.length) {