diff options
| author | 2018-12-13 21:44:18 +0000 | |
|---|---|---|
| committer | 2018-12-13 21:44:18 +0000 | |
| commit | 70d74835c66bea86f849d52a54966a3f081f4e05 (patch) | |
| tree | 82779e5ef74d13512f839f425ced77eac1321fb8 | |
| parent | ca72a20238b98cc75cff6000c732f73980fd7ac4 (diff) | |
| parent | a9f8e1f7322d8b2c957984bd75e4487aaab0c3f6 (diff) | |
Merge "Clearing QuotaController data on app/user removal."
5 files changed, 146 insertions, 14 deletions
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 78e18e91ae73..1325f049e737 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -861,6 +861,11 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "Removing jobs for uid: " + uidRemoved); } cancelJobsForPackageAndUid(pkgName, uidRemoved, "app uninstalled"); + synchronized (mLock) { + for (int c = 0; c < mControllers.size(); ++c) { + mControllers.get(c).onAppRemovedLocked(pkgName, pkgUid); + } + } } } else if (Intent.ACTION_USER_REMOVED.equals(action)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); @@ -868,6 +873,11 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "Removing jobs for user: " + userId); } cancelJobsForUser(userId); + synchronized (mLock) { + for (int c = 0; c < mControllers.size(); ++c) { + mControllers.get(c).onUserRemovedLocked(userId); + } + } } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { // Has this package scheduled any jobs, such that we will take action // if it were to be force-stopped? diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index 8f104e4a1525..aca02bf1fb7c 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -296,6 +296,12 @@ public final class ConnectivityController extends StateController implements mRequestedWhitelistJobs.remove(uid); } + @GuardedBy("mLock") + @Override + public void onAppRemovedLocked(String pkgName, int uid) { + mTrackedJobs.delete(uid); + } + /** * Test to see if running the given job on the given network is insane. * <p> diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java index 660c2383ea2f..58ee21795d99 100644 --- a/services/core/java/com/android/server/job/controllers/QuotaController.java +++ b/services/core/java/com/android/server/job/controllers/QuotaController.java @@ -98,6 +98,19 @@ public final class QuotaController extends StateController { data.put(packageName, obj); } + /** Removes all the data for the user, if there was any. */ + public void delete(int userId) { + mData.delete(userId); + } + + /** Removes the data for the user and package, if there was any. */ + public void delete(int userId, @NonNull String packageName) { + ArrayMap<String, T> data = mData.get(userId); + if (data != null) { + data.remove(packageName); + } + } + @Nullable public T get(int userId, @NonNull String packageName) { ArrayMap<String, T> data = mData.get(userId); @@ -371,6 +384,38 @@ public final class QuotaController extends StateController { } } + @Override + public void onAppRemovedLocked(String packageName, int uid) { + if (packageName == null) { + Slog.wtf(TAG, "Told app removed but given null package name."); + return; + } + final int userId = UserHandle.getUserId(uid); + mTrackedJobs.delete(userId, packageName); + Timer timer = mPkgTimers.get(userId, packageName); + if (timer != null) { + if (timer.isActive()) { + Slog.wtf(TAG, "onAppRemovedLocked called before Timer turned off."); + timer.dropEverything(); + } + mPkgTimers.delete(userId, packageName); + } + mTimingSessions.delete(userId, packageName); + QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName); + if (alarmListener != null) { + mAlarmManager.cancel(alarmListener); + mInQuotaAlarmListeners.delete(userId, packageName); + } + } + + @Override + public void onUserRemovedLocked(int userId) { + mTrackedJobs.delete(userId); + mPkgTimers.delete(userId); + mTimingSessions.delete(userId); + mInQuotaAlarmListeners.delete(userId); + } + /** * Returns an appropriate standby bucket for the job, taking into account any standby * exemptions. @@ -882,6 +927,15 @@ public final class QuotaController extends StateController { } } + /** + * Stops tracking all jobs and cancels any pending alarms. This should only be called if + * the Timer is not going to be used anymore. + */ + void dropEverything() { + mRunningBgJobs.clear(); + cancelCutoff(); + } + private void emitSessionLocked(long nowElapsed) { if (mBgJobCount <= 0) { // Nothing to emit. diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java index 61dc4799f221..97c3bac4ddbb 100644 --- a/services/core/java/com/android/server/job/controllers/StateController.java +++ b/services/core/java/com/android/server/job/controllers/StateController.java @@ -83,21 +83,12 @@ public abstract class StateController { public void onConstantsUpdatedLocked() { } - protected boolean wouldBeReadyWithConstraintLocked(JobStatus jobStatus, int constraint) { - // This is very cheap to check (just a few conditions on data in JobStatus). - final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint); - if (DEBUG) { - Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString() - + " readyWithConstraint=" + jobWouldBeReady); - } - if (!jobWouldBeReady) { - // If the job wouldn't be ready, nothing to do here. - return false; - } + /** Called when a package is uninstalled from the device (not for an update). */ + public void onAppRemovedLocked(String packageName, int uid) { + } - // This is potentially more expensive since JSS may have to query component - // presence. - return mService.areComponentsInPlaceLocked(jobStatus); + /** Called when a user is removed from the device. */ + public void onUserRemovedLocked(int userId) { } /** @@ -114,6 +105,23 @@ public abstract class StateController { public void reevaluateStateLocked(int uid) { } + protected boolean wouldBeReadyWithConstraintLocked(JobStatus jobStatus, int constraint) { + // This is very cheap to check (just a few conditions on data in JobStatus). + final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint); + if (DEBUG) { + Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString() + + " readyWithConstraint=" + jobWouldBeReady); + } + if (!jobWouldBeReady) { + // If the job wouldn't be ready, nothing to do here. + return false; + } + + // This is potentially more expensive since JSS may have to query component + // presence. + return mService.areComponentsInPlaceLocked(jobStatus); + } + public abstract void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate); public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index 71aec235640b..effb5a72bd66 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -270,6 +270,60 @@ public class QuotaControllerTest { } @Test + public void testOnAppRemovedLocked() { + final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); + mQuotaController.saveTimingSession(0, "com.android.test.remove", + createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5)); + mQuotaController.saveTimingSession(0, "com.android.test.remove", + createTimingSession( + now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5)); + mQuotaController.saveTimingSession(0, "com.android.test.remove", + createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1)); + // Test that another app isn't affected. + TimingSession one = createTimingSession( + now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3); + TimingSession two = createTimingSession( + now - (70 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1); + List<TimingSession> expected = new ArrayList<>(); + // Added in correct (chronological) order. + expected.add(two); + expected.add(one); + mQuotaController.saveTimingSession(0, "com.android.test.stay", two); + mQuotaController.saveTimingSession(0, "com.android.test.stay", one); + + mQuotaController.onAppRemovedLocked("com.android.test.remove", 10001); + assertNull(mQuotaController.getTimingSessions(0, "com.android.test.remove")); + assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test.stay")); + } + + @Test + public void testOnUserRemovedLocked() { + final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); + mQuotaController.saveTimingSession(0, "com.android.test", + createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5)); + mQuotaController.saveTimingSession(0, "com.android.test", + createTimingSession( + now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5)); + mQuotaController.saveTimingSession(0, "com.android.test", + createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1)); + // Test that another user isn't affected. + TimingSession one = createTimingSession( + now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3); + TimingSession two = createTimingSession( + now - (70 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1); + List<TimingSession> expected = new ArrayList<>(); + // Added in correct (chronological) order. + expected.add(two); + expected.add(one); + mQuotaController.saveTimingSession(10, "com.android.test", two); + mQuotaController.saveTimingSession(10, "com.android.test", one); + + mQuotaController.onUserRemovedLocked(0); + assertNull(mQuotaController.getTimingSessions(0, "com.android.test")); + assertEquals(expected, mQuotaController.getTimingSessions(10, "com.android.test")); + } + + @Test public void testGetTrailingExecutionTimeLocked_NoTimer() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); // Added in chronological order. |