diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index d4325448ef145..ff68e2348b4ad 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2907,6 +2907,8 @@ public class ActivityManager { /** * @hide */ + @RequiresPermission(anyOf={Manifest.permission.CLEAR_APP_USER_DATA, + Manifest.permission.ACCESS_INSTANT_APPS}) public boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) { try { return getService().clearApplicationUserData(packageName, diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index bd0228e8049db..a9dbdd5268a6f 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2225,7 +2225,12 @@ public class Intent implements Parcelable, Cloneable { * Note that the cleared package does not * receive this broadcast. The data contains the name of the package. * * *

This is a protected intent that can only be sent diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 99700df2b990a..e8bade9b2c94d 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -20,7 +20,6 @@ import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager.ApplicationInfoFlags; import android.content.pm.PackageManager.ComponentInfoFlags; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.PackageInfoFlags; import android.content.pm.PackageManager.ResolveInfoFlags; import android.os.Bundle; @@ -372,4 +371,11 @@ public abstract class PackageManagerInternal { /** Whether the binder caller can access instant apps. */ public abstract boolean canAccessInstantApps(int callingUid, int userId); + + /** + * Returns {@code true} if a given package has instant application meta-data. + * Otherwise, returns {@code false}. Meta-data is state (eg. cookie, app icon, etc) + * associated with an instant app. It may be kept after the instant app has been uninstalled. + */ + public abstract boolean hasInstantApplicationMetadata(String packageName, int userId); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d9f345471f634..28e7b6c8be1cc 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5848,26 +5848,53 @@ public class ActivityManagerService extends IActivityManager.Stub enforceNotIsolatedCaller("clearApplicationUserData"); int uid = Binder.getCallingUid(); int pid = Binder.getCallingPid(); - userId = mUserController.handleIncomingUser(pid, uid, userId, false, + final int resolvedUserId = mUserController.handleIncomingUser(pid, uid, userId, false, ALLOW_FULL_ONLY, "clearApplicationUserData", null); + final ApplicationInfo appInfo; + final boolean isInstantApp; long callingId = Binder.clearCallingIdentity(); try { IPackageManager pm = AppGlobals.getPackageManager(); - int pkgUid = -1; synchronized(this) { + // Instant packages are not protected if (getPackageManagerInternalLocked().isPackageDataProtected( - userId, packageName)) { + resolvedUserId, packageName)) { throw new SecurityException( "Cannot clear data for a protected package: " + packageName); } + ApplicationInfo applicationInfo = null; try { - pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES, userId); + applicationInfo = pm.getApplicationInfo(packageName, + MATCH_UNINSTALLED_PACKAGES, resolvedUserId); } catch (RemoteException e) { + /* ignore */ } - if (pkgUid == -1) { + appInfo = applicationInfo; + + final boolean clearingOwnUidData = appInfo != null && appInfo.uid == uid; + + if (!clearingOwnUidData && checkComponentPermission(permission.CLEAR_APP_USER_DATA, + pid, uid, -1, true) != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("PID " + pid + " does not have permission " + + android.Manifest.permission.CLEAR_APP_USER_DATA + " to clear data" + + " of package " + packageName); + } + + final boolean hasInstantMetadata = getPackageManagerInternalLocked() + .hasInstantApplicationMetadata(packageName, resolvedUserId); + final boolean isUninstalledAppWithoutInstantMetadata = + (appInfo == null && !hasInstantMetadata); + isInstantApp = (appInfo != null && appInfo.isInstantApp()) + || hasInstantMetadata; + final boolean canAccessInstantApps = checkComponentPermission( + permission.ACCESS_INSTANT_APPS, pid, uid, -1, true) + == PackageManager.PERMISSION_GRANTED; + + if (isUninstalledAppWithoutInstantMetadata || (isInstantApp + && !canAccessInstantApps)) { Slog.w(TAG, "Invalid packageName: " + packageName); if (observer != null) { try { @@ -5878,45 +5905,45 @@ public class ActivityManagerService extends IActivityManager.Stub } return false; } - if (uid == pkgUid || checkComponentPermission( - android.Manifest.permission.CLEAR_APP_USER_DATA, - pid, uid, -1, true) - == PackageManager.PERMISSION_GRANTED) { - forceStopPackageLocked(packageName, pkgUid, "clear data"); - } else { - throw new SecurityException("PID " + pid + " does not have permission " - + android.Manifest.permission.CLEAR_APP_USER_DATA + " to clear data" - + " of package " + packageName); - } - // Remove all tasks match the cleared application package and user - for (int i = mRecentTasks.size() - 1; i >= 0; i--) { - final TaskRecord tr = mRecentTasks.get(i); - final String taskPackageName = - tr.getBaseIntent().getComponent().getPackageName(); - if (tr.userId != userId) continue; - if (!taskPackageName.equals(packageName)) continue; - mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS); + if (appInfo != null) { + forceStopPackageLocked(packageName, appInfo.uid, "clear data"); + // Remove all tasks match the cleared application package and user + for (int i = mRecentTasks.size() - 1; i >= 0; i--) { + final TaskRecord tr = mRecentTasks.get(i); + final String taskPackageName = + tr.getBaseIntent().getComponent().getPackageName(); + if (tr.userId != resolvedUserId) continue; + if (!taskPackageName.equals(packageName)) continue; + mStackSupervisor.removeTaskByIdLocked(tr.taskId, false, + REMOVE_FROM_RECENTS); + } } } - final int pkgUidF = pkgUid; - final int userIdF = userId; final IPackageDataObserver localObserver = new IPackageDataObserver.Stub() { @Override public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException { - synchronized (ActivityManagerService.this) { - finishForceStopPackageLocked(packageName, pkgUidF); + if (appInfo != null) { + synchronized (ActivityManagerService.this) { + finishForceStopPackageLocked(packageName, appInfo.uid); + } } - final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED, Uri.fromParts("package", packageName, null)); intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - intent.putExtra(Intent.EXTRA_UID, pkgUidF); - intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(pkgUidF)); - broadcastIntentInPackage("android", SYSTEM_UID, intent, - null, null, 0, null, null, null, null, false, false, userIdF); + intent.putExtra(Intent.EXTRA_UID, (appInfo != null) ? appInfo.uid : -1); + intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId); + if (isInstantApp) { + intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); + broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0, + null, null, permission.ACCESS_INSTANT_APPS, null, false, false, + resolvedUserId); + } else { + broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0, + null, null, null, null, false, false, resolvedUserId); + } if (observer != null) { observer.onRemoveCompleted(packageName, succeeded); @@ -5926,16 +5953,18 @@ public class ActivityManagerService extends IActivityManager.Stub try { // Clear application user data - pm.clearApplicationUserData(packageName, localObserver, userId); + pm.clearApplicationUserData(packageName, localObserver, resolvedUserId); - synchronized(this) { - // Remove all permissions granted from/to this package - removeUriPermissionsForPackageLocked(packageName, userId, true); + if (appInfo != null) { + synchronized (this) { + // Remove all permissions granted from/to this package + removeUriPermissionsForPackageLocked(packageName, resolvedUserId, true); + } + + // Reset notification settings. + INotificationManager inm = NotificationManager.getService(); + inm.clearData(packageName, appInfo.uid, uid == appInfo.uid); } - - // Reset notification settings. - INotificationManager inm = NotificationManager.getService(); - inm.clearData(packageName, pkgUidF, uid == pkgUidF); } catch (RemoteException e) { } } finally { diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java index 211a1c9f3edf9..719c4d44cf9e6 100644 --- a/services/core/java/com/android/server/pm/InstantAppRegistry.java +++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java @@ -504,6 +504,11 @@ class InstantAppRegistry { } } + boolean hasInstantApplicationMetadataLPr(String packageName, int userId) { + return hasUninstalledInstantAppStateLPr(packageName, userId) + || hasInstantAppMetadataLPr(packageName, userId); + } + public void deleteInstantApplicationMetadataLPw(@NonNull String packageName, @UserIdInt int userId) { removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) -> @@ -547,6 +552,33 @@ class InstantAppRegistry { } } + private boolean hasUninstalledInstantAppStateLPr(String packageName, @UserIdInt int userId) { + if (mUninstalledInstantApps == null) { + return false; + } + final List uninstalledAppStates = + mUninstalledInstantApps.get(userId); + if (uninstalledAppStates == null) { + return false; + } + final int appCount = uninstalledAppStates.size(); + for (int i = 0; i < appCount; i++) { + final UninstalledInstantAppState uninstalledAppState = uninstalledAppStates.get(i); + if (packageName.equals(uninstalledAppState.mInstantAppInfo.getPackageName())) { + return true; + } + } + return false; + } + + private boolean hasInstantAppMetadataLPr(String packageName, @UserIdInt int userId) { + final File instantAppDir = getInstantApplicationDir(packageName, userId); + return new File(instantAppDir, INSTANT_APP_METADATA_FILE).exists() + || new File(instantAppDir, INSTANT_APP_ICON_FILE).exists() + || new File(instantAppDir, INSTANT_APP_ANDROID_ID_FILE).exists() + || peekInstantCookieFile(packageName, userId) != null; + } + void pruneInstantApps() { final long maxInstalledCacheDuration = Settings.Global.getLong( mService.mContext.getContentResolver(), @@ -1071,7 +1103,7 @@ class InstantAppRegistry { } private static @NonNull File getInstantApplicationDir(String packageName, int userId) { - return new File (getInstantApplicationsDir(userId), packageName); + return new File(getInstantApplicationsDir(userId), packageName); } private static void deleteDir(@NonNull File dir) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 99902eeeabc0b..a784d3a4bedb1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -25452,6 +25452,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); public boolean canAccessInstantApps(int callingUid, int userId) { return PackageManagerService.this.canViewInstantApps(callingUid, userId); } + + @Override + public boolean hasInstantApplicationMetadata(String packageName, int userId) { + synchronized (mPackages) { + return mInstantAppRegistry.hasInstantApplicationMetadataLPr(packageName, userId); + } + } } @Override