Loading services/core/java/com/android/server/pm/PackageArchiver.java +112 −10 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.content.pm.ArchivedActivityInfo.bytesFromBitmap; import static android.content.pm.ArchivedActivityInfo.drawableToBitmap; import static android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_STATUS; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageManager.DELETE_ARCHIVE; import static android.content.pm.PackageManager.DELETE_KEEP_DATA; import static android.content.pm.PackageManager.INSTALL_UNARCHIVE_DRAFT; Loading @@ -38,6 +40,7 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.IIntentReceiver; Loading Loading @@ -118,6 +121,15 @@ public class PackageArchiver { private static final String ACTION_UNARCHIVE_DIALOG = "com.android.intent.action.UNARCHIVE_DIALOG"; private static final String ACTION_UNARCHIVE_ERROR_DIALOG = "com.android.intent.action.UNARCHIVE_ERROR_DIALOG"; private static final String EXTRA_REQUIRED_BYTES = "com.android.content.pm.extra.UNARCHIVE_EXTRA_REQUIRED_BYTES"; private static final String EXTRA_INSTALLER_PACKAGE_NAME = "com.android.content.pm.extra.UNARCHIVE_INSTALLER_PACKAGE_NAME"; private static final String EXTRA_INSTALLER_TITLE = "com.android.content.pm.extra.UNARCHIVE_INSTALLER_TITLE"; private final Context mContext; private final PackageManagerService mPm; Loading Loading @@ -305,11 +317,14 @@ public class PackageArchiver { /** Creates archived state for the package and user. */ private CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId) throws PackageManager.NameNotFoundException { PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(), Computer snapshot = mPm.snapshotComputer(); PackageStateInternal ps = getPackageState(packageName, snapshot, Binder.getCallingUid(), userId); verifyNotSystemApp(ps.getFlags()); String responsibleInstallerPackage = getResponsibleInstallerPackage(ps); verifyInstaller(responsibleInstallerPackage, userId); ApplicationInfo installerInfo = snapshot.getApplicationInfo( responsibleInstallerPackage, /* flags= */ 0, userId); verifyOptOutStatus(packageName, UserHandle.getUid(userId, UserHandle.getUid(userId, ps.getAppId()))); Loading @@ -320,7 +335,7 @@ public class PackageArchiver { try { archiveState.complete( createArchiveStateInternal(packageName, userId, mainActivities, responsibleInstallerPackage)); installerInfo.loadLabel(mContext.getPackageManager()).toString())); } catch (IOException e) { archiveState.completeExceptionally(e); } Loading @@ -328,8 +343,17 @@ public class PackageArchiver { return archiveState; } static ArchiveState createArchiveState(@NonNull ArchivedPackageParcel archivedPackage, @Nullable ArchiveState createArchiveState(@NonNull ArchivedPackageParcel archivedPackage, int userId, String installerPackage) { ApplicationInfo installerInfo = mPm.snapshotComputer().getApplicationInfo( installerPackage, /* flags= */ 0, userId); if (installerInfo == null) { // Should never happen because we just fetched the installerInfo. Slog.e(TAG, "Couldnt find installer " + installerPackage); return null; } try { var packageName = archivedPackage.packageName; var mainActivities = archivedPackage.archivedActivities; Loading @@ -346,7 +370,8 @@ public class PackageArchiver { archiveActivityInfos.add(activityInfo); } return new ArchiveState(archiveActivityInfos, installerPackage); return new ArchiveState(archiveActivityInfos, installerInfo.loadLabel(mContext.getPackageManager()).toString()); } catch (IOException e) { Slog.e(TAG, "Failed to create archive state", e); return null; Loading @@ -354,7 +379,7 @@ public class PackageArchiver { } ArchiveState createArchiveStateInternal(String packageName, int userId, List<LauncherActivityInfo> mainActivities, String installerPackage) List<LauncherActivityInfo> mainActivities, String installerTitle) throws IOException { final int iconSize = mContext.getSystemService( ActivityManager.class).getLauncherLargeIconSize(); Loading @@ -372,7 +397,7 @@ public class PackageArchiver { archiveActivityInfos.add(activityInfo); } return new ArchiveState(archiveActivityInfos, installerPackage); return new ArchiveState(archiveActivityInfos, installerTitle); } // TODO(b/298452477) Handle monochrome icons. Loading Loading @@ -412,14 +437,14 @@ public class PackageArchiver { return iconFile.toPath(); } private void verifyInstaller(String installerPackage, int userId) private void verifyInstaller(String installerPackageName, int userId) throws PackageManager.NameNotFoundException { if (TextUtils.isEmpty(installerPackage)) { if (TextUtils.isEmpty(installerPackageName)) { throw new PackageManager.NameNotFoundException("No installer found"); } // Allow shell for easier development. if ((Binder.getCallingUid() != Process.SHELL_UID) && !verifySupportsUnarchival(installerPackage, userId)) { && !verifySupportsUnarchival(installerPackageName, userId)) { throw new PackageManager.NameNotFoundException("Installer does not support unarchival"); } } Loading Loading @@ -588,7 +613,7 @@ public class PackageArchiver { final Intent broadcastIntent = new Intent(); broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName); broadcastIntent.putExtra(PackageInstaller.EXTRA_UNARCHIVE_STATUS, broadcastIntent.putExtra(EXTRA_UNARCHIVE_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION); broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent); sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent); Loading Loading @@ -782,6 +807,83 @@ public class PackageArchiver { : ps.getInstallSource().mUpdateOwnerPackageName; } void notifyUnarchivalListener(int status, String installerPackageName, String appPackageName, long requiredStorageBytes, @Nullable PendingIntent userActionIntent, IntentSender unarchiveIntentSender, int userId) { final Intent broadcastIntent = new Intent(); broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, appPackageName); broadcastIntent.putExtra(EXTRA_UNARCHIVE_STATUS, status); if (status != UNARCHIVAL_OK) { final Intent dialogIntent = createErrorDialogIntent(status, installerPackageName, appPackageName, requiredStorageBytes, userActionIntent, userId); if (dialogIntent == null) { // Error already logged. return; } broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent); } final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setPendingIntentBackgroundActivityStartMode( MODE_BACKGROUND_ACTIVITY_START_DENIED); try { unarchiveIntentSender.sendIntent(mContext, 0, broadcastIntent, /* onFinished= */ null, /* handler= */ null, /* requiredPermission= */ null, options.toBundle()); } catch (IntentSender.SendIntentException e) { Slog.e(TAG, TextUtils.formatSimple("Failed to send unarchive intent"), e); } } @Nullable private Intent createErrorDialogIntent(int status, String installerPackageName, String appPackageName, long requiredStorageBytes, PendingIntent userActionIntent, int userId) { final Intent dialogIntent = new Intent(ACTION_UNARCHIVE_ERROR_DIALOG); dialogIntent.putExtra(EXTRA_UNARCHIVE_STATUS, status); if (requiredStorageBytes > 0) { dialogIntent.putExtra(EXTRA_REQUIRED_BYTES, requiredStorageBytes); } // Note that the userActionIntent is provided by the installer and is used only by the // system package installer as a follow-up action after the user confirms the dialog. if (userActionIntent != null) { dialogIntent.putExtra(Intent.EXTRA_INTENT, userActionIntent); } dialogIntent.putExtra(EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName); // We fetch this label from the archive state because the installer might not be installed // anymore in an edge case. String installerTitle = getInstallerTitle(appPackageName, userId); if (installerTitle == null) { // Error already logged. return null; } dialogIntent.putExtra(EXTRA_INSTALLER_TITLE, installerTitle); return dialogIntent; } private String getInstallerTitle(String appPackageName, int userId) { PackageStateInternal packageState; try { packageState = getPackageState(appPackageName, mPm.snapshotComputer(), Process.SYSTEM_UID, userId); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, TextUtils.formatSimple( "notifyUnarchivalListener: Couldn't fetch package state for %s.", appPackageName), e); return null; } ArchiveState archiveState = packageState.getUserStateOrDefault(userId).getArchiveState(); if (archiveState == null) { Slog.e(TAG, TextUtils.formatSimple("notifyUnarchivalListener: App not archived %s.", appPackageName)); return null; } return archiveState.getInstallerTitle(); } @NonNull private static PackageStateInternal getPackageState(String packageName, Computer snapshot, int callingUid, int userId) Loading services/core/java/com/android/server/pm/PackageInstallerService.java +8 −22 Original line number Diff line number Diff line Loading @@ -16,9 +16,10 @@ package com.android.server.pm; import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_DELETED_BY_DO; import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSTALLER_DISABLED; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSTALLER_UNINSTALLED; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_NO_CONNECTIVITY; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_USER_ACTION_NEEDED; Loading Loading @@ -1703,7 +1704,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements }); } // TODO(b/307299702) Implement error dialog and propagate userActionIntent. @Override public void reportUnarchivalStatus( int unarchiveId, Loading Loading @@ -1746,8 +1746,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // Execute expensive calls outside the sync block. mPm.mHandler.post( () -> notifyUnarchivalListener(status, session.params.appPackageName, unarchiveIntentSender)); () -> mPackageArchiver.notifyUnarchivalListener(status, session.getInstallerPackageName(), session.params.appPackageName, requiredStorageBytes, userActionIntent, unarchiveIntentSender, userId)); session.params.unarchiveIntentSender = null; if (status != UNARCHIVAL_OK) { Binder.withCleanCallingIdentity(session::abandon); Loading Loading @@ -1776,29 +1778,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements UNARCHIVAL_ERROR_USER_ACTION_NEEDED, UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE, UNARCHIVAL_ERROR_NO_CONNECTIVITY, UNARCHIVAL_ERROR_INSTALLER_DISABLED, UNARCHIVAL_ERROR_INSTALLER_UNINSTALLED, UNARCHIVAL_GENERIC_ERROR).contains(status)) { throw new IllegalStateException("Invalid status code passed " + status); } } private void notifyUnarchivalListener(int status, String packageName, IntentSender unarchiveIntentSender) { final Intent fillIn = new Intent(); fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName); fillIn.putExtra(PackageInstaller.EXTRA_UNARCHIVE_STATUS, status); // TODO(b/307299702) Attach failure dialog with EXTRA_INTENT and requiredStorageBytes here. final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setPendingIntentBackgroundActivityStartMode( MODE_BACKGROUND_ACTIVITY_START_DENIED); try { unarchiveIntentSender.sendIntent(mContext, 0, fillIn, /* onFinished= */ null, /* handler= */ null, /* requiredPermission= */ null, options.toBundle()); } catch (SendIntentException e) { Slog.e(TAG, TextUtils.formatSimple("Failed to send unarchive intent"), e); } } private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, int installerUid) { int count = 0; Loading services/core/java/com/android/server/pm/PackageManagerService.java +2 −2 Original line number Diff line number Diff line Loading @@ -1534,8 +1534,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService return; } for (int userId : userIds) { var archiveState = PackageArchiver.createArchiveState(archivePackage, userId, responsibleInstallerPackage); var archiveState = mInstallerService.mPackageArchiver.createArchiveState( archivePackage, userId, responsibleInstallerPackage); if (archiveState == null) { continue; } Loading services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +7 −1 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; Loading Loading @@ -92,6 +93,7 @@ public class PackageArchiverTest { private static final String PACKAGE = "com.example"; private static final String CALLER_PACKAGE = "com.caller"; private static final String INSTALLER_PACKAGE = "com.installer"; private static final String INSTALLER_LABEL = "Installer"; private static final Path ICON_PATH = Path.of("icon.png"); @Rule Loading Loading @@ -198,6 +200,10 @@ public class PackageArchiverTest { when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getResourcesForApplication(eq(PACKAGE))).thenReturn( mock(Resources.class)); ApplicationInfo installerAi = mock(ApplicationInfo.class); when(mComputer.getApplicationInfo(eq(INSTALLER_PACKAGE), anyLong(), anyInt())).thenReturn( installerAi); when(installerAi.loadLabel(any())).thenReturn(INSTALLER_LABEL); when(mInstallerService.createSessionInternal(any(), any(), any(), anyInt(), anyInt())).thenReturn(1); when(mInstallerService.getExistingDraftSessionId(anyInt(), any(), anyInt())).thenReturn( Loading Loading @@ -545,7 +551,7 @@ public class PackageArchiverTest { ICON_PATH, null); activityInfos.add(activityInfo); } return new ArchiveState(activityInfos, INSTALLER_PACKAGE); return new ArchiveState(activityInfos, INSTALLER_LABEL); } private static List<LauncherActivityInfo> createLauncherActivities() { Loading Loading
services/core/java/com/android/server/pm/PackageArchiver.java +112 −10 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.content.pm.ArchivedActivityInfo.bytesFromBitmap; import static android.content.pm.ArchivedActivityInfo.drawableToBitmap; import static android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_STATUS; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageManager.DELETE_ARCHIVE; import static android.content.pm.PackageManager.DELETE_KEEP_DATA; import static android.content.pm.PackageManager.INSTALL_UNARCHIVE_DRAFT; Loading @@ -38,6 +40,7 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.IIntentReceiver; Loading Loading @@ -118,6 +121,15 @@ public class PackageArchiver { private static final String ACTION_UNARCHIVE_DIALOG = "com.android.intent.action.UNARCHIVE_DIALOG"; private static final String ACTION_UNARCHIVE_ERROR_DIALOG = "com.android.intent.action.UNARCHIVE_ERROR_DIALOG"; private static final String EXTRA_REQUIRED_BYTES = "com.android.content.pm.extra.UNARCHIVE_EXTRA_REQUIRED_BYTES"; private static final String EXTRA_INSTALLER_PACKAGE_NAME = "com.android.content.pm.extra.UNARCHIVE_INSTALLER_PACKAGE_NAME"; private static final String EXTRA_INSTALLER_TITLE = "com.android.content.pm.extra.UNARCHIVE_INSTALLER_TITLE"; private final Context mContext; private final PackageManagerService mPm; Loading Loading @@ -305,11 +317,14 @@ public class PackageArchiver { /** Creates archived state for the package and user. */ private CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId) throws PackageManager.NameNotFoundException { PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(), Computer snapshot = mPm.snapshotComputer(); PackageStateInternal ps = getPackageState(packageName, snapshot, Binder.getCallingUid(), userId); verifyNotSystemApp(ps.getFlags()); String responsibleInstallerPackage = getResponsibleInstallerPackage(ps); verifyInstaller(responsibleInstallerPackage, userId); ApplicationInfo installerInfo = snapshot.getApplicationInfo( responsibleInstallerPackage, /* flags= */ 0, userId); verifyOptOutStatus(packageName, UserHandle.getUid(userId, UserHandle.getUid(userId, ps.getAppId()))); Loading @@ -320,7 +335,7 @@ public class PackageArchiver { try { archiveState.complete( createArchiveStateInternal(packageName, userId, mainActivities, responsibleInstallerPackage)); installerInfo.loadLabel(mContext.getPackageManager()).toString())); } catch (IOException e) { archiveState.completeExceptionally(e); } Loading @@ -328,8 +343,17 @@ public class PackageArchiver { return archiveState; } static ArchiveState createArchiveState(@NonNull ArchivedPackageParcel archivedPackage, @Nullable ArchiveState createArchiveState(@NonNull ArchivedPackageParcel archivedPackage, int userId, String installerPackage) { ApplicationInfo installerInfo = mPm.snapshotComputer().getApplicationInfo( installerPackage, /* flags= */ 0, userId); if (installerInfo == null) { // Should never happen because we just fetched the installerInfo. Slog.e(TAG, "Couldnt find installer " + installerPackage); return null; } try { var packageName = archivedPackage.packageName; var mainActivities = archivedPackage.archivedActivities; Loading @@ -346,7 +370,8 @@ public class PackageArchiver { archiveActivityInfos.add(activityInfo); } return new ArchiveState(archiveActivityInfos, installerPackage); return new ArchiveState(archiveActivityInfos, installerInfo.loadLabel(mContext.getPackageManager()).toString()); } catch (IOException e) { Slog.e(TAG, "Failed to create archive state", e); return null; Loading @@ -354,7 +379,7 @@ public class PackageArchiver { } ArchiveState createArchiveStateInternal(String packageName, int userId, List<LauncherActivityInfo> mainActivities, String installerPackage) List<LauncherActivityInfo> mainActivities, String installerTitle) throws IOException { final int iconSize = mContext.getSystemService( ActivityManager.class).getLauncherLargeIconSize(); Loading @@ -372,7 +397,7 @@ public class PackageArchiver { archiveActivityInfos.add(activityInfo); } return new ArchiveState(archiveActivityInfos, installerPackage); return new ArchiveState(archiveActivityInfos, installerTitle); } // TODO(b/298452477) Handle monochrome icons. Loading Loading @@ -412,14 +437,14 @@ public class PackageArchiver { return iconFile.toPath(); } private void verifyInstaller(String installerPackage, int userId) private void verifyInstaller(String installerPackageName, int userId) throws PackageManager.NameNotFoundException { if (TextUtils.isEmpty(installerPackage)) { if (TextUtils.isEmpty(installerPackageName)) { throw new PackageManager.NameNotFoundException("No installer found"); } // Allow shell for easier development. if ((Binder.getCallingUid() != Process.SHELL_UID) && !verifySupportsUnarchival(installerPackage, userId)) { && !verifySupportsUnarchival(installerPackageName, userId)) { throw new PackageManager.NameNotFoundException("Installer does not support unarchival"); } } Loading Loading @@ -588,7 +613,7 @@ public class PackageArchiver { final Intent broadcastIntent = new Intent(); broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName); broadcastIntent.putExtra(PackageInstaller.EXTRA_UNARCHIVE_STATUS, broadcastIntent.putExtra(EXTRA_UNARCHIVE_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION); broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent); sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent); Loading Loading @@ -782,6 +807,83 @@ public class PackageArchiver { : ps.getInstallSource().mUpdateOwnerPackageName; } void notifyUnarchivalListener(int status, String installerPackageName, String appPackageName, long requiredStorageBytes, @Nullable PendingIntent userActionIntent, IntentSender unarchiveIntentSender, int userId) { final Intent broadcastIntent = new Intent(); broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, appPackageName); broadcastIntent.putExtra(EXTRA_UNARCHIVE_STATUS, status); if (status != UNARCHIVAL_OK) { final Intent dialogIntent = createErrorDialogIntent(status, installerPackageName, appPackageName, requiredStorageBytes, userActionIntent, userId); if (dialogIntent == null) { // Error already logged. return; } broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent); } final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setPendingIntentBackgroundActivityStartMode( MODE_BACKGROUND_ACTIVITY_START_DENIED); try { unarchiveIntentSender.sendIntent(mContext, 0, broadcastIntent, /* onFinished= */ null, /* handler= */ null, /* requiredPermission= */ null, options.toBundle()); } catch (IntentSender.SendIntentException e) { Slog.e(TAG, TextUtils.formatSimple("Failed to send unarchive intent"), e); } } @Nullable private Intent createErrorDialogIntent(int status, String installerPackageName, String appPackageName, long requiredStorageBytes, PendingIntent userActionIntent, int userId) { final Intent dialogIntent = new Intent(ACTION_UNARCHIVE_ERROR_DIALOG); dialogIntent.putExtra(EXTRA_UNARCHIVE_STATUS, status); if (requiredStorageBytes > 0) { dialogIntent.putExtra(EXTRA_REQUIRED_BYTES, requiredStorageBytes); } // Note that the userActionIntent is provided by the installer and is used only by the // system package installer as a follow-up action after the user confirms the dialog. if (userActionIntent != null) { dialogIntent.putExtra(Intent.EXTRA_INTENT, userActionIntent); } dialogIntent.putExtra(EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName); // We fetch this label from the archive state because the installer might not be installed // anymore in an edge case. String installerTitle = getInstallerTitle(appPackageName, userId); if (installerTitle == null) { // Error already logged. return null; } dialogIntent.putExtra(EXTRA_INSTALLER_TITLE, installerTitle); return dialogIntent; } private String getInstallerTitle(String appPackageName, int userId) { PackageStateInternal packageState; try { packageState = getPackageState(appPackageName, mPm.snapshotComputer(), Process.SYSTEM_UID, userId); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, TextUtils.formatSimple( "notifyUnarchivalListener: Couldn't fetch package state for %s.", appPackageName), e); return null; } ArchiveState archiveState = packageState.getUserStateOrDefault(userId).getArchiveState(); if (archiveState == null) { Slog.e(TAG, TextUtils.formatSimple("notifyUnarchivalListener: App not archived %s.", appPackageName)); return null; } return archiveState.getInstallerTitle(); } @NonNull private static PackageStateInternal getPackageState(String packageName, Computer snapshot, int callingUid, int userId) Loading
services/core/java/com/android/server/pm/PackageInstallerService.java +8 −22 Original line number Diff line number Diff line Loading @@ -16,9 +16,10 @@ package com.android.server.pm; import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_DELETED_BY_DO; import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSTALLER_DISABLED; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSTALLER_UNINSTALLED; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_NO_CONNECTIVITY; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_USER_ACTION_NEEDED; Loading Loading @@ -1703,7 +1704,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements }); } // TODO(b/307299702) Implement error dialog and propagate userActionIntent. @Override public void reportUnarchivalStatus( int unarchiveId, Loading Loading @@ -1746,8 +1746,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // Execute expensive calls outside the sync block. mPm.mHandler.post( () -> notifyUnarchivalListener(status, session.params.appPackageName, unarchiveIntentSender)); () -> mPackageArchiver.notifyUnarchivalListener(status, session.getInstallerPackageName(), session.params.appPackageName, requiredStorageBytes, userActionIntent, unarchiveIntentSender, userId)); session.params.unarchiveIntentSender = null; if (status != UNARCHIVAL_OK) { Binder.withCleanCallingIdentity(session::abandon); Loading Loading @@ -1776,29 +1778,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements UNARCHIVAL_ERROR_USER_ACTION_NEEDED, UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE, UNARCHIVAL_ERROR_NO_CONNECTIVITY, UNARCHIVAL_ERROR_INSTALLER_DISABLED, UNARCHIVAL_ERROR_INSTALLER_UNINSTALLED, UNARCHIVAL_GENERIC_ERROR).contains(status)) { throw new IllegalStateException("Invalid status code passed " + status); } } private void notifyUnarchivalListener(int status, String packageName, IntentSender unarchiveIntentSender) { final Intent fillIn = new Intent(); fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName); fillIn.putExtra(PackageInstaller.EXTRA_UNARCHIVE_STATUS, status); // TODO(b/307299702) Attach failure dialog with EXTRA_INTENT and requiredStorageBytes here. final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setPendingIntentBackgroundActivityStartMode( MODE_BACKGROUND_ACTIVITY_START_DENIED); try { unarchiveIntentSender.sendIntent(mContext, 0, fillIn, /* onFinished= */ null, /* handler= */ null, /* requiredPermission= */ null, options.toBundle()); } catch (SendIntentException e) { Slog.e(TAG, TextUtils.formatSimple("Failed to send unarchive intent"), e); } } private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, int installerUid) { int count = 0; Loading
services/core/java/com/android/server/pm/PackageManagerService.java +2 −2 Original line number Diff line number Diff line Loading @@ -1534,8 +1534,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService return; } for (int userId : userIds) { var archiveState = PackageArchiver.createArchiveState(archivePackage, userId, responsibleInstallerPackage); var archiveState = mInstallerService.mPackageArchiver.createArchiveState( archivePackage, userId, responsibleInstallerPackage); if (archiveState == null) { continue; } Loading
services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +7 −1 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; Loading Loading @@ -92,6 +93,7 @@ public class PackageArchiverTest { private static final String PACKAGE = "com.example"; private static final String CALLER_PACKAGE = "com.caller"; private static final String INSTALLER_PACKAGE = "com.installer"; private static final String INSTALLER_LABEL = "Installer"; private static final Path ICON_PATH = Path.of("icon.png"); @Rule Loading Loading @@ -198,6 +200,10 @@ public class PackageArchiverTest { when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getResourcesForApplication(eq(PACKAGE))).thenReturn( mock(Resources.class)); ApplicationInfo installerAi = mock(ApplicationInfo.class); when(mComputer.getApplicationInfo(eq(INSTALLER_PACKAGE), anyLong(), anyInt())).thenReturn( installerAi); when(installerAi.loadLabel(any())).thenReturn(INSTALLER_LABEL); when(mInstallerService.createSessionInternal(any(), any(), any(), anyInt(), anyInt())).thenReturn(1); when(mInstallerService.getExistingDraftSessionId(anyInt(), any(), anyInt())).thenReturn( Loading Loading @@ -545,7 +551,7 @@ public class PackageArchiverTest { ICON_PATH, null); activityInfos.add(activityInfo); } return new ArchiveState(activityInfos, INSTALLER_PACKAGE); return new ArchiveState(activityInfos, INSTALLER_LABEL); } private static List<LauncherActivityInfo> createLauncherActivities() { Loading