Merge "Allow clearing instant app meta-data" into oc-mr1-dev
am: e391175330
Change-Id: I35fea7acf6bd4084b06cb17c580c75df08ef484c
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -2225,7 +2225,12 @@ public class Intent implements Parcelable, Cloneable {
|
||||
* Note that the cleared package does <em>not</em>
|
||||
* receive this broadcast. The data contains the name of the package.
|
||||
* <ul>
|
||||
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
|
||||
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package. If the
|
||||
* package whose data was cleared is an uninstalled instant app, then the UID
|
||||
* will be -1. The platform keeps some meta-data associated with instant apps
|
||||
* after they are uninstalled.
|
||||
* <li> {@link #EXTRA_PACKAGE_NAME} containing the package name only if the cleared
|
||||
* data was for an instant app.
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<UninstalledInstantAppState> 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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user