From 3f7be62d316cf366fabca64b718f17982c8f436d Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Wed, 7 Feb 2018 10:49:01 -0800 Subject: [PATCH] Retry: JobScheduler to use UID active state for job exemption This is a second try for I134ac3d84a26309dab56ab6cbb271de626acdf7d. Apparently alarms are firing even before PHASE_SYSTEM_SERVICES_READY, so add more null checks. Test: Boot on taimen. Test: atest CtsAlarmManagerTestCases Test: atest CtsJobSchedulerTestCases Test: atest CtsBatterySavingTestCases Test: atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java Change-Id: I4b2a5af04e4d78c996e73da0621047da7a7bff39 --- core/java/android/app/ActivityManagerInternal.java | 5 ++ .../com/android/server/AlarmManagerService.java | 33 +++++--- ...AppStandbyTracker.java => AppStateTracker.java} | 80 +++++++++-------- .../com/android/server/DeviceIdleController.java | 8 +- .../core/java/com/android/server/StatLogger.java | 11 ++- .../android/server/am/ActivityManagerService.java | 8 ++ .../android/server/job/JobSchedulerService.java | 29 +++---- .../job/controllers/BackgroundJobsController.java | 38 ++++----- ...byTrackerTest.java => AppStateTrackerTest.java} | 99 +++++++++++++++------- 9 files changed, 192 insertions(+), 119 deletions(-) rename services/core/java/com/android/server/{ForceAppStandbyTracker.java => AppStateTracker.java} (95%) rename services/tests/servicestests/src/com/android/server/{ForceAppStandbyTrackerTest.java => AppStateTrackerTest.java} (93%) diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 5ee7edee9db7..4626cb274c0e 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -348,4 +348,9 @@ public abstract class ActivityManagerInternal { * Returns is the caller has the same uid as the Recents component */ public abstract boolean isCallerRecents(int callingUid); + + /** + * Whether an UID is active or idle. + */ + public abstract boolean isUidActive(int uid); } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 17c617c095d8..355da2df87a9 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -98,7 +98,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.LocalLog; -import com.android.server.ForceAppStandbyTracker.Listener; +import com.android.internal.util.Preconditions; +import com.android.server.AppStateTracker.Listener; /** * Alarm manager implementaion. @@ -249,7 +250,7 @@ class AlarmManagerService extends SystemService { private final SparseArray mHandlerSparseAlarmClockArray = new SparseArray<>(); - private final ForceAppStandbyTracker mForceAppStandbyTracker; + private AppStateTracker mAppStateTracker; private boolean mAppStandbyParole; private ArrayMap, Long> mLastAlarmDeliveredForPackage = new ArrayMap<>(); @@ -707,9 +708,6 @@ class AlarmManagerService extends SystemService { super(context); mConstants = new Constants(mHandler); - mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context); - mForceAppStandbyTracker.addListener(mForceAppStandbyListener); - publishLocalService(AlarmManagerInternal.class, new LocalService()); } @@ -1329,13 +1327,15 @@ class AlarmManagerService extends SystemService { @Override public void onBootPhase(int phase) { if (phase == PHASE_SYSTEM_SERVICES_READY) { - mForceAppStandbyTracker.start(); mConstants.start(getContext().getContentResolver()); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); mLocalDeviceIdleController = LocalServices.getService(DeviceIdleController.LocalService.class); mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class); mUsageStatsManagerInternal.addAppIdleStateChangeListener(new AppStandbyTracker()); + + mAppStateTracker = LocalServices.getService(AppStateTracker.class); + mAppStateTracker.addListener(mForceAppStandbyListener); } } @@ -1729,7 +1729,8 @@ class AlarmManagerService extends SystemService { // timing restrictions. } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID || callingUid == mSystemUiUid - || mForceAppStandbyTracker.isUidPowerSaveWhitelisted(callingUid))) { + || (mAppStateTracker != null + && mAppStateTracker.isUidPowerSaveWhitelisted(callingUid)))) { flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED; flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE; } @@ -1812,8 +1813,10 @@ class AlarmManagerService extends SystemService { mConstants.dump(pw); pw.println(); - mForceAppStandbyTracker.dump(pw, " "); - pw.println(); + if (mAppStateTracker != null) { + mAppStateTracker.dump(pw, " "); + pw.println(); + } pw.println(" App Standby Parole: " + mAppStandbyParole); pw.println(); @@ -2161,8 +2164,10 @@ class AlarmManagerService extends SystemService { mConstants.dumpProto(proto, AlarmManagerServiceProto.SETTINGS); - mForceAppStandbyTracker.dumpProto(proto, - AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER); + if (mAppStateTracker != null) { + mAppStateTracker.dumpProto(proto, + AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER); + } proto.write(AlarmManagerServiceProto.IS_INTERACTIVE, mInteractive); if (!mInteractive) { @@ -2942,7 +2947,7 @@ class AlarmManagerService extends SystemService { } final String sourcePackage = alarm.sourcePackage; final int sourceUid = alarm.creatorUid; - return mForceAppStandbyTracker.areAlarmsRestricted(sourceUid, sourcePackage, + return mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage, allowWhileIdle); } @@ -2955,7 +2960,7 @@ class AlarmManagerService extends SystemService { private long getWhileIdleMinIntervalLocked(int uid) { final boolean dozing = mPendingIdleUntil != null; - final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled(); + final boolean ebs = mAppStateTracker.isForceAllAppsStandbyEnabled(); if (!dozing && !ebs) { return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME; } @@ -4133,7 +4138,7 @@ class AlarmManagerService extends SystemService { if (allowWhileIdle) { // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm. mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED); - if (mForceAppStandbyTracker.isUidInForeground(alarm.creatorUid)) { + if (mAppStateTracker.isUidInForeground(alarm.creatorUid)) { mUseAllowWhileIdleShortTime.put(alarm.creatorUid, true); } else { mUseAllowWhileIdleShortTime.put(alarm.creatorUid, false); diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/AppStateTracker.java similarity index 95% rename from services/core/java/com/android/server/ForceAppStandbyTracker.java rename to services/core/java/com/android/server/AppStateTracker.java index 100680df637d..51dff56d3c11 100644 --- a/services/core/java/com/android/server/ForceAppStandbyTracker.java +++ b/services/core/java/com/android/server/AppStateTracker.java @@ -54,7 +54,6 @@ import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; -import com.android.server.DeviceIdleController.LocalService; import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage; import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages; @@ -73,14 +72,14 @@ import java.util.List; * TODO: Make it a LocalService. * * Test: - atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java + atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java */ -public class ForceAppStandbyTracker { +public class AppStateTracker { private static final String TAG = "ForceAppStandbyTracker"; private static final boolean DEBUG = true; - @GuardedBy("ForceAppStandbyTracker.class") - private static ForceAppStandbyTracker sInstance; + @GuardedBy("AppStateTracker.class") + private static AppStateTracker sInstance; private final Object mLock = new Object(); private final Context mContext; @@ -89,6 +88,7 @@ public class ForceAppStandbyTracker { static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND; IActivityManager mIActivityManager; + ActivityManagerInternal mActivityManagerInternal; AppOpsManager mAppOpsManager; IAppOpsService mAppOpsService; PowerManagerInternal mPowerManagerInternal; @@ -172,6 +172,9 @@ public class ForceAppStandbyTracker { int EXEMPT_CHANGED = 6; int FORCE_ALL_CHANGED = 7; int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8; + + int IS_UID_ACTIVE_CACHED = 9; + int IS_UID_ACTIVE_RAW = 10; } private final StatLogger mStatLogger = new StatLogger(new String[] { @@ -184,6 +187,9 @@ public class ForceAppStandbyTracker { "EXEMPT_CHANGED", "FORCE_ALL_CHANGED", "FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED", + + "IS_UID_ACTIVE_CACHED", + "IS_UID_ACTIVE_RAW", }); @VisibleForTesting @@ -249,7 +255,7 @@ public class ForceAppStandbyTracker { /** * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package. */ - private void onRunAnyAppOpsChanged(ForceAppStandbyTracker sender, + private void onRunAnyAppOpsChanged(AppStateTracker sender, int uid, @NonNull String packageName) { updateJobsForUidPackage(uid, packageName); @@ -264,14 +270,14 @@ public class ForceAppStandbyTracker { /** * This is called when the foreground state changed for a UID. */ - private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) { + private void onUidForegroundStateChanged(AppStateTracker sender, int uid) { onUidForeground(uid, sender.isUidInForeground(uid)); } /** * This is called when the active/idle state changed for a UID. */ - private void onUidActiveStateChanged(ForceAppStandbyTracker sender, int uid) { + private void onUidActiveStateChanged(AppStateTracker sender, int uid) { updateJobsForUid(uid); if (sender.isUidActive(uid)) { @@ -282,7 +288,7 @@ public class ForceAppStandbyTracker { /** * This is called when an app-id(s) is removed from the power save whitelist. */ - private void onPowerSaveUnwhitelisted(ForceAppStandbyTracker sender) { + private void onPowerSaveUnwhitelisted(AppStateTracker sender) { updateAllJobs(); unblockAllUnrestrictedAlarms(); } @@ -291,14 +297,14 @@ public class ForceAppStandbyTracker { * This is called when the power save whitelist changes, excluding the * {@link #onPowerSaveUnwhitelisted} case. */ - private void onPowerSaveWhitelistedChanged(ForceAppStandbyTracker sender) { + private void onPowerSaveWhitelistedChanged(AppStateTracker sender) { updateAllJobs(); } /** * This is called when the temp whitelist changes. */ - private void onTempPowerSaveWhitelistChanged(ForceAppStandbyTracker sender) { + private void onTempPowerSaveWhitelistChanged(AppStateTracker sender) { // TODO This case happens rather frequently; consider optimizing and update jobs // only for affected app-ids. @@ -311,7 +317,7 @@ public class ForceAppStandbyTracker { /** * This is called when the EXEMPT bucket is updated. */ - private void onExemptChanged(ForceAppStandbyTracker sender) { + private void onExemptChanged(AppStateTracker sender) { // This doesn't happen very often, so just re-evaluate all jobs / alarms. updateAllJobs(); unblockAllUnrestrictedAlarms(); @@ -320,7 +326,7 @@ public class ForceAppStandbyTracker { /** * This is called when the global "force all apps standby" flag changes. */ - private void onForceAllAppsStandbyChanged(ForceAppStandbyTracker sender) { + private void onForceAllAppsStandbyChanged(AppStateTracker sender) { updateAllJobs(); if (!sender.isForceAllAppsStandbyEnabled()) { @@ -377,30 +383,15 @@ public class ForceAppStandbyTracker { } } - @VisibleForTesting - ForceAppStandbyTracker(Context context, Looper looper) { + public AppStateTracker(Context context, Looper looper) { mContext = context; mHandler = new MyHandler(looper); } - private ForceAppStandbyTracker(Context context) { - this(context, FgThread.get().getLooper()); - } - - /** - * Get the singleton instance. - */ - public static synchronized ForceAppStandbyTracker getInstance(Context context) { - if (sInstance == null) { - sInstance = new ForceAppStandbyTracker(context); - } - return sInstance; - } - /** * Call it when the system is ready. */ - public void start() { + public void onSystemServicesReady() { synchronized (mLock) { if (mStarted) { return; @@ -408,6 +399,7 @@ public class ForceAppStandbyTracker { mStarted = true; mIActivityManager = Preconditions.checkNotNull(injectIActivityManager()); + mActivityManagerInternal = Preconditions.checkNotNull(injectActivityManagerInternal()); mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager()); mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService()); mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal()); @@ -475,6 +467,11 @@ public class ForceAppStandbyTracker { } @VisibleForTesting + ActivityManagerInternal injectActivityManagerInternal() { + return LocalServices.getService(ActivityManagerInternal.class); + } + + @VisibleForTesting PowerManagerInternal injectPowerManagerInternal() { return LocalServices.getService(PowerManagerInternal.class); } @@ -799,7 +796,7 @@ public class ForceAppStandbyTracker { return; } } - final ForceAppStandbyTracker sender = ForceAppStandbyTracker.this; + final AppStateTracker sender = AppStateTracker.this; long start = mStatLogger.getTime(); switch (msg.what) { @@ -1089,11 +1086,11 @@ public class ForceAppStandbyTracker { } /** - * @return whether a UID is in active or not. + * @return whether a UID is in active or not *based on cached information.* * * Note this information is based on the UID proc state callback, meaning it's updated * asynchronously and may subtly be stale. If the fresh data is needed, use - * {@link ActivityManagerInternal#getUidProcessState} instead. + * {@link #isUidActiveSynced} instead. */ public boolean isUidActive(int uid) { if (UserHandle.isCore(uid)) { @@ -1105,6 +1102,23 @@ public class ForceAppStandbyTracker { } /** + * @return whether a UID is in active or not *right now.* + * + * This gives the fresh information, but may access the activity manager so is slower. + */ + public boolean isUidActiveSynced(int uid) { + if (isUidActive(uid)) { // Use the cached one first. + return true; + } + final long start = mStatLogger.getTime(); + + final boolean ret = mActivityManagerInternal.isUidActive(uid); + mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start); + + return ret; + } + + /** * @return whether a UID is in the foreground or not. * * Note this information is based on the UID proc state callback, meaning it's updated diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 44974ffd3509..2b3c5852ac8b 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -82,6 +82,7 @@ import com.android.internal.os.AtomicFile; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.net.NetworkPolicyManagerInternal; @@ -128,6 +129,7 @@ public class DeviceIdleController extends SystemService private Intent mIdleIntent; private Intent mLightIdleIntent; private AnyMotionDetector mAnyMotionDetector; + private final AppStateTracker mAppStateTracker; private boolean mLightEnabled; private boolean mDeepEnabled; private boolean mForceIdle; @@ -1371,6 +1373,8 @@ public class DeviceIdleController extends SystemService super(context); mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml")); mHandler = new MyHandler(BackgroundThread.getHandler().getLooper()); + mAppStateTracker = new AppStateTracker(context, FgThread.get().getLooper()); + LocalServices.addService(AppStateTracker.class, mAppStateTracker); } boolean isAppOnWhitelistInternal(int appid) { @@ -1501,6 +1505,8 @@ public class DeviceIdleController extends SystemService (PowerManager) getContext().getSystemService(Context.POWER_SERVICE), mHandler, mSensorManager, this, angleThreshold); + mAppStateTracker.onSystemServicesReady(); + mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); @@ -2615,7 +2621,7 @@ public class DeviceIdleController extends SystemService } private void passWhiteListToForceAppStandbyTrackerLocked() { - ForceAppStandbyTracker.getInstance(getContext()).setPowerSaveWhitelistAppIds( + mAppStateTracker.setPowerSaveWhitelistAppIds( mPowerSaveWhitelistExceptIdleAppIdArray, mTempWhitelistAppIdArray); } diff --git a/services/core/java/com/android/server/StatLogger.java b/services/core/java/com/android/server/StatLogger.java index f2117314df00..0e6f5e2338c7 100644 --- a/services/core/java/com/android/server/StatLogger.java +++ b/services/core/java/com/android/server/StatLogger.java @@ -17,6 +17,7 @@ package com.android.server; import android.os.SystemClock; +import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; @@ -33,6 +34,8 @@ import java.io.PrintWriter; * @hide */ public class StatLogger { + private static final String TAG = "StatLogger"; + private final Object mLock = new Object(); private final int SIZE; @@ -66,8 +69,12 @@ public class StatLogger { */ public void logDurationStat(int eventId, long start) { synchronized (mLock) { - mCountStats[eventId]++; - mDurationStats[eventId] += (getTime() - start); + if (eventId >= 0 && eventId < SIZE) { + mCountStats[eventId]++; + mDurationStats[eventId] += (getTime() - start); + } else { + Slog.wtf(TAG, "Invalid event ID: " + eventId); + } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a6c4fc952839..9db4e2b4e4c2 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -25863,6 +25863,14 @@ public class ActivityManagerService extends IActivityManager.Stub public boolean isCallerRecents(int callingUid) { return getRecentTasks().isCallerRecents(callingUid); } + + @Override + public boolean isUidActive(int uid) { + synchronized (ActivityManagerService.this) { + final UidRecord uidRec = mActiveUids.get(uid); + return (uidRec != null) && !uidRec.idle; + } + } } /** diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 401c05e80307..47a4fb24201c 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -40,7 +40,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.Intent.UriFlags; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; @@ -79,7 +78,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.DeviceIdleController; import com.android.server.FgThread; -import com.android.server.ForceAppStandbyTracker; +import com.android.server.AppStateTracker; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob; import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob; @@ -184,7 +183,7 @@ public final class JobSchedulerService extends com.android.server.SystemService ActivityManagerInternal mActivityManagerInternal; IBatteryStats mBatteryStats; DeviceIdleController.LocalService mLocalDeviceIdleController; - final ForceAppStandbyTracker mForceAppStandbyTracker; + AppStateTracker mAppStateTracker; /** * Set to true once we are allowed to run third party apps. @@ -787,20 +786,13 @@ public final class JobSchedulerService extends com.android.server.SystemService } /** - * Return whether an UID is in the foreground or not. + * Return whether an UID is active or idle. */ - private boolean isUidInForeground(int uid) { - synchronized (mLock) { - if (mUidPriorityOverride.get(uid, 0) > 0) { - return true; - } - } - // Note UID observer may not be called in time, so we always check with the AM. - return mActivityManagerInternal.getUidProcessState(uid) - <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; + private boolean isUidActive(int uid) { + return mAppStateTracker.isUidActiveSynced(uid); } - private final Predicate mIsUidInForegroundPredicate = this::isUidInForeground; + private final Predicate mIsUidActivePredicate = this::isUidActive; public int scheduleAsPackage(JobInfo job, JobWorkItem work, int uId, String packageName, int userId, String tag) { @@ -826,7 +818,7 @@ public final class JobSchedulerService extends com.android.server.SystemService // If any of work item is enqueued when the source is in the foreground, // exempt the entire job. - toCancel.maybeAddForegroundExemption(mIsUidInForegroundPredicate); + toCancel.maybeAddForegroundExemption(mIsUidActivePredicate); return JobScheduler.RESULT_SUCCESS; } @@ -838,7 +830,7 @@ public final class JobSchedulerService extends com.android.server.SystemService // Note if it's a sync job, this method is called on the handler so it's not exactly // the state when requestSync() was called, but that should be fine because of the // 1 minute foreground grace period. - jobStatus.maybeAddForegroundExemption(mIsUidInForegroundPredicate); + jobStatus.maybeAddForegroundExemption(mIsUidActivePredicate); if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString()); // Jobs on behalf of others don't apply to the per-app job cap @@ -1123,8 +1115,6 @@ public final class JobSchedulerService extends com.android.server.SystemService mDeviceIdleJobsController = DeviceIdleJobsController.get(this); mControllers.add(mDeviceIdleJobsController); - mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context); - // If the job store determined that it can't yet reschedule persisted jobs, // we need to start watching the clock. if (!mJobs.jobTimesInflatedValid()) { @@ -1185,7 +1175,8 @@ public final class JobSchedulerService extends com.android.server.SystemService if (PHASE_SYSTEM_SERVICES_READY == phase) { mConstants.start(getContext().getContentResolver()); - mForceAppStandbyTracker.start(); + mAppStateTracker = Preconditions.checkNotNull( + LocalServices.getService(AppStateTracker.class)); // Register br for package removals and user removals. final IntentFilter filter = new IntentFilter(); diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java index 5eb77000a4f1..e8057fbd4150 100644 --- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java +++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java @@ -22,8 +22,10 @@ import android.os.UserHandle; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import com.android.server.ForceAppStandbyTracker; -import com.android.server.ForceAppStandbyTracker.Listener; +import com.android.internal.util.Preconditions; +import com.android.server.AppStateTracker; +import com.android.server.AppStateTracker.Listener; +import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.JobStore; import com.android.server.job.StateControllerProto; @@ -42,8 +44,7 @@ public final class BackgroundJobsController extends StateController { private final JobSchedulerService mJobSchedulerService; - private final ForceAppStandbyTracker mForceAppStandbyTracker; - + private final AppStateTracker mAppStateTracker; public static BackgroundJobsController get(JobSchedulerService service) { synchronized (sCreationLock) { @@ -59,10 +60,9 @@ public final class BackgroundJobsController extends StateController { super(service, context, lock); mJobSchedulerService = service; - mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context); - - mForceAppStandbyTracker.addListener(mForceAppStandbyListener); - mForceAppStandbyTracker.start(); + mAppStateTracker = Preconditions.checkNotNull( + LocalServices.getService(AppStateTracker.class)); + mAppStateTracker.addListener(mForceAppStandbyListener); } @Override @@ -79,7 +79,7 @@ public final class BackgroundJobsController extends StateController { public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) { pw.println("BackgroundJobsController"); - mForceAppStandbyTracker.dump(pw, ""); + mAppStateTracker.dump(pw, ""); pw.println("Job state:"); mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> { @@ -92,16 +92,16 @@ public final class BackgroundJobsController extends StateController { jobStatus.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, uid); - pw.print(mForceAppStandbyTracker.isUidActive(uid) ? " active" : " idle"); - if (mForceAppStandbyTracker.isUidPowerSaveWhitelisted(uid) || - mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(uid)) { + pw.print(mAppStateTracker.isUidActive(uid) ? " active" : " idle"); + if (mAppStateTracker.isUidPowerSaveWhitelisted(uid) || + mAppStateTracker.isUidTempPowerSaveWhitelisted(uid)) { pw.print(", whitelisted"); } pw.print(": "); pw.print(sourcePkg); pw.print(" [RUN_ANY_IN_BACKGROUND "); - pw.print(mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(uid, sourcePkg) + pw.print(mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, sourcePkg) ? "allowed]" : "disallowed]"); if ((jobStatus.satisfiedConstraints @@ -118,7 +118,7 @@ public final class BackgroundJobsController extends StateController { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.BACKGROUND); - mForceAppStandbyTracker.dumpProto(proto, + mAppStateTracker.dumpProto(proto, StateControllerProto.BackgroundJobsController.FORCE_APP_STANDBY_TRACKER); mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> { @@ -136,14 +136,14 @@ public final class BackgroundJobsController extends StateController { proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg); proto.write(TrackedJob.IS_IN_FOREGROUND, - mForceAppStandbyTracker.isUidActive(sourceUid)); + mAppStateTracker.isUidActive(sourceUid)); proto.write(TrackedJob.IS_WHITELISTED, - mForceAppStandbyTracker.isUidPowerSaveWhitelisted(sourceUid) || - mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(sourceUid)); + mAppStateTracker.isUidPowerSaveWhitelisted(sourceUid) || + mAppStateTracker.isUidTempPowerSaveWhitelisted(sourceUid)); proto.write( TrackedJob.CAN_RUN_ANY_IN_BACKGROUND, - mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed( + mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed( sourceUid, sourcePkg)); proto.write( @@ -197,7 +197,7 @@ public final class BackgroundJobsController extends StateController { final int uid = jobStatus.getSourceUid(); final String packageName = jobStatus.getSourcePackageName(); - final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName, + final boolean canRun = !mAppStateTracker.areJobsRestricted(uid, packageName, (jobStatus.getInternalFlags() & JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0); diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java similarity index 93% rename from services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java rename to services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java index a499472d197f..90db2a328c6f 100644 --- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java @@ -15,7 +15,7 @@ */ package com.android.server; -import static com.android.server.ForceAppStandbyTracker.TARGET_OP; +import static com.android.server.AppStateTracker.TARGET_OP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -33,6 +33,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.PackageOps; @@ -63,7 +64,7 @@ import android.util.Pair; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; -import com.android.server.ForceAppStandbyTracker.Listener; +import com.android.server.AppStateTracker.Listener; import org.junit.Before; import org.junit.Test; @@ -82,17 +83,17 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; /** - * Tests for {@link ForceAppStandbyTracker} + * Tests for {@link AppStateTracker} * * Run with: - atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java + atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java */ @SmallTest @RunWith(AndroidJUnit4.class) -public class ForceAppStandbyTrackerTest { +public class AppStateTrackerTest { - private class ForceAppStandbyTrackerTestable extends ForceAppStandbyTracker { - ForceAppStandbyTrackerTestable() { + private class AppStateTrackerTestable extends AppStateTracker { + AppStateTrackerTestable() { super(mMockContext, Looper.getMainLooper()); } @@ -112,6 +113,11 @@ public class ForceAppStandbyTrackerTest { } @Override + ActivityManagerInternal injectActivityManagerInternal() { + return mMockIActivityManagerInternal; + } + + @Override PowerManagerInternal injectPowerManagerInternal() { return mMockPowerManagerInternal; } @@ -152,6 +158,9 @@ public class ForceAppStandbyTrackerTest { private IActivityManager mMockIActivityManager; @Mock + private ActivityManagerInternal mMockIActivityManagerInternal; + + @Mock private AppOpsManager mMockAppOpsManager; @Mock @@ -195,7 +204,7 @@ public class ForceAppStandbyTrackerTest { return new PowerSaveState.Builder().setBatterySaverEnabled(mPowerSaveMode).build(); } - private ForceAppStandbyTrackerTestable newInstance() throws Exception { + private AppStateTrackerTestable newInstance() throws Exception { MockitoAnnotations.initMocks(this); when(mMockIAppOpsService.checkOperation(eq(TARGET_OP), anyInt(), anyString())) @@ -205,12 +214,12 @@ public class ForceAppStandbyTrackerTest { AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED; }); - final ForceAppStandbyTrackerTestable instance = new ForceAppStandbyTrackerTestable(); + final AppStateTrackerTestable instance = new AppStateTrackerTestable(); return instance; } - private void callStart(ForceAppStandbyTrackerTestable instance) throws RemoteException { + private void callStart(AppStateTrackerTestable instance) throws RemoteException { // Set up functions that start() calls. when(mMockPowerManagerInternal.getLowPowerState(eq(ServiceType.FORCE_ALL_APPS_STANDBY))) @@ -223,7 +232,7 @@ public class ForceAppStandbyTrackerTest { when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); // Call start. - instance.start(); + instance.onSystemServicesReady(); // Capture the listeners. ArgumentCaptor uidObserverArgumentCaptor = @@ -287,7 +296,7 @@ public class ForceAppStandbyTrackerTest { private static final int JOBS_ONLY = 1 << 1; private static final int JOBS_AND_ALARMS = ALARMS_ONLY | JOBS_ONLY; - private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName, + private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName, int restrictionTypes, boolean exemptFromBatterySaver) { assertEquals(((restrictionTypes & JOBS_ONLY) != 0), instance.areJobsRestricted(uid, packageName, exemptFromBatterySaver)); @@ -295,13 +304,13 @@ public class ForceAppStandbyTrackerTest { instance.areAlarmsRestricted(uid, packageName, exemptFromBatterySaver)); } - private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName, + private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName, int restrictionTypes) { areRestricted(instance, uid, packageName, restrictionTypes, /*exemptFromBatterySaver=*/ false); } - private void areRestrictedWithExemption(ForceAppStandbyTrackerTestable instance, + private void areRestrictedWithExemption(AppStateTrackerTestable instance, int uid, String packageName, int restrictionTypes) { areRestricted(instance, uid, packageName, restrictionTypes, /*exemptFromBatterySaver=*/ true); @@ -309,7 +318,7 @@ public class ForceAppStandbyTrackerTest { @Test public void testAll() throws Exception { - final ForceAppStandbyTrackerTestable instance = newInstance(); + final AppStateTrackerTestable instance = newInstance(); callStart(instance); assertFalse(instance.isForceAllAppsStandbyEnabled()); @@ -466,7 +475,7 @@ public class ForceAppStandbyTrackerTest { @Test public void testUidStateForeground() throws Exception { - final ForceAppStandbyTrackerTestable instance = newInstance(); + final AppStateTrackerTestable instance = newInstance(); callStart(instance); mIUidObserver.onUidActive(UID_1); @@ -476,6 +485,10 @@ public class ForceAppStandbyTrackerTest { assertFalse(instance.isUidActive(UID_2)); assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + assertTrue(instance.isUidActiveSynced(UID_1)); + assertFalse(instance.isUidActiveSynced(UID_2)); + assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID)); + assertFalse(instance.isUidInForeground(UID_1)); assertFalse(instance.isUidInForeground(UID_2)); assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); @@ -489,6 +502,10 @@ public class ForceAppStandbyTrackerTest { assertFalse(instance.isUidActive(UID_2)); assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + assertTrue(instance.isUidActiveSynced(UID_1)); + assertFalse(instance.isUidActiveSynced(UID_2)); + assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID)); + assertFalse(instance.isUidInForeground(UID_1)); assertTrue(instance.isUidInForeground(UID_2)); assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); @@ -548,14 +565,34 @@ public class ForceAppStandbyTrackerTest { assertFalse(instance.isUidActive(UID_2)); assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + assertFalse(instance.isUidActiveSynced(UID_1)); + assertFalse(instance.isUidActiveSynced(UID_2)); + assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID)); + assertFalse(instance.isUidInForeground(UID_1)); assertFalse(instance.isUidInForeground(UID_2)); assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); + + // The result from AMI.isUidActive() only affects isUidActiveSynced(). + when(mMockIActivityManagerInternal.isUidActive(anyInt())).thenReturn(true); + + assertFalse(instance.isUidActive(UID_1)); + assertFalse(instance.isUidActive(UID_2)); + assertTrue(instance.isUidActive(Process.SYSTEM_UID)); + + assertTrue(instance.isUidActiveSynced(UID_1)); + assertTrue(instance.isUidActiveSynced(UID_2)); + assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID)); + + assertFalse(instance.isUidInForeground(UID_1)); + assertFalse(instance.isUidInForeground(UID_2)); + assertTrue(instance.isUidInForeground(Process.SYSTEM_UID)); + } @Test public void testExempt() throws Exception { - final ForceAppStandbyTrackerTestable instance = newInstance(); + final AppStateTrackerTestable instance = newInstance(); callStart(instance); assertFalse(instance.isForceAllAppsStandbyEnabled()); @@ -621,7 +658,7 @@ public class ForceAppStandbyTrackerTest { } public void loadPersistedAppOps() throws Exception { - final ForceAppStandbyTrackerTestable instance = newInstance(); + final AppStateTrackerTestable instance = newInstance(); final List ops = new ArrayList<>(); @@ -631,7 +668,7 @@ public class ForceAppStandbyTrackerTest { AppOpsManager.OP_ACCESS_NOTIFICATIONS, AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null)); entries.add(new AppOpsManager.OpEntry( - ForceAppStandbyTracker.TARGET_OP, + AppStateTracker.TARGET_OP, AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null)); ops.add(new PackageOps(PACKAGE_1, UID_1, entries)); @@ -639,7 +676,7 @@ public class ForceAppStandbyTrackerTest { //-------------------------------------------------- entries = new ArrayList<>(); entries.add(new AppOpsManager.OpEntry( - ForceAppStandbyTracker.TARGET_OP, + AppStateTracker.TARGET_OP, AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null)); ops.add(new PackageOps(PACKAGE_2, UID_2, entries)); @@ -647,7 +684,7 @@ public class ForceAppStandbyTrackerTest { //-------------------------------------------------- entries = new ArrayList<>(); entries.add(new AppOpsManager.OpEntry( - ForceAppStandbyTracker.TARGET_OP, + AppStateTracker.TARGET_OP, AppOpsManager.MODE_ALLOWED, 0, 0, 0, 0, null)); ops.add(new PackageOps(PACKAGE_1, UID_10_1, entries)); @@ -655,7 +692,7 @@ public class ForceAppStandbyTrackerTest { //-------------------------------------------------- entries = new ArrayList<>(); entries.add(new AppOpsManager.OpEntry( - ForceAppStandbyTracker.TARGET_OP, + AppStateTracker.TARGET_OP, AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null)); entries.add(new AppOpsManager.OpEntry( AppOpsManager.OP_ACCESS_NOTIFICATIONS, @@ -688,10 +725,10 @@ public class ForceAppStandbyTrackerTest { @Test public void testPowerSaveListener() throws Exception { - final ForceAppStandbyTrackerTestable instance = newInstance(); + final AppStateTrackerTestable instance = newInstance(); callStart(instance); - ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class); + AppStateTracker.Listener l = mock(AppStateTracker.Listener.class); instance.addListener(l); // Power save on. @@ -731,10 +768,10 @@ public class ForceAppStandbyTrackerTest { @Test public void testAllListeners() throws Exception { - final ForceAppStandbyTrackerTestable instance = newInstance(); + final AppStateTrackerTestable instance = newInstance(); callStart(instance); - ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class); + AppStateTracker.Listener l = mock(AppStateTracker.Listener.class); instance.addListener(l); // ------------------------------------------------------------------------- @@ -1042,7 +1079,7 @@ public class ForceAppStandbyTrackerTest { @Test public void testUserRemoved() throws Exception { - final ForceAppStandbyTrackerTestable instance = newInstance(); + final AppStateTrackerTestable instance = newInstance(); callStart(instance); mIUidObserver.onUidActive(UID_1); @@ -1077,7 +1114,7 @@ public class ForceAppStandbyTrackerTest { // This is a small battery device mIsSmallBatteryDevice = true; - final ForceAppStandbyTrackerTestable instance = newInstance(); + final AppStateTrackerTestable instance = newInstance(); callStart(instance); assertFalse(instance.isForceAllAppsStandbyEnabled()); @@ -1103,7 +1140,7 @@ public class ForceAppStandbyTrackerTest { // Not a small battery device, so plugged in status should not affect forced app standby mIsSmallBatteryDevice = false; - final ForceAppStandbyTrackerTestable instance = newInstance(); + final AppStateTrackerTestable instance = newInstance(); callStart(instance); assertFalse(instance.isForceAllAppsStandbyEnabled()); @@ -1152,7 +1189,7 @@ public class ForceAppStandbyTrackerTest { private void checkAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray, boolean expected) { assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray), - expected, ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(prevArray, newArray)); + expected, AppStateTracker.isAnyAppIdUnwhitelisted(prevArray, newArray)); // Also test isAnyAppIdUnwhitelistedSlow. assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray), @@ -1184,7 +1221,7 @@ public class ForceAppStandbyTrackerTest { final int[] array2 = makeRandomArray(); final boolean expected = isAnyAppIdUnwhitelistedSlow(array1, array2); - final boolean actual = ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(array1, array2); + final boolean actual = AppStateTracker.isAnyAppIdUnwhitelisted(array1, array2); assertEquals("Input: " + Arrays.toString(array1) + " " + Arrays.toString(array2), expected, actual); -- 2.11.0