diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 8508c2c95666e..f5f4afb21588d 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -29,7 +29,6 @@ import android.content.pm.UserInfo; import android.os.Bundle; import android.os.IBinder; import android.os.TransactionTooLargeException; -import android.view.RemoteAnimationAdapter; import java.util.ArrayList; import java.util.List; @@ -356,4 +355,7 @@ public abstract class ActivityManagerInternal { * Unregisters the specified {@code processObserver}. */ public abstract void unregisterProcessObserver(IProcessObserver processObserver); + + /** Returns true if the given UID is registered as an active instrumentation. */ + public abstract boolean isActiveInstrumentation(int uid); } diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 672994e791340..3e880f03b222e 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -999,4 +999,16 @@ public abstract class PackageManagerInternal { * Migrates legacy obb data to its new location. */ public abstract void migrateLegacyObbData(); + + /** + * Ensures that we block deletion of unused packages on user removal. This is purely for the + * purpose of ensuring that b/141413692 is not reproducible on Q. + */ + public abstract void notifyingOnNextUserRemovalForTest(); + + /** + * Notifies PackageManager of the removal of a user. This is purely for the purpose of ensuring + * that b/141413692 is not reproducible on Q. + */ + public abstract void userRemovedForTest(); } diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 63641e538b8e4..880416abc4f32 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -104,4 +104,5 @@ interface IUserManager { String getUserName(); long getUserStartRealtime(); long getUserUnlockRealtime(); + void notifyOnNextUserRemoveForTest(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 88c29987d1df6..c6cae530e7952 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -271,8 +271,8 @@ import android.os.WorkSource; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.DeviceConfig; -import android.provider.Settings; import android.provider.DeviceConfig.Properties; +import android.provider.Settings; import android.server.ServerProtoEnums; import android.sysprop.VoldProperties; import android.text.TextUtils; @@ -8256,6 +8256,21 @@ public class ActivityManagerService extends IActivityManager.Stub } } + private boolean isActiveInstrumentation(int uid) { + synchronized (ActivityManagerService.this) { + for (int i = mActiveInstrumentation.size() - 1; i >= 0; i--) { + final ActiveInstrumentation instrumentation = mActiveInstrumentation.get(i); + for (int j = instrumentation.mRunningProcesses.size() - 1; j >= 0; j--) { + final ProcessRecord process = instrumentation.mRunningProcesses.get(j); + if (process.uid == uid) { + return true; + } + } + } + } + return false; + } + @Override public int getUidProcessState(int uid, String callingPackage) { if (!hasUsageStatsPermission(callingPackage)) { @@ -18507,6 +18522,11 @@ public class ActivityManagerService extends IActivityManager.Stub public void unregisterProcessObserver(IProcessObserver processObserver) { ActivityManagerService.this.unregisterProcessObserver(processObserver); } + + @Override + public boolean isActiveInstrumentation(int uid) { + return ActivityManagerService.this.isActiveInstrumentation(uid); + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0a2951d147c9e..47774b2a13fae 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -208,6 +208,7 @@ import android.os.AsyncTask; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.ConditionVariable; import android.os.Debug; import android.os.Environment; import android.os.FileUtils; @@ -978,6 +979,8 @@ public class PackageManagerService extends IPackageManager.Stub private Future mPrepareAppDataFuture; + private final ConditionVariable mBlockDeleteOnUserRemoveForTest = new ConditionVariable(true); + private static class IFVerificationParams { PackageParser.Package pkg; boolean replacing; @@ -23652,8 +23655,13 @@ public class PackageManagerService extends IPackageManager.Stub Slog.i(TAG, " Removing package " + packageName); } //end run - mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, - userHandle, 0)); + mHandler.post(() -> { + if (!mBlockDeleteOnUserRemoveForTest.block(30000 /* 30 seconds*/)) { + mBlockDeleteOnUserRemoveForTest.open(); + } + deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, + userHandle, 0); + }); } } } @@ -25008,6 +25016,16 @@ public class PackageManagerService extends IPackageManager.Stub Slog.wtf(TAG, e); } } + + @Override + public void notifyingOnNextUserRemovalForTest() { + mBlockDeleteOnUserRemoveForTest.close(); + } + + @Override + public void userRemovedForTest() { + mBlockDeleteOnUserRemoveForTest.open(); + } } @GuardedBy("mPackages") diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 204f186f9e130..e2ebd73361247 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import static android.Manifest.permission.INJECT_EVENTS; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -39,6 +40,7 @@ import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; import android.content.res.Resources; @@ -124,6 +126,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; /** * Service for {@link UserManager}. @@ -246,6 +249,7 @@ public class UserManagerService extends IUserManager.Stub { private final File mUserListFile; private static final IBinder mUserRestriconToken = new Binder(); + private final AtomicBoolean mNotifyPackageManagerOnUserRemoval = new AtomicBoolean(false); /** * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps. @@ -3134,6 +3138,11 @@ public class UserManagerService extends IUserManager.Stub { mRemovingUserIds.delete(userHandle); } } + if (mNotifyPackageManagerOnUserRemoval.getAndSet(false)) { + final PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); + pmInternal.userRemovedForTest(); + } } private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) { @@ -4210,4 +4219,20 @@ public class UserManagerService extends IUserManager.Stub { + " does not match the calling uid " + callingUid); } } + + @Override + public void notifyOnNextUserRemoveForTest() { + mContext.enforceCallingOrSelfPermission(INJECT_EVENTS, "notifyOnNextUserRemoveForTest"); + final ActivityManagerInternal amInternal = + LocalServices.getService(ActivityManagerInternal.class); + if (!amInternal.isActiveInstrumentation(Binder.getCallingUid())) { + return; + } + + this.mNotifyPackageManagerOnUserRemoval.set(true); + + final PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); + pmInternal.notifyingOnNextUserRemovalForTest(); + } }