From 5610199bb29792a43447aab36c32937bd1dc4952 Mon Sep 17 00:00:00 2001 From: Ankita Vyas Date: Mon, 16 Jan 2023 09:02:01 +0000 Subject: [PATCH] Delete clone app when primary app is being uninstalled. In followup cl, will generalize this to any profile by adding a new UserProperty. Also contains fix in dialog fragment to pass correct userId. Bug: 265622990 Test: manual Change-Id: I4fc4d137bb546b55010060eed248ae6060446c19 --- packages/PackageInstaller/res/values/strings.xml | 2 ++ .../android/packageinstaller/UninstallFinish.java | 6 +++++- .../packageinstaller/UninstallerActivity.java | 15 ++++++++++++++- .../handheld/UninstallAlertDialogFragment.java | 12 ++++++------ .../android/server/pm/DeletePackageHelper.java | 15 +++++++++++++++ 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml index cb2baa974b0c2..ae6f71c954ca7 100644 --- a/packages/PackageInstaller/res/values/strings.xml +++ b/packages/PackageInstaller/res/values/strings.xml @@ -143,6 +143,8 @@ Uninstalled %1$s + Deleted %1$s clone + Uninstall unsuccessful. Uninstalling %1$s unsuccessful. diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java index b9552fc4e1433..e089aef43197c 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java @@ -49,6 +49,7 @@ public class UninstallFinish extends BroadcastReceiver { static final String EXTRA_UNINSTALL_ID = "com.android.packageinstaller.extra.UNINSTALL_ID"; static final String EXTRA_APP_LABEL = "com.android.packageinstaller.extra.APP_LABEL"; + static final String EXTRA_IS_CLONE_APP = "com.android.packageinstaller.extra.IS_CLONE_APP"; @Override public void onReceive(Context context, Intent intent) { @@ -84,7 +85,10 @@ public class UninstallFinish extends BroadcastReceiver { case PackageInstaller.STATUS_SUCCESS: notificationManager.cancel(uninstallId); - Toast.makeText(context, context.getString(R.string.uninstall_done_app, appLabel), + boolean isCloneApp = intent.getBooleanExtra(EXTRA_IS_CLONE_APP, false); + Toast.makeText(context, isCloneApp + ? context.getString(R.string.uninstall_done_clone_app, appLabel) + : context.getString(R.string.uninstall_done_app, appLabel), Toast.LENGTH_LONG).show(); return; case PackageInstaller.STATUS_FAILURE_BLOCKED: { diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java index 04496b91c9781..7250bdd4bec61 100755 --- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java @@ -67,6 +67,7 @@ public class UninstallerActivity extends Activity { private static final String TAG = "UninstallerActivity"; private static final String UNINSTALLING_CHANNEL = "uninstalling"; + private boolean mIsClonedApp; public static class DialogInfo { public ApplicationInfo appInfo; @@ -277,6 +278,14 @@ public class UninstallerActivity extends Activity { fragment.show(ft, "dialog"); } + /** + * Starts uninstall of app. + */ + public void startUninstallProgress(boolean keepData, boolean isClonedApp) { + mIsClonedApp = isClonedApp; + startUninstallProgress(keepData); + } + public void startUninstallProgress(boolean keepData) { boolean returnResult = getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false); CharSequence label = mDialogInfo.appInfo.loadSafeLabel(getPackageManager()); @@ -329,6 +338,7 @@ public class UninstallerActivity extends Activity { broadcastIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mDialogInfo.appInfo); broadcastIntent.putExtra(UninstallFinish.EXTRA_APP_LABEL, label); broadcastIntent.putExtra(UninstallFinish.EXTRA_UNINSTALL_ID, uninstallId); + broadcastIntent.putExtra(UninstallFinish.EXTRA_IS_CLONE_APP, mIsClonedApp); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, uninstallId, broadcastIntent, @@ -343,7 +353,10 @@ public class UninstallerActivity extends Activity { Notification uninstallingNotification = (new Notification.Builder(this, UNINSTALLING_CHANNEL)) .setSmallIcon(R.drawable.ic_remove).setProgress(0, 1, true) - .setContentTitle(getString(R.string.uninstalling_app, label)).setOngoing(true) + .setContentTitle(mIsClonedApp + ? getString(R.string.uninstalling_cloned_app, label) + : getString(R.string.uninstalling_app, label)) + .setOngoing(true) .build(); notificationManager.notify(uninstallId, uninstallingNotification); diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java index 1bbdad5ddfc8b..4a93bf80ae390 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java @@ -54,6 +54,7 @@ public class UninstallAlertDialogFragment extends DialogFragment implements private static final String LOG_TAG = UninstallAlertDialogFragment.class.getSimpleName(); private @Nullable CheckBox mKeepData; + private boolean mIsClonedApp; /** * Get number of bytes of the app data of the package. @@ -125,7 +126,6 @@ public class UninstallAlertDialogFragment extends DialogFragment implements messageBuilder.append(" ").append(appLabel).append(".\n\n"); } } - boolean isClonedApp = false; final boolean isUpdate = ((dialogInfo.appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0); @@ -154,7 +154,7 @@ public class UninstallAlertDialogFragment extends DialogFragment implements userName)); } else if (customUserManager.isUserOfType(USER_TYPE_PROFILE_CLONE) && customUserManager.isSameProfileGroup(dialogInfo.user, myUserHandle)) { - isClonedApp = true; + mIsClonedApp = true; messageBuilder.append(getString( R.string.uninstall_application_text_current_user_clone_profile)); } else { @@ -162,7 +162,7 @@ public class UninstallAlertDialogFragment extends DialogFragment implements getString(R.string.uninstall_application_text_user, userName)); } } else if (isCloneProfile(myUserHandle)) { - isClonedApp = true; + mIsClonedApp = true; messageBuilder.append(getString( R.string.uninstall_application_text_current_user_clone_profile)); } else { @@ -177,7 +177,7 @@ public class UninstallAlertDialogFragment extends DialogFragment implements } } - if (isClonedApp) { + if (mIsClonedApp) { dialogBuilder.setTitle(getString(R.string.cloned_app_label, appLabel)); } else { dialogBuilder.setTitle(appLabel); @@ -236,7 +236,7 @@ public class UninstallAlertDialogFragment extends DialogFragment implements UserManager userManager = getContext().getSystemService(UserManager.class); List profiles = userManager.getUserProfiles(); for (UserHandle userHandle : profiles) { - if (!Process.myUserHandle().equals(UserHandle.SYSTEM) && isCloneProfile(userHandle)) { + if (!userHandle.equals(UserHandle.SYSTEM) && isCloneProfile(userHandle)) { cloneUser = userHandle; break; } @@ -260,7 +260,7 @@ public class UninstallAlertDialogFragment extends DialogFragment implements public void onClick(DialogInterface dialog, int which) { if (which == Dialog.BUTTON_POSITIVE) { ((UninstallerActivity) getActivity()).startUninstallProgress( - mKeepData != null && mKeepData.isChecked()); + mKeepData != null && mKeepData.isChecked(), mIsClonedApp); } else { ((UninstallerActivity) getActivity()).dispatchAborted(); } diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java index 3df46a245eb16..a7e0af371d511 100644 --- a/services/core/java/com/android/server/pm/DeletePackageHelper.java +++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java @@ -774,6 +774,21 @@ final class DeletePackageHelper { if (!deleteAllUsers) { returnCode = deletePackageX(internalPackageName, versionCode, userId, deleteFlags, false /*removedBySystem*/); + + // Get a list of child user profiles and delete if package is + // present in clone profile. + int[] childUserIds = mUserManagerInternal.getProfileIds(userId, true); + for (int childId : childUserIds) { + if (childId != userId) { + UserInfo userInfo = mUserManagerInternal.getUserInfo(childId); + if (userInfo != null && userInfo.isCloneProfile()) { + returnCode = deletePackageX(internalPackageName, versionCode, + childId, deleteFlags, false /*removedBySystem*/); + break; + } + } + } + } else { int[] blockUninstallUserIds = getBlockUninstallForUsers(innerSnapshot, internalPackageName, users);