diff options
13 files changed, 169 insertions, 140 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 924137838ad4..7ab047df5137 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2613,7 +2613,7 @@ public class ActivityManager { Manifest.permission.ACCESS_INSTANT_APPS}) public boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) { try { - return getService().clearApplicationUserData(packageName, + return getService().clearApplicationUserData(packageName, false, observer, UserHandle.myUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 84c07ec7f45a..85bf6aa75f56 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -207,7 +207,7 @@ interface IActivityManager { boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot); void getMemoryInfo(out ActivityManager.MemoryInfo outInfo); List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState(); - boolean clearApplicationUserData(in String packageName, + boolean clearApplicationUserData(in String packageName, boolean keepState, in IPackageDataObserver observer, int userId); void forceStopPackage(in String packageName, int userId); boolean killPids(in int[] pids, in String reason, boolean secure); diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java index bd0d853ce698..1dba0529eaf4 100644 --- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java @@ -1520,7 +1520,11 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter } // clear an application's data, blocking until the operation completes or times out - public void clearApplicationDataSynchronous(String packageName) { + // if keepSystemState is true, we intentionally do not also clear system state that + // would ordinarily also be cleared, because we aren't actually wiping the app back + // to empty; we're bringing it into the actual expected state related to the already- + // restored notification state etc. + public void clearApplicationDataSynchronous(String packageName, boolean keepSystemState) { // Don't wipe packages marked allowClearUserData=false try { PackageInfo info = mPackageManager.getPackageInfo(packageName, 0); @@ -1541,7 +1545,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter synchronized (mClearDataLock) { mClearingData = true; try { - mActivityManager.clearApplicationUserData(packageName, observer, 0); + mActivityManager.clearApplicationUserData(packageName, keepSystemState, observer, 0); } catch (RemoteException e) { // can't happen because the activity manager is in this process } diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index 888dcd7e7a5e..7efe5cadb5cc 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -327,7 +327,7 @@ public class FullRestoreEngine extends RestoreEngine { Slog.d(TAG, "Clearing app data preparatory to full restore"); } - mBackupManagerService.clearApplicationDataSynchronous(pkg); + mBackupManagerService.clearApplicationDataSynchronous(pkg, true); } else { if (MORE_DEBUG) { Slog.d(TAG, "backup agent (" diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java index 22691bb60bfa..3dc242f1d48a 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java @@ -591,7 +591,7 @@ public class PerformAdbRestoreTask implements Runnable { Slog.d(TAG, "Clearing app data preparatory to full restore"); } - mBackupManagerService.clearApplicationDataSynchronous(pkg); + mBackupManagerService.clearApplicationDataSynchronous(pkg, true); } else { if (DEBUG) { Slog.d(TAG, "backup agent (" diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 5884dc536080..2db743020237 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -947,7 +947,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // We also need to wipe the current target's data, as it's probably // in an incoherent state. backupManagerService.clearApplicationDataSynchronous( - mCurrentPackage.packageName); + mCurrentPackage.packageName, false); // Schedule the next state based on the nature of our failure if (status == BackupTransport.TRANSPORT_ERROR) { @@ -1115,7 +1115,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // If the agent fails restore, it might have put the app's data // into an incoherent state. For consistency we wipe its data // again in this case before continuing with normal teardown - backupManagerService.clearApplicationDataSynchronous(mCurrentPackage.packageName); + backupManagerService.clearApplicationDataSynchronous(mCurrentPackage.packageName, false); keyValueAgentCleanup(); } diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java new file mode 100644 index 000000000000..dbff957a0da7 --- /dev/null +++ b/services/core/java/com/android/server/AlarmManagerInternal.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server; + +public interface AlarmManagerInternal { + void removeAlarmsForUid(int uid); +} diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index ca1524959358..ae4f0cef18b6 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -92,6 +92,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.internal.util.LocalLog; import com.android.server.ForceAppStandbyTracker.Listener; +import com.android.server.LocalServices; /** * Alarm manager implementaion. @@ -467,21 +468,14 @@ class AlarmManagerService extends SystemService { return newStart; } - boolean remove(final PendingIntent operation, final IAlarmListener listener) { - if (operation == null && listener == null) { - if (localLOGV) { - Slog.w(TAG, "requested remove() of null operation", - new RuntimeException("here")); - } - return false; - } + boolean remove(Predicate<Alarm> predicate) { boolean didRemove = false; long newStart = 0; // recalculate endpoints as we go long newEnd = Long.MAX_VALUE; int newFlags = 0; for (int i = 0; i < alarms.size(); ) { Alarm alarm = alarms.get(i); - if (alarm.matches(operation, listener)) { + if (predicate.test(alarm)) { alarms.remove(i); didRemove = true; if (alarm.alarmClock != null) { @@ -507,111 +501,6 @@ class AlarmManagerService extends SystemService { return didRemove; } - boolean remove(final String packageName) { - if (packageName == null) { - if (localLOGV) { - Slog.w(TAG, "requested remove() of null packageName", - new RuntimeException("here")); - } - return false; - } - boolean didRemove = false; - long newStart = 0; // recalculate endpoints as we go - long newEnd = Long.MAX_VALUE; - int newFlags = 0; - for (int i = alarms.size()-1; i >= 0; i--) { - Alarm alarm = alarms.get(i); - if (alarm.matches(packageName)) { - alarms.remove(i); - didRemove = true; - if (alarm.alarmClock != null) { - mNextAlarmClockMayChange = true; - } - } else { - if (alarm.whenElapsed > newStart) { - newStart = alarm.whenElapsed; - } - if (alarm.maxWhenElapsed < newEnd) { - newEnd = alarm.maxWhenElapsed; - } - newFlags |= alarm.flags; - } - } - if (didRemove) { - // commit the new batch bounds - start = newStart; - end = newEnd; - flags = newFlags; - } - return didRemove; - } - - boolean removeForStopped(final int uid) { - boolean didRemove = false; - long newStart = 0; // recalculate endpoints as we go - long newEnd = Long.MAX_VALUE; - int newFlags = 0; - for (int i = alarms.size()-1; i >= 0; i--) { - Alarm alarm = alarms.get(i); - try { - if (alarm.uid == uid && ActivityManager.getService().isAppStartModeDisabled( - uid, alarm.packageName)) { - alarms.remove(i); - didRemove = true; - if (alarm.alarmClock != null) { - mNextAlarmClockMayChange = true; - } - } else { - if (alarm.whenElapsed > newStart) { - newStart = alarm.whenElapsed; - } - if (alarm.maxWhenElapsed < newEnd) { - newEnd = alarm.maxWhenElapsed; - } - newFlags |= alarm.flags; - } - } catch (RemoteException e) { - } - } - if (didRemove) { - // commit the new batch bounds - start = newStart; - end = newEnd; - flags = newFlags; - } - return didRemove; - } - - boolean remove(final int userHandle) { - boolean didRemove = false; - long newStart = 0; // recalculate endpoints as we go - long newEnd = Long.MAX_VALUE; - for (int i = 0; i < alarms.size(); ) { - Alarm alarm = alarms.get(i); - if (UserHandle.getUserId(alarm.creatorUid) == userHandle) { - alarms.remove(i); - didRemove = true; - if (alarm.alarmClock != null) { - mNextAlarmClockMayChange = true; - } - } else { - if (alarm.whenElapsed > newStart) { - newStart = alarm.whenElapsed; - } - if (alarm.maxWhenElapsed < newEnd) { - newEnd = alarm.maxWhenElapsed; - } - i++; - } - } - if (didRemove) { - // commit the new batch bounds - start = newStart; - end = newEnd; - } - return didRemove; - } - boolean hasPackage(final String packageName) { final int N = alarms.size(); for (int i = 0; i < N; i++) { @@ -759,6 +648,8 @@ class AlarmManagerService extends SystemService { mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context); mForceAppStandbyTracker.addListener(mForceAppStandbyListener); + + publishLocalService(AlarmManagerInternal.class, new LocalService()); } static long convertToElapsed(long when, int type) { @@ -1554,6 +1445,21 @@ class AlarmManagerService extends SystemService { } } + /** + * System-process internal API + */ + private final class LocalService implements AlarmManagerInternal { + @Override + public void removeAlarmsForUid(int uid) { + synchronized (mLock) { + removeLocked(uid); + } + } + } + + /** + * Public-facing binder interface + */ private final IBinder mService = new IAlarmManager.Stub() { @Override public void set(String callingPackage, @@ -2430,10 +2336,19 @@ class AlarmManagerService extends SystemService { } private void removeLocked(PendingIntent operation, IAlarmListener directReceiver) { + if (operation == null && directReceiver == null) { + if (localLOGV) { + Slog.w(TAG, "requested remove() of null operation", + new RuntimeException("here")); + } + return; + } + boolean didRemove = false; + final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver); for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(operation, directReceiver); + didRemove |= b.remove(whichAlarms); if (b.size() == 0) { mAlarmBatches.remove(i); } @@ -2476,11 +2391,58 @@ class AlarmManagerService extends SystemService { } } - void removeLocked(String packageName) { + void removeLocked(final int uid) { boolean didRemove = false; + final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(packageName); + didRemove |= b.remove(whichAlarms); + if (b.size() == 0) { + mAlarmBatches.remove(i); + } + } + for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) { + final Alarm a = mPendingWhileIdleAlarms.get(i); + if (a.uid == uid) { + // Don't set didRemove, since this doesn't impact the scheduled alarms. + mPendingWhileIdleAlarms.remove(i); + } + } + for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i --) { + final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i); + for (int j = alarmsForUid.size() - 1; j >= 0; j--) { + if (alarmsForUid.get(j).uid == uid) { + alarmsForUid.remove(j); + } + } + if (alarmsForUid.size() == 0) { + mPendingBackgroundAlarms.removeAt(i); + } + } + if (didRemove) { + if (DEBUG_BATCH) { + Slog.v(TAG, "remove(uid) changed bounds; rebatching"); + } + rebatchAllAlarmsLocked(true); + rescheduleKernelAlarmsLocked(); + updateNextAlarmClockLocked(); + } + } + + void removeLocked(final String packageName) { + if (packageName == null) { + if (localLOGV) { + Slog.w(TAG, "requested remove() of null packageName", + new RuntimeException("here")); + } + return; + } + + boolean didRemove = false; + final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(packageName); + for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { + Batch b = mAlarmBatches.get(i); + didRemove |= b.remove(whichAlarms); if (b.size() == 0) { mAlarmBatches.remove(i); } @@ -2513,11 +2475,20 @@ class AlarmManagerService extends SystemService { } } - void removeForStoppedLocked(int uid) { + void removeForStoppedLocked(final int uid) { boolean didRemove = false; + final Predicate<Alarm> whichAlarms = (Alarm a) -> { + try { + if (a.uid == uid && ActivityManager.getService().isAppStartModeDisabled( + uid, a.packageName)) { + return true; + } + } catch (RemoteException e) { /* fall through */} + return false; + }; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); - didRemove |= b.removeForStopped(uid); + didRemove |= b.remove(whichAlarms); if (b.size() == 0) { mAlarmBatches.remove(i); } @@ -2546,9 +2517,11 @@ class AlarmManagerService extends SystemService { void removeUserLocked(int userHandle) { boolean didRemove = false; + final Predicate<Alarm> whichAlarms = + (Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { Batch b = mAlarmBatches.get(i); - didRemove |= b.remove(userHandle); + didRemove |= b.remove(whichAlarms); if (b.size() == 0) { mAlarmBatches.remove(i); } @@ -3396,6 +3369,7 @@ class AlarmManagerService extends SystemService { @Override public void onReceive(Context context, Intent intent) { + final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); synchronized (mLock) { String action = intent.getAction(); String pkgList[] = null; @@ -3416,7 +3390,6 @@ class AlarmManagerService extends SystemService { removeUserLocked(userHandle); } } else if (Intent.ACTION_UID_REMOVED.equals(action)) { - int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); if (uid >= 0) { mLastAllowWhileIdleDispatch.delete(uid); } @@ -3436,7 +3409,13 @@ class AlarmManagerService extends SystemService { } if (pkgList != null && (pkgList.length > 0)) { for (String pkg : pkgList) { - removeLocked(pkg); + if (uid >= 0) { + // package-removed case + removeLocked(uid); + } else { + // external-applications-unavailable etc case + removeLocked(pkg); + } mPriorities.remove(pkg); for (int i=mBroadcastStats.size()-1; i>=0; i--) { ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7b4703a4677c..3bb439969eeb 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -401,6 +401,7 @@ import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; +import com.android.server.AlarmManagerInternal; import com.android.server.AppOpsService; import com.android.server.AttributeCache; import com.android.server.DeviceIdleController; @@ -471,6 +472,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import dalvik.system.VMRuntime; + import libcore.io.IoUtils; import libcore.util.EmptyArray; @@ -5948,7 +5950,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public boolean clearApplicationUserData(final String packageName, + public boolean clearApplicationUserData(final String packageName, boolean keepState, final IPackageDataObserver observer, int userId) { enforceNotIsolatedCaller("clearApplicationUserData"); int uid = Binder.getCallingUid(); @@ -6052,14 +6054,27 @@ public class ActivityManagerService extends IActivityManager.Stub pm.clearApplicationUserData(packageName, localObserver, resolvedUserId); if (appInfo != null) { - synchronized (this) { - // Remove all permissions granted from/to this package - removeUriPermissionsForPackageLocked(packageName, resolvedUserId, true); + // Restore already established notification state and permission grants, + // so it told us to keep those intact -- it's about to emplace app data + // that is appropriate for those bits of system state. + if (!keepState) { + synchronized (this) { + // Remove all permissions granted from/to this package + removeUriPermissionsForPackageLocked(packageName, resolvedUserId, true); + } + + // Reset notification state + INotificationManager inm = NotificationManager.getService(); + inm.clearData(packageName, appInfo.uid, uid == appInfo.uid); } - // Reset notification settings. - INotificationManager inm = NotificationManager.getService(); - inm.clearData(packageName, appInfo.uid, uid == appInfo.uid); + // Clear its scheduled jobs + JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); + js.cancelJobsForUid(appInfo.uid, "clear data"); + + // Clear its pending alarms + AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class); + ami.removeAlarmsForUid(uid); } } catch (RemoteException e) { } diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/services/core/java/com/android/server/job/JobSchedulerInternal.java index 9bcf208ab3f0..c97eeaf30ab3 100644 --- a/services/core/java/com/android/server/job/JobSchedulerInternal.java +++ b/services/core/java/com/android/server/job/JobSchedulerInternal.java @@ -44,6 +44,11 @@ public interface JobSchedulerInternal { List<JobInfo> getSystemScheduledPendingJobs(); /** + * Cancel the jobs for a given uid (e.g. when app data is cleared) + */ + void cancelJobsForUid(int uid, String reason); + + /** * These are for activity manager to communicate to use what is currently performing backups. */ void addBackingUpUid(int uid); diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 3f014b550839..d0ee91971f81 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -1984,6 +1984,11 @@ public final class JobSchedulerService extends com.android.server.SystemService } @Override + public void cancelJobsForUid(int uid, String reason) { + JobSchedulerService.this.cancelJobsForUid(uid, reason); + } + + @Override public void addBackingUpUid(int uid) { synchronized (mLock) { // No need to actually do anything here, since for a full backup the diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index a7cced75bfd6..2d82c469592e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -1374,7 +1374,7 @@ class PackageManagerShellCommand extends ShellCommand { } ClearDataObserver obs = new ClearDataObserver(); - ActivityManager.getService().clearApplicationUserData(pkg, obs, userId); + ActivityManager.getService().clearApplicationUserData(pkg, false, obs, userId); synchronized (obs) { while (!obs.finished) { try { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index b979ff46702d..738257271ead 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -11555,8 +11555,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { long ident = mInjector.binderClearCallingIdentity(); try { - return ActivityManager.getService().clearApplicationUserData(packageName, callback, - userId); + return ActivityManager.getService().clearApplicationUserData(packageName, false, + callback, userId); } catch(RemoteException re) { // Same process, should not happen. } catch (SecurityException se) { |