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