Loading apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +8 −0 Original line number Diff line number Diff line Loading @@ -793,6 +793,13 @@ public class JobSchedulerService extends com.android.server.SystemService mDebuggableApps.remove(pkgName); } } } else if (Intent.ACTION_USER_ADDED.equals(action)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); synchronized (mLock) { for (int c = 0; c < mControllers.size(); ++c) { mControllers.get(c).onUserAddedLocked(userId); } } } else if (Intent.ACTION_USER_REMOVED.equals(action)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); if (DEBUG) { Loading Loading @@ -1454,6 +1461,7 @@ public class JobSchedulerService extends com.android.server.SystemService getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, filter, null, null); final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); userFilter.addAction(Intent.ACTION_USER_ADDED); getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, userFilter, null, null); try { Loading apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +97 −31 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; import static com.android.server.job.JobSchedulerService.WORKING_INDEX; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; Loading @@ -42,7 +43,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManagerInternal; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.Handler; Loading Loading @@ -118,6 +121,10 @@ public final class QuotaController extends StateController { private static final String ALARM_TAG_CLEANUP = "*job.cleanup*"; private static final String ALARM_TAG_QUOTA_CHECK = "*job.quota_check*"; private static final int SYSTEM_APP_CHECK_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.GET_PERMISSIONS | PackageManager.MATCH_KNOWN_PACKAGES; /** * Standardize the output of userId-packageName combo. */ Loading Loading @@ -526,7 +533,9 @@ public final class QuotaController extends StateController { QcConstants.DEFAULT_EJ_LIMIT_RESTRICTED_MS }; private long mEjLimitSpecialAdditionMs = QcConstants.DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS; private long mEjLimitAdditionInstallerMs = QcConstants.DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS; private long mEjLimitAdditionSpecialMs = QcConstants.DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS; /** * The period of time used to calculate expedited job sessions. Apps can only have expedited job Loading Loading @@ -560,9 +569,11 @@ public final class QuotaController extends StateController { private long mEJGracePeriodTopAppMs = QcConstants.DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS; /** The package verifier app. */ @Nullable private String mPackageVerifier; /** * List of system apps with the {@link android.Manifest.permission#INSTALL_PACKAGES} permission * granted for each user. */ private final SparseSetArray<String> mSystemInstallers = new SparseSetArray<>(); /** An app has reached its quota. The message should contain a {@link Package} object. */ @VisibleForTesting Loading Loading @@ -627,11 +638,8 @@ public final class QuotaController extends StateController { @Override public void onSystemServicesReady() { String[] pkgNames = LocalServices.getService(PackageManagerInternal.class) .getKnownPackageNames( PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM); synchronized (mLock) { mPackageVerifier = ArrayUtils.firstOrNull(pkgNames); cacheInstallerPackagesLocked(UserHandle.USER_SYSTEM); } } Loading Loading @@ -730,6 +738,11 @@ public final class QuotaController extends StateController { mTopAppGraceCache.delete(uid); } @Override public void onUserAddedLocked(int userId) { cacheInstallerPackagesLocked(userId); } @Override public void onUserRemovedLocked(int userId) { mTrackedJobs.delete(userId); Loading @@ -741,6 +754,7 @@ public final class QuotaController extends StateController { mExecutionStatsCache.delete(userId); mEJStats.delete(userId); mUidToPackageCache.clear(); mSystemInstallers.remove(userId); } /** Drop all historical stats and stop tracking any active sessions for the specified app. */ Loading @@ -767,6 +781,22 @@ public final class QuotaController extends StateController { mEJStats.delete(userId, packageName); } private void cacheInstallerPackagesLocked(int userId) { final List<PackageInfo> packages = mContext.getPackageManager() .getInstalledPackagesAsUser(SYSTEM_APP_CHECK_FLAGS, userId); for (int i = packages.size() - 1; i >= 0; --i) { final PackageInfo pi = packages.get(i); final ApplicationInfo ai = pi.applicationInfo; final int idx = ArrayUtils.indexOf( pi.requestedPermissions, Manifest.permission.INSTALL_PACKAGES); if (idx >= 0 && ai != null && PackageManager.PERMISSION_GRANTED == mContext.checkPermission(Manifest.permission.INSTALL_PACKAGES, -1, ai.uid)) { mSystemInstallers.add(UserHandle.getUserId(ai.uid), pi.packageName); } } } private boolean isUidInForeground(int uid) { if (UserHandle.isCore(uid)) { return true; Loading Loading @@ -962,7 +992,8 @@ public final class QuotaController extends StateController { if (quota.getStandbyBucketLocked() == NEVER_INDEX) { return 0; } final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked()); final long limitMs = getEJLimitMsLocked(userId, packageName, quota.getStandbyBucketLocked()); long remainingMs = limitMs - quota.getTallyLocked(); // Stale sessions may still be factored into tally. Make sure they're removed. Loading Loading @@ -1000,10 +1031,11 @@ public final class QuotaController extends StateController { return remainingMs - timer.getCurrentDuration(sElapsedRealtimeClock.millis()); } private long getEJLimitMsLocked(@NonNull final String packageName, final int standbyBucket) { private long getEJLimitMsLocked(final int userId, @NonNull final String packageName, final int standbyBucket) { final long baseLimitMs = mEJLimitsMs[standbyBucket]; if (packageName.equals(mPackageVerifier)) { return baseLimitMs + mEjLimitSpecialAdditionMs; if (mSystemInstallers.contains(userId, packageName)) { return baseLimitMs + mEjLimitAdditionInstallerMs; } return baseLimitMs; } Loading Loading @@ -1116,7 +1148,8 @@ public final class QuotaController extends StateController { final long nowElapsed = sElapsedRealtimeClock.millis(); ShrinkableDebits quota = getEJDebitsLocked(userId, packageName); final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked()); final long limitMs = getEJLimitMsLocked(userId, packageName, quota.getStandbyBucketLocked()); final long startWindowElapsed = Math.max(0, nowElapsed - mEJLimitWindowSizeMs); long remainingDeadSpaceMs = remainingExecutionTimeMs; // Total time looked at where a session wouldn't be phasing out. Loading Loading @@ -1743,7 +1776,8 @@ public final class QuotaController extends StateController { inRegularQuotaTimeElapsed = inQuotaTimeElapsed; } if (remainingEJQuota <= 0) { final long limitMs = getEJLimitMsLocked(packageName, standbyBucket) - mQuotaBufferMs; final long limitMs = getEJLimitMsLocked(userId, packageName, standbyBucket) - mQuotaBufferMs; long sumMs = 0; final Timer ejTimer = mEJPkgTimers.get(userId, packageName); if (ejTimer != null && ejTimer.isActive()) { Loading Loading @@ -3029,8 +3063,11 @@ public final class QuotaController extends StateController { static final String KEY_EJ_LIMIT_RESTRICTED_MS = QC_CONSTANT_PREFIX + "ej_limit_restricted_ms"; @VisibleForTesting static final String KEY_EJ_LIMIT_SPECIAL_ADDITION_MS = QC_CONSTANT_PREFIX + "ej_limit_special_addition_ms"; static final String KEY_EJ_LIMIT_ADDITION_SPECIAL_MS = QC_CONSTANT_PREFIX + "ej_limit_addition_special_ms"; @VisibleForTesting static final String KEY_EJ_LIMIT_ADDITION_INSTALLER_MS = QC_CONSTANT_PREFIX + "ej_limit_addition_installer_ms"; @VisibleForTesting static final String KEY_EJ_WINDOW_SIZE_MS = QC_CONSTANT_PREFIX + "ej_window_size_ms"; Loading Loading @@ -3098,7 +3135,8 @@ public final class QuotaController extends StateController { private static final long DEFAULT_EJ_LIMIT_FREQUENT_MS = 10 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_LIMIT_RARE_MS = DEFAULT_EJ_LIMIT_FREQUENT_MS; private static final long DEFAULT_EJ_LIMIT_RESTRICTED_MS = 5 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS = 30 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS = 15 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS = 30 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_WINDOW_SIZE_MS = 24 * HOUR_IN_MILLIS; private static final long DEFAULT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS = 30 * SECOND_IN_MILLIS; private static final long DEFAULT_EJ_REWARD_TOP_APP_MS = 10 * SECOND_IN_MILLIS; Loading Loading @@ -3303,7 +3341,13 @@ public final class QuotaController extends StateController { /** * How much additional EJ quota special, critical apps should get. */ public long EJ_LIMIT_SPECIAL_ADDITION_MS = DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS; public long EJ_LIMIT_ADDITION_SPECIAL_MS = DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS; /** * How much additional EJ quota system installers (with the INSTALL_PACKAGES permission) * should get. */ public long EJ_LIMIT_ADDITION_INSTALLER_MS = DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS; /** * The period of time used to calculate expedited job sessions. Apps can only have expedited Loading Loading @@ -3369,7 +3413,8 @@ public final class QuotaController extends StateController { case KEY_EJ_LIMIT_FREQUENT_MS: case KEY_EJ_LIMIT_RARE_MS: case KEY_EJ_LIMIT_RESTRICTED_MS: case KEY_EJ_LIMIT_SPECIAL_ADDITION_MS: case KEY_EJ_LIMIT_ADDITION_SPECIAL_MS: case KEY_EJ_LIMIT_ADDITION_INSTALLER_MS: case KEY_EJ_WINDOW_SIZE_MS: updateEJLimitConstantsLocked(); break; Loading Loading @@ -3704,7 +3749,8 @@ public final class QuotaController extends StateController { DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_EJ_LIMIT_ACTIVE_MS, KEY_EJ_LIMIT_WORKING_MS, KEY_EJ_LIMIT_FREQUENT_MS, KEY_EJ_LIMIT_RARE_MS, KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, KEY_EJ_WINDOW_SIZE_MS); EJ_LIMIT_ACTIVE_MS = properties.getLong( KEY_EJ_LIMIT_ACTIVE_MS, DEFAULT_EJ_LIMIT_ACTIVE_MS); Loading @@ -3716,8 +3762,10 @@ public final class QuotaController extends StateController { KEY_EJ_LIMIT_RARE_MS, DEFAULT_EJ_LIMIT_RARE_MS); EJ_LIMIT_RESTRICTED_MS = properties.getLong( KEY_EJ_LIMIT_RESTRICTED_MS, DEFAULT_EJ_LIMIT_RESTRICTED_MS); EJ_LIMIT_SPECIAL_ADDITION_MS = properties.getLong( KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS); EJ_LIMIT_ADDITION_INSTALLER_MS = properties.getLong( KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS); EJ_LIMIT_ADDITION_SPECIAL_MS = properties.getLong( KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS); EJ_WINDOW_SIZE_MS = properties.getLong( KEY_EJ_WINDOW_SIZE_MS, DEFAULT_EJ_WINDOW_SIZE_MS); Loading Loading @@ -3763,11 +3811,17 @@ public final class QuotaController extends StateController { mEJLimitsMs[RESTRICTED_INDEX] = newRestrictedLimitMs; mShouldReevaluateConstraints = true; } // The addition must be in the range [0 minutes, window size - active limit]. long newSpecialAdditionMs = Math.max(0, Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_SPECIAL_ADDITION_MS)); if (mEjLimitSpecialAdditionMs != newSpecialAdditionMs) { mEjLimitSpecialAdditionMs = newSpecialAdditionMs; // The additions must be in the range [0 minutes, window size - active limit]. long newAdditionInstallerMs = Math.max(0, Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_ADDITION_INSTALLER_MS)); if (mEjLimitAdditionInstallerMs != newAdditionInstallerMs) { mEjLimitAdditionInstallerMs = newAdditionInstallerMs; mShouldReevaluateConstraints = true; } long newAdditionSpecialMs = Math.max(0, Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_ADDITION_SPECIAL_MS)); if (mEjLimitAdditionSpecialMs != newAdditionSpecialMs) { mEjLimitAdditionSpecialMs = newAdditionSpecialMs; mShouldReevaluateConstraints = true; } } Loading Loading @@ -3808,7 +3862,8 @@ public final class QuotaController extends StateController { pw.print(KEY_EJ_LIMIT_FREQUENT_MS, EJ_LIMIT_FREQUENT_MS).println(); pw.print(KEY_EJ_LIMIT_RARE_MS, EJ_LIMIT_RARE_MS).println(); pw.print(KEY_EJ_LIMIT_RESTRICTED_MS, EJ_LIMIT_RESTRICTED_MS).println(); pw.print(KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, EJ_LIMIT_SPECIAL_ADDITION_MS).println(); pw.print(KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, EJ_LIMIT_ADDITION_INSTALLER_MS).println(); pw.print(KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, EJ_LIMIT_ADDITION_SPECIAL_MS).println(); pw.print(KEY_EJ_WINDOW_SIZE_MS, EJ_WINDOW_SIZE_MS).println(); pw.print(KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, EJ_TOP_APP_TIME_CHUNK_SIZE_MS).println(); pw.print(KEY_EJ_REWARD_TOP_APP_MS, EJ_REWARD_TOP_APP_MS).println(); Loading Loading @@ -3945,8 +4000,13 @@ public final class QuotaController extends StateController { } @VisibleForTesting long getEjLimitSpecialAdditionMs() { return mEjLimitSpecialAdditionMs; long getEjLimitAdditionInstallerMs() { return mEjLimitAdditionInstallerMs; } @VisibleForTesting long getEjLimitAdditionSpecialMs() { return mEjLimitAdditionSpecialMs; } @VisibleForTesting Loading Loading @@ -4067,6 +4127,12 @@ public final class QuotaController extends StateController { pw.decreaseIndent(); pw.println(); pw.println("Special apps:"); pw.increaseIndent(); pw.print("System installers", mSystemInstallers.toString()); pw.decreaseIndent(); pw.println(); mTrackedJobs.forEach((jobs) -> { for (int j = 0; j < jobs.size(); j++) { final JobStatus js = jobs.valueAt(j); Loading apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java +4 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,10 @@ public abstract class StateController { public void onAppRemovedLocked(String packageName, int uid) { } /** Called when a user is added to the device. */ public void onUserAddedLocked(int userId) { } /** Called when a user is removed from the device. */ public void onUserRemovedLocked(int userId) { } Loading services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +31 −10 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.Manifest; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; Loading @@ -66,7 +67,10 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ServiceInfo; import android.os.BatteryManager; Loading Loading @@ -142,6 +146,8 @@ public class QuotaControllerTest { @Mock private JobSchedulerService mJobSchedulerService; @Mock private PackageManager mPackageManager; @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private PowerAllowlistInternal mPowerAllowlistInternal; Loading Loading @@ -201,6 +207,8 @@ public class QuotaControllerTest { -> mDeviceConfigPropertiesBuilder.build()) .when(() -> DeviceConfig.getProperties( eq(DeviceConfig.NAMESPACE_JOB_SCHEDULER), ArgumentMatchers.<String>any())); // Used in QuotaController.onSystemServicesReady when(mContext.getPackageManager()).thenReturn(mPackageManager); // Freeze the clocks at 24 hours after this moment in time. Several tests create sessions // in the past, and QuotaController sometimes floors values at 0, so if the test time Loading Loading @@ -2704,7 +2712,8 @@ public class QuotaControllerTest { setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 1 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 30 * MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 27 * MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 10 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, 10 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 12 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 10 * MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 87 * SECOND_IN_MILLIS); Loading Loading @@ -2745,7 +2754,8 @@ public class QuotaControllerTest { assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]); assertEquals(30 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]); assertEquals(27 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); assertEquals(10 * HOUR_IN_MILLIS, mQuotaController.getEjLimitSpecialAdditionMs()); assertEquals(7 * HOUR_IN_MILLIS, mQuotaController.getEjLimitAdditionInstallerMs()); assertEquals(10 * HOUR_IN_MILLIS, mQuotaController.getEjLimitAdditionSpecialMs()); assertEquals(12 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs()); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs()); assertEquals(87 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs()); Loading Loading @@ -2786,7 +2796,8 @@ public class QuotaControllerTest { setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, -1); Loading Loading @@ -2823,7 +2834,8 @@ public class QuotaControllerTest { assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]); assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs()); assertEquals(0, mQuotaController.getEjLimitAdditionInstallerMs()); assertEquals(0, mQuotaController.getEjLimitAdditionSpecialMs()); assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs()); assertEquals(1, mQuotaController.getEJTopAppTimeChunkSizeMs()); assertEquals(10 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs()); Loading Loading @@ -2858,7 +2870,8 @@ public class QuotaControllerTest { setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 25 * HOUR_IN_MILLIS); Loading @@ -2885,7 +2898,8 @@ public class QuotaControllerTest { assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs()); assertEquals(0, mQuotaController.getEjLimitAdditionInstallerMs()); assertEquals(0, mQuotaController.getEjLimitAdditionSpecialMs()); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs()); assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs()); assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardTopAppMs()); Loading Loading @@ -3957,9 +3971,16 @@ public class QuotaControllerTest { } @Test public void testGetRemainingEJExecutionTimeLocked_SpecialApp() { doReturn(new String[]{SOURCE_PACKAGE}).when(mPackageManagerInternal) .getKnownPackageNames(eq(PackageManagerInternal.PACKAGE_VERIFIER), anyInt()); public void testGetRemainingEJExecutionTimeLocked_Installer() { PackageInfo pi = new PackageInfo(); pi.packageName = SOURCE_PACKAGE; pi.requestedPermissions = new String[]{Manifest.permission.INSTALL_PACKAGES}; pi.requestedPermissionsFlags = new int[]{PackageInfo.REQUESTED_PERMISSION_GRANTED}; pi.applicationInfo = new ApplicationInfo(); pi.applicationInfo.uid = mSourceUid; doReturn(List.of(pi)).when(mPackageManager).getInstalledPackagesAsUser(anyInt(), anyInt()); doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkPermission( eq(Manifest.permission.INSTALL_PACKAGES), anyInt(), eq(mSourceUid)); mQuotaController.onSystemServicesReady(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); Loading @@ -3980,7 +4001,7 @@ public class QuotaControllerTest { setStandbyBucket(i); assertEquals("Got wrong remaining EJ execution time for bucket #" + i, i == NEVER_INDEX ? 0 : (limits[i] + mQuotaController.getEjLimitSpecialAdditionMs() : (limits[i] + mQuotaController.getEjLimitAdditionInstallerMs() - 5 * MINUTE_IN_MILLIS), mQuotaController.getRemainingEJExecutionTimeLocked( SOURCE_USER_ID, SOURCE_PACKAGE)); Loading Loading
apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +8 −0 Original line number Diff line number Diff line Loading @@ -793,6 +793,13 @@ public class JobSchedulerService extends com.android.server.SystemService mDebuggableApps.remove(pkgName); } } } else if (Intent.ACTION_USER_ADDED.equals(action)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); synchronized (mLock) { for (int c = 0; c < mControllers.size(); ++c) { mControllers.get(c).onUserAddedLocked(userId); } } } else if (Intent.ACTION_USER_REMOVED.equals(action)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); if (DEBUG) { Loading Loading @@ -1454,6 +1461,7 @@ public class JobSchedulerService extends com.android.server.SystemService getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, filter, null, null); final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED); userFilter.addAction(Intent.ACTION_USER_ADDED); getContext().registerReceiverAsUser( mBroadcastReceiver, UserHandle.ALL, userFilter, null, null); try { Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +97 −31 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; import static com.android.server.job.JobSchedulerService.WORKING_INDEX; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; Loading @@ -42,7 +43,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManagerInternal; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.Handler; Loading Loading @@ -118,6 +121,10 @@ public final class QuotaController extends StateController { private static final String ALARM_TAG_CLEANUP = "*job.cleanup*"; private static final String ALARM_TAG_QUOTA_CHECK = "*job.quota_check*"; private static final int SYSTEM_APP_CHECK_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.GET_PERMISSIONS | PackageManager.MATCH_KNOWN_PACKAGES; /** * Standardize the output of userId-packageName combo. */ Loading Loading @@ -526,7 +533,9 @@ public final class QuotaController extends StateController { QcConstants.DEFAULT_EJ_LIMIT_RESTRICTED_MS }; private long mEjLimitSpecialAdditionMs = QcConstants.DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS; private long mEjLimitAdditionInstallerMs = QcConstants.DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS; private long mEjLimitAdditionSpecialMs = QcConstants.DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS; /** * The period of time used to calculate expedited job sessions. Apps can only have expedited job Loading Loading @@ -560,9 +569,11 @@ public final class QuotaController extends StateController { private long mEJGracePeriodTopAppMs = QcConstants.DEFAULT_EJ_GRACE_PERIOD_TOP_APP_MS; /** The package verifier app. */ @Nullable private String mPackageVerifier; /** * List of system apps with the {@link android.Manifest.permission#INSTALL_PACKAGES} permission * granted for each user. */ private final SparseSetArray<String> mSystemInstallers = new SparseSetArray<>(); /** An app has reached its quota. The message should contain a {@link Package} object. */ @VisibleForTesting Loading Loading @@ -627,11 +638,8 @@ public final class QuotaController extends StateController { @Override public void onSystemServicesReady() { String[] pkgNames = LocalServices.getService(PackageManagerInternal.class) .getKnownPackageNames( PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM); synchronized (mLock) { mPackageVerifier = ArrayUtils.firstOrNull(pkgNames); cacheInstallerPackagesLocked(UserHandle.USER_SYSTEM); } } Loading Loading @@ -730,6 +738,11 @@ public final class QuotaController extends StateController { mTopAppGraceCache.delete(uid); } @Override public void onUserAddedLocked(int userId) { cacheInstallerPackagesLocked(userId); } @Override public void onUserRemovedLocked(int userId) { mTrackedJobs.delete(userId); Loading @@ -741,6 +754,7 @@ public final class QuotaController extends StateController { mExecutionStatsCache.delete(userId); mEJStats.delete(userId); mUidToPackageCache.clear(); mSystemInstallers.remove(userId); } /** Drop all historical stats and stop tracking any active sessions for the specified app. */ Loading @@ -767,6 +781,22 @@ public final class QuotaController extends StateController { mEJStats.delete(userId, packageName); } private void cacheInstallerPackagesLocked(int userId) { final List<PackageInfo> packages = mContext.getPackageManager() .getInstalledPackagesAsUser(SYSTEM_APP_CHECK_FLAGS, userId); for (int i = packages.size() - 1; i >= 0; --i) { final PackageInfo pi = packages.get(i); final ApplicationInfo ai = pi.applicationInfo; final int idx = ArrayUtils.indexOf( pi.requestedPermissions, Manifest.permission.INSTALL_PACKAGES); if (idx >= 0 && ai != null && PackageManager.PERMISSION_GRANTED == mContext.checkPermission(Manifest.permission.INSTALL_PACKAGES, -1, ai.uid)) { mSystemInstallers.add(UserHandle.getUserId(ai.uid), pi.packageName); } } } private boolean isUidInForeground(int uid) { if (UserHandle.isCore(uid)) { return true; Loading Loading @@ -962,7 +992,8 @@ public final class QuotaController extends StateController { if (quota.getStandbyBucketLocked() == NEVER_INDEX) { return 0; } final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked()); final long limitMs = getEJLimitMsLocked(userId, packageName, quota.getStandbyBucketLocked()); long remainingMs = limitMs - quota.getTallyLocked(); // Stale sessions may still be factored into tally. Make sure they're removed. Loading Loading @@ -1000,10 +1031,11 @@ public final class QuotaController extends StateController { return remainingMs - timer.getCurrentDuration(sElapsedRealtimeClock.millis()); } private long getEJLimitMsLocked(@NonNull final String packageName, final int standbyBucket) { private long getEJLimitMsLocked(final int userId, @NonNull final String packageName, final int standbyBucket) { final long baseLimitMs = mEJLimitsMs[standbyBucket]; if (packageName.equals(mPackageVerifier)) { return baseLimitMs + mEjLimitSpecialAdditionMs; if (mSystemInstallers.contains(userId, packageName)) { return baseLimitMs + mEjLimitAdditionInstallerMs; } return baseLimitMs; } Loading Loading @@ -1116,7 +1148,8 @@ public final class QuotaController extends StateController { final long nowElapsed = sElapsedRealtimeClock.millis(); ShrinkableDebits quota = getEJDebitsLocked(userId, packageName); final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked()); final long limitMs = getEJLimitMsLocked(userId, packageName, quota.getStandbyBucketLocked()); final long startWindowElapsed = Math.max(0, nowElapsed - mEJLimitWindowSizeMs); long remainingDeadSpaceMs = remainingExecutionTimeMs; // Total time looked at where a session wouldn't be phasing out. Loading Loading @@ -1743,7 +1776,8 @@ public final class QuotaController extends StateController { inRegularQuotaTimeElapsed = inQuotaTimeElapsed; } if (remainingEJQuota <= 0) { final long limitMs = getEJLimitMsLocked(packageName, standbyBucket) - mQuotaBufferMs; final long limitMs = getEJLimitMsLocked(userId, packageName, standbyBucket) - mQuotaBufferMs; long sumMs = 0; final Timer ejTimer = mEJPkgTimers.get(userId, packageName); if (ejTimer != null && ejTimer.isActive()) { Loading Loading @@ -3029,8 +3063,11 @@ public final class QuotaController extends StateController { static final String KEY_EJ_LIMIT_RESTRICTED_MS = QC_CONSTANT_PREFIX + "ej_limit_restricted_ms"; @VisibleForTesting static final String KEY_EJ_LIMIT_SPECIAL_ADDITION_MS = QC_CONSTANT_PREFIX + "ej_limit_special_addition_ms"; static final String KEY_EJ_LIMIT_ADDITION_SPECIAL_MS = QC_CONSTANT_PREFIX + "ej_limit_addition_special_ms"; @VisibleForTesting static final String KEY_EJ_LIMIT_ADDITION_INSTALLER_MS = QC_CONSTANT_PREFIX + "ej_limit_addition_installer_ms"; @VisibleForTesting static final String KEY_EJ_WINDOW_SIZE_MS = QC_CONSTANT_PREFIX + "ej_window_size_ms"; Loading Loading @@ -3098,7 +3135,8 @@ public final class QuotaController extends StateController { private static final long DEFAULT_EJ_LIMIT_FREQUENT_MS = 10 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_LIMIT_RARE_MS = DEFAULT_EJ_LIMIT_FREQUENT_MS; private static final long DEFAULT_EJ_LIMIT_RESTRICTED_MS = 5 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS = 30 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS = 15 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS = 30 * MINUTE_IN_MILLIS; private static final long DEFAULT_EJ_WINDOW_SIZE_MS = 24 * HOUR_IN_MILLIS; private static final long DEFAULT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS = 30 * SECOND_IN_MILLIS; private static final long DEFAULT_EJ_REWARD_TOP_APP_MS = 10 * SECOND_IN_MILLIS; Loading Loading @@ -3303,7 +3341,13 @@ public final class QuotaController extends StateController { /** * How much additional EJ quota special, critical apps should get. */ public long EJ_LIMIT_SPECIAL_ADDITION_MS = DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS; public long EJ_LIMIT_ADDITION_SPECIAL_MS = DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS; /** * How much additional EJ quota system installers (with the INSTALL_PACKAGES permission) * should get. */ public long EJ_LIMIT_ADDITION_INSTALLER_MS = DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS; /** * The period of time used to calculate expedited job sessions. Apps can only have expedited Loading Loading @@ -3369,7 +3413,8 @@ public final class QuotaController extends StateController { case KEY_EJ_LIMIT_FREQUENT_MS: case KEY_EJ_LIMIT_RARE_MS: case KEY_EJ_LIMIT_RESTRICTED_MS: case KEY_EJ_LIMIT_SPECIAL_ADDITION_MS: case KEY_EJ_LIMIT_ADDITION_SPECIAL_MS: case KEY_EJ_LIMIT_ADDITION_INSTALLER_MS: case KEY_EJ_WINDOW_SIZE_MS: updateEJLimitConstantsLocked(); break; Loading Loading @@ -3704,7 +3749,8 @@ public final class QuotaController extends StateController { DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_EJ_LIMIT_ACTIVE_MS, KEY_EJ_LIMIT_WORKING_MS, KEY_EJ_LIMIT_FREQUENT_MS, KEY_EJ_LIMIT_RARE_MS, KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, KEY_EJ_WINDOW_SIZE_MS); EJ_LIMIT_ACTIVE_MS = properties.getLong( KEY_EJ_LIMIT_ACTIVE_MS, DEFAULT_EJ_LIMIT_ACTIVE_MS); Loading @@ -3716,8 +3762,10 @@ public final class QuotaController extends StateController { KEY_EJ_LIMIT_RARE_MS, DEFAULT_EJ_LIMIT_RARE_MS); EJ_LIMIT_RESTRICTED_MS = properties.getLong( KEY_EJ_LIMIT_RESTRICTED_MS, DEFAULT_EJ_LIMIT_RESTRICTED_MS); EJ_LIMIT_SPECIAL_ADDITION_MS = properties.getLong( KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS); EJ_LIMIT_ADDITION_INSTALLER_MS = properties.getLong( KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, DEFAULT_EJ_LIMIT_ADDITION_INSTALLER_MS); EJ_LIMIT_ADDITION_SPECIAL_MS = properties.getLong( KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, DEFAULT_EJ_LIMIT_ADDITION_SPECIAL_MS); EJ_WINDOW_SIZE_MS = properties.getLong( KEY_EJ_WINDOW_SIZE_MS, DEFAULT_EJ_WINDOW_SIZE_MS); Loading Loading @@ -3763,11 +3811,17 @@ public final class QuotaController extends StateController { mEJLimitsMs[RESTRICTED_INDEX] = newRestrictedLimitMs; mShouldReevaluateConstraints = true; } // The addition must be in the range [0 minutes, window size - active limit]. long newSpecialAdditionMs = Math.max(0, Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_SPECIAL_ADDITION_MS)); if (mEjLimitSpecialAdditionMs != newSpecialAdditionMs) { mEjLimitSpecialAdditionMs = newSpecialAdditionMs; // The additions must be in the range [0 minutes, window size - active limit]. long newAdditionInstallerMs = Math.max(0, Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_ADDITION_INSTALLER_MS)); if (mEjLimitAdditionInstallerMs != newAdditionInstallerMs) { mEjLimitAdditionInstallerMs = newAdditionInstallerMs; mShouldReevaluateConstraints = true; } long newAdditionSpecialMs = Math.max(0, Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_ADDITION_SPECIAL_MS)); if (mEjLimitAdditionSpecialMs != newAdditionSpecialMs) { mEjLimitAdditionSpecialMs = newAdditionSpecialMs; mShouldReevaluateConstraints = true; } } Loading Loading @@ -3808,7 +3862,8 @@ public final class QuotaController extends StateController { pw.print(KEY_EJ_LIMIT_FREQUENT_MS, EJ_LIMIT_FREQUENT_MS).println(); pw.print(KEY_EJ_LIMIT_RARE_MS, EJ_LIMIT_RARE_MS).println(); pw.print(KEY_EJ_LIMIT_RESTRICTED_MS, EJ_LIMIT_RESTRICTED_MS).println(); pw.print(KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, EJ_LIMIT_SPECIAL_ADDITION_MS).println(); pw.print(KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, EJ_LIMIT_ADDITION_INSTALLER_MS).println(); pw.print(KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, EJ_LIMIT_ADDITION_SPECIAL_MS).println(); pw.print(KEY_EJ_WINDOW_SIZE_MS, EJ_WINDOW_SIZE_MS).println(); pw.print(KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, EJ_TOP_APP_TIME_CHUNK_SIZE_MS).println(); pw.print(KEY_EJ_REWARD_TOP_APP_MS, EJ_REWARD_TOP_APP_MS).println(); Loading Loading @@ -3945,8 +4000,13 @@ public final class QuotaController extends StateController { } @VisibleForTesting long getEjLimitSpecialAdditionMs() { return mEjLimitSpecialAdditionMs; long getEjLimitAdditionInstallerMs() { return mEjLimitAdditionInstallerMs; } @VisibleForTesting long getEjLimitAdditionSpecialMs() { return mEjLimitAdditionSpecialMs; } @VisibleForTesting Loading Loading @@ -4067,6 +4127,12 @@ public final class QuotaController extends StateController { pw.decreaseIndent(); pw.println(); pw.println("Special apps:"); pw.increaseIndent(); pw.print("System installers", mSystemInstallers.toString()); pw.decreaseIndent(); pw.println(); mTrackedJobs.forEach((jobs) -> { for (int j = 0; j < jobs.size(); j++) { final JobStatus js = jobs.valueAt(j); Loading
apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java +4 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,10 @@ public abstract class StateController { public void onAppRemovedLocked(String packageName, int uid) { } /** Called when a user is added to the device. */ public void onUserAddedLocked(int userId) { } /** Called when a user is removed from the device. */ public void onUserRemovedLocked(int userId) { } Loading
services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +31 −10 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.Manifest; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; Loading @@ -66,7 +67,10 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ServiceInfo; import android.os.BatteryManager; Loading Loading @@ -142,6 +146,8 @@ public class QuotaControllerTest { @Mock private JobSchedulerService mJobSchedulerService; @Mock private PackageManager mPackageManager; @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private PowerAllowlistInternal mPowerAllowlistInternal; Loading Loading @@ -201,6 +207,8 @@ public class QuotaControllerTest { -> mDeviceConfigPropertiesBuilder.build()) .when(() -> DeviceConfig.getProperties( eq(DeviceConfig.NAMESPACE_JOB_SCHEDULER), ArgumentMatchers.<String>any())); // Used in QuotaController.onSystemServicesReady when(mContext.getPackageManager()).thenReturn(mPackageManager); // Freeze the clocks at 24 hours after this moment in time. Several tests create sessions // in the past, and QuotaController sometimes floors values at 0, so if the test time Loading Loading @@ -2704,7 +2712,8 @@ public class QuotaControllerTest { setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 1 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 30 * MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 27 * MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 10 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, 7 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, 10 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 12 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 10 * MINUTE_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 87 * SECOND_IN_MILLIS); Loading Loading @@ -2745,7 +2754,8 @@ public class QuotaControllerTest { assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]); assertEquals(30 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]); assertEquals(27 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); assertEquals(10 * HOUR_IN_MILLIS, mQuotaController.getEjLimitSpecialAdditionMs()); assertEquals(7 * HOUR_IN_MILLIS, mQuotaController.getEjLimitAdditionInstallerMs()); assertEquals(10 * HOUR_IN_MILLIS, mQuotaController.getEjLimitAdditionSpecialMs()); assertEquals(12 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs()); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs()); assertEquals(87 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs()); Loading Loading @@ -2786,7 +2796,8 @@ public class QuotaControllerTest { setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, -1); setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, -1); Loading Loading @@ -2823,7 +2834,8 @@ public class QuotaControllerTest { assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]); assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs()); assertEquals(0, mQuotaController.getEjLimitAdditionInstallerMs()); assertEquals(0, mQuotaController.getEjLimitAdditionSpecialMs()); assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs()); assertEquals(1, mQuotaController.getEJTopAppTimeChunkSizeMs()); assertEquals(10 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs()); Loading Loading @@ -2858,7 +2870,8 @@ public class QuotaControllerTest { setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_INSTALLER_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_ADDITION_SPECIAL_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 25 * HOUR_IN_MILLIS); setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 25 * HOUR_IN_MILLIS); Loading @@ -2885,7 +2898,8 @@ public class QuotaControllerTest { assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs()); assertEquals(0, mQuotaController.getEjLimitAdditionInstallerMs()); assertEquals(0, mQuotaController.getEjLimitAdditionSpecialMs()); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs()); assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs()); assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardTopAppMs()); Loading Loading @@ -3957,9 +3971,16 @@ public class QuotaControllerTest { } @Test public void testGetRemainingEJExecutionTimeLocked_SpecialApp() { doReturn(new String[]{SOURCE_PACKAGE}).when(mPackageManagerInternal) .getKnownPackageNames(eq(PackageManagerInternal.PACKAGE_VERIFIER), anyInt()); public void testGetRemainingEJExecutionTimeLocked_Installer() { PackageInfo pi = new PackageInfo(); pi.packageName = SOURCE_PACKAGE; pi.requestedPermissions = new String[]{Manifest.permission.INSTALL_PACKAGES}; pi.requestedPermissionsFlags = new int[]{PackageInfo.REQUESTED_PERMISSION_GRANTED}; pi.applicationInfo = new ApplicationInfo(); pi.applicationInfo.uid = mSourceUid; doReturn(List.of(pi)).when(mPackageManager).getInstalledPackagesAsUser(anyInt(), anyInt()); doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkPermission( eq(Manifest.permission.INSTALL_PACKAGES), anyInt(), eq(mSourceUid)); mQuotaController.onSystemServicesReady(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); Loading @@ -3980,7 +4001,7 @@ public class QuotaControllerTest { setStandbyBucket(i); assertEquals("Got wrong remaining EJ execution time for bucket #" + i, i == NEVER_INDEX ? 0 : (limits[i] + mQuotaController.getEjLimitSpecialAdditionMs() : (limits[i] + mQuotaController.getEjLimitAdditionInstallerMs() - 5 * MINUTE_IN_MILLIS), mQuotaController.getRemainingEJExecutionTimeLocked( SOURCE_USER_ID, SOURCE_PACKAGE)); Loading