Loading core/java/android/content/pm/PackageInstaller.java +8 −6 Original line number Diff line number Diff line Loading @@ -671,6 +671,13 @@ public class PackageInstaller { @Retention(RetentionPolicy.SOURCE) public @interface UserActionReason {} /** * The unarchival status is not set. * * @hide */ public static final int UNARCHIVAL_STATUS_UNSET = -1; /** * The unarchival is possible and will commence. * Loading Loading @@ -736,6 +743,7 @@ public class PackageInstaller { * @hide */ @IntDef(value = { UNARCHIVAL_STATUS_UNSET, UNARCHIVAL_OK, UNARCHIVAL_ERROR_USER_ACTION_NEEDED, UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE, Loading Loading @@ -2696,8 +2704,6 @@ public class PackageInstaller { public int developmentInstallFlags = 0; /** {@hide} */ public int unarchiveId = -1; /** {@hide} */ public IntentSender unarchiveIntentSender; private final ArrayMap<String, Integer> mPermissionStates; Loading Loading @@ -2750,7 +2756,6 @@ public class PackageInstaller { applicationEnabledSettingPersistent = source.readBoolean(); developmentInstallFlags = source.readInt(); unarchiveId = source.readInt(); unarchiveIntentSender = source.readParcelable(null, IntentSender.class); } /** {@hide} */ Loading Loading @@ -2785,7 +2790,6 @@ public class PackageInstaller { ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent; ret.developmentInstallFlags = developmentInstallFlags; ret.unarchiveId = unarchiveId; ret.unarchiveIntentSender = unarchiveIntentSender; return ret; } Loading Loading @@ -3495,7 +3499,6 @@ public class PackageInstaller { applicationEnabledSettingPersistent); pw.printHexPair("developmentInstallFlags", developmentInstallFlags); pw.printPair("unarchiveId", unarchiveId); pw.printPair("unarchiveIntentSender", unarchiveIntentSender); pw.println(); } Loading Loading @@ -3540,7 +3543,6 @@ public class PackageInstaller { dest.writeBoolean(applicationEnabledSettingPersistent); dest.writeInt(developmentInstallFlags); dest.writeInt(unarchiveId); dest.writeParcelable(unarchiveIntentSender, flags); } public static final Parcelable.Creator<SessionParams> Loading services/core/java/com/android/server/pm/PackageArchiver.java +38 −22 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static android.content.pm.ArchivedActivityInfo.drawableToBitmap; import static android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_STATUS; import static android.content.pm.PackageInstaller.STATUS_PENDING_USER_ACTION; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET; 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 Loading @@ -100,6 +101,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; /** Loading Loading @@ -210,7 +212,6 @@ public class PackageArchiver { return; } // TODO(b/278553670) Add special strings for the delete dialog mPm.mInstallerService.uninstall( new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), Loading Loading @@ -264,7 +265,7 @@ public class PackageArchiver { try { // TODO(b/311709794) Make showUnarchivalConfirmation dependent on the compat options. requestUnarchive(packageName, callerPackageName, getOrCreateUnarchiveIntentSender(userId, packageName), getOrCreateLauncherListener(userId, packageName), UserHandle.of(userId), false /* showUnarchivalConfirmation= */); } catch (Throwable t) { Loading Loading @@ -329,7 +330,7 @@ public class PackageArchiver { return true; } private IntentSender getOrCreateUnarchiveIntentSender(int userId, String packageName) { private IntentSender getOrCreateLauncherListener(int userId, String packageName) { Pair<Integer, String> key = Pair.create(userId, packageName); synchronized (mLauncherIntentSenders) { IntentSender intentSender = mLauncherIntentSenders.get(key); Loading Loading @@ -515,7 +516,6 @@ public class PackageArchiver { /** * Returns true if the app is archivable. */ // TODO(b/299299569) Exclude system apps public boolean isAppArchivable(@NonNull String packageName, @NonNull UserHandle user) { Objects.requireNonNull(packageName); Objects.requireNonNull(user); Loading Loading @@ -685,15 +685,14 @@ public class PackageArchiver { PackageInstaller.SessionParams.MODE_FULL_INSTALL); sessionParams.setAppPackageName(packageName); sessionParams.installFlags = INSTALL_UNARCHIVE_DRAFT; sessionParams.unarchiveIntentSender = statusReceiver; int installerUid = mPm.snapshotComputer().getPackageUid(installerPackage, 0, userId); // Handles case of repeated unarchival calls for the same package. // TODO(b/316881759) Allow attaching multiple intentSenders to one session. int existingSessionId = mPm.mInstallerService.getExistingDraftSessionId(installerUid, sessionParams, userId); if (existingSessionId != PackageInstaller.SessionInfo.INVALID_ID) { attachListenerToSession(statusReceiver, existingSessionId, userId); return existingSessionId; } Loading @@ -702,12 +701,34 @@ public class PackageArchiver { installerPackage, mContext.getAttributionTag(), installerUid, userId); attachListenerToSession(statusReceiver, sessionId, userId); // TODO(b/297358628) Also cleanup sessions upon device restart. mPm.mHandler.postDelayed(() -> mPm.mInstallerService.cleanupDraftIfUnclaimed(sessionId), getUnarchiveForegroundTimeout()); return sessionId; } private void attachListenerToSession(IntentSender statusReceiver, int existingSessionId, int userId) { PackageInstallerSession session = mPm.mInstallerService.getSession(existingSessionId); int status = session.getUnarchivalStatus(); // Here we handle a race condition that might happen when an installer reports UNARCHIVAL_OK // but hasn't created a session yet. Without this the listener would never receive a success // response. if (status == UNARCHIVAL_OK) { notifyUnarchivalListener(UNARCHIVAL_OK, session.getInstallerPackageName(), session.params.appPackageName, /* requiredStorageBytes= */ 0, /* userActionIntent= */ null, Set.of(statusReceiver), userId); return; } else if (status != UNARCHIVAL_STATUS_UNSET) { throw new IllegalStateException(TextUtils.formatSimple("Session %s has unarchive status" + "%s but is still active.", session.sessionId, status)); } session.registerUnarchivalListener(statusReceiver); } /** * Returns the icon of an archived app. This is the icon of the main activity of the app. * Loading Loading @@ -883,13 +904,7 @@ public class PackageArchiver { void notifyUnarchivalListener(int status, String installerPackageName, String appPackageName, long requiredStorageBytes, @Nullable PendingIntent userActionIntent, @Nullable IntentSender unarchiveIntentSender, int userId) { if (unarchiveIntentSender == null) { // Maybe this can happen if the installer calls reportUnarchivalStatus twice in quick // succession. return; } Set<IntentSender> unarchiveIntentSenders, int userId) { final Intent broadcastIntent = new Intent(); broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, appPackageName); broadcastIntent.putExtra(EXTRA_UNARCHIVE_STATUS, status); Loading @@ -909,10 +924,10 @@ public class PackageArchiver { final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setPendingIntentBackgroundActivityStartMode( MODE_BACKGROUND_ACTIVITY_START_DENIED); for (IntentSender intentSender : unarchiveIntentSenders) { try { unarchiveIntentSender.sendIntent(mContext, 0, broadcastIntent, /* onFinished= */ null, /* handler= */ null, /* requiredPermission= */ null, options.toBundle()); intentSender.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); } finally { Loading @@ -921,6 +936,7 @@ public class PackageArchiver { } } } } @Nullable private Intent createErrorDialogIntent(int status, String installerPackageName, Loading services/core/java/com/android/server/pm/PackageInstallerService.java +2 −20 Original line number Diff line number Diff line Loading @@ -1759,26 +1759,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements binderUid, unarchiveId)); } IntentSender unarchiveIntentSender = session.params.unarchiveIntentSender; if (unarchiveIntentSender == null) { throw new IllegalStateException( TextUtils.formatSimple( "Unarchival status for ID %s has already been set or a " + "session has been created for it already by the " + "caller.", unarchiveId)); } // Execute expensive calls outside the sync block. mPm.mHandler.post( () -> mPackageArchiver.notifyUnarchivalListener(status, session.getInstallerPackageName(), session.params.appPackageName, requiredStorageBytes, userActionIntent, unarchiveIntentSender, userId)); session.params.unarchiveIntentSender = null; if (status != UNARCHIVAL_OK) { Binder.withCleanCallingIdentity(session::abandon); } session.reportUnarchivalStatus(unarchiveId, status, requiredStorageBytes, userActionIntent); } } Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +49 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDAT import static android.content.pm.DataLoaderType.INCREMENTAL; import static android.content.pm.DataLoaderType.STREAMING; import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET; import static android.content.pm.PackageItemInfo.MAX_SAFE_LABEL_LENGTH; import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED; import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE; Loading Loading @@ -65,6 +67,7 @@ import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; Loading Loading @@ -97,6 +100,7 @@ import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.PreapprovalDetails; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageInstaller.UnarchivalStatus; import android.content.pm.PackageInstaller.UserActionReason; import android.content.pm.PackageManager; import android.content.pm.PackageManager.PackageInfoFlags; Loading Loading @@ -771,6 +775,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final List<String> mResolvedInstructionSets = new ArrayList<>(); @GuardedBy("mLock") private final List<String> mResolvedNativeLibPaths = new ArrayList<>(); @GuardedBy("mLock") private final Set<IntentSender> mUnarchivalListeners = new ArraySet<>(); @GuardedBy("mLock") private File mInheritedFilesBase; @GuardedBy("mLock") Loading @@ -796,6 +804,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private int mValidatedTargetSdk = INVALID_TARGET_SDK_VERSION; @UnarchivalStatus private int mUnarchivalStatus = UNARCHIVAL_STATUS_UNSET; private static final FileFilter sAddedApkFilter = new FileFilter() { @Override public boolean accept(File file) { Loading Loading @@ -5088,6 +5099,44 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } void registerUnarchivalListener(IntentSender intentSender) { synchronized (mLock) { this.mUnarchivalListeners.add(intentSender); } } Set<IntentSender> getUnarchivalListeners() { synchronized (mLock) { return new ArraySet<>(mUnarchivalListeners); } } void reportUnarchivalStatus(@UnarchivalStatus int status, int unarchiveId, long requiredStorageBytes, PendingIntent userActionIntent) { if (getUnarchivalStatus() != UNARCHIVAL_STATUS_UNSET) { throw new IllegalStateException( TextUtils.formatSimple( "Unarchival status for ID %s has already been set or a session has " + "been created for it already by the caller.", unarchiveId)); } mUnarchivalStatus = status; // Execute expensive calls outside the sync block. mPm.mHandler.post( () -> mPm.mInstallerService.mPackageArchiver.notifyUnarchivalListener(status, getInstallerPackageName(), params.appPackageName, requiredStorageBytes, userActionIntent, getUnarchivalListeners(), userId)); if (status != UNARCHIVAL_OK) { Binder.withCleanCallingIdentity(this::abandon); } } @UnarchivalStatus int getUnarchivalStatus() { return this.mUnarchivalStatus; } /** * Free up storage used by this session and its children. * Must not be called on a child session. Loading services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +3 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,9 @@ public class PackageArchiverTest { anyInt())).thenReturn(1); when(mInstallerService.getExistingDraftSessionId(anyInt(), any(), anyInt())).thenReturn( PackageInstaller.SessionInfo.INVALID_ID); PackageInstallerSession session = mock(PackageInstallerSession.class); when(mInstallerService.getSession(anyInt())).thenReturn(session); when(session.getUnarchivalStatus()).thenReturn(PackageInstaller.UNARCHIVAL_STATUS_UNSET); doReturn(new ParceledListSlice<>(List.of(mock(ResolveInfo.class)))) .when(mPackageManagerService).queryIntentReceivers(any(), any(), any(), anyLong(), eq(mUserId)); Loading Loading
core/java/android/content/pm/PackageInstaller.java +8 −6 Original line number Diff line number Diff line Loading @@ -671,6 +671,13 @@ public class PackageInstaller { @Retention(RetentionPolicy.SOURCE) public @interface UserActionReason {} /** * The unarchival status is not set. * * @hide */ public static final int UNARCHIVAL_STATUS_UNSET = -1; /** * The unarchival is possible and will commence. * Loading Loading @@ -736,6 +743,7 @@ public class PackageInstaller { * @hide */ @IntDef(value = { UNARCHIVAL_STATUS_UNSET, UNARCHIVAL_OK, UNARCHIVAL_ERROR_USER_ACTION_NEEDED, UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE, Loading Loading @@ -2696,8 +2704,6 @@ public class PackageInstaller { public int developmentInstallFlags = 0; /** {@hide} */ public int unarchiveId = -1; /** {@hide} */ public IntentSender unarchiveIntentSender; private final ArrayMap<String, Integer> mPermissionStates; Loading Loading @@ -2750,7 +2756,6 @@ public class PackageInstaller { applicationEnabledSettingPersistent = source.readBoolean(); developmentInstallFlags = source.readInt(); unarchiveId = source.readInt(); unarchiveIntentSender = source.readParcelable(null, IntentSender.class); } /** {@hide} */ Loading Loading @@ -2785,7 +2790,6 @@ public class PackageInstaller { ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent; ret.developmentInstallFlags = developmentInstallFlags; ret.unarchiveId = unarchiveId; ret.unarchiveIntentSender = unarchiveIntentSender; return ret; } Loading Loading @@ -3495,7 +3499,6 @@ public class PackageInstaller { applicationEnabledSettingPersistent); pw.printHexPair("developmentInstallFlags", developmentInstallFlags); pw.printPair("unarchiveId", unarchiveId); pw.printPair("unarchiveIntentSender", unarchiveIntentSender); pw.println(); } Loading Loading @@ -3540,7 +3543,6 @@ public class PackageInstaller { dest.writeBoolean(applicationEnabledSettingPersistent); dest.writeInt(developmentInstallFlags); dest.writeInt(unarchiveId); dest.writeParcelable(unarchiveIntentSender, flags); } public static final Parcelable.Creator<SessionParams> Loading
services/core/java/com/android/server/pm/PackageArchiver.java +38 −22 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static android.content.pm.ArchivedActivityInfo.drawableToBitmap; import static android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_STATUS; import static android.content.pm.PackageInstaller.STATUS_PENDING_USER_ACTION; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET; 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 Loading @@ -100,6 +101,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; /** Loading Loading @@ -210,7 +212,6 @@ public class PackageArchiver { return; } // TODO(b/278553670) Add special strings for the delete dialog mPm.mInstallerService.uninstall( new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), Loading Loading @@ -264,7 +265,7 @@ public class PackageArchiver { try { // TODO(b/311709794) Make showUnarchivalConfirmation dependent on the compat options. requestUnarchive(packageName, callerPackageName, getOrCreateUnarchiveIntentSender(userId, packageName), getOrCreateLauncherListener(userId, packageName), UserHandle.of(userId), false /* showUnarchivalConfirmation= */); } catch (Throwable t) { Loading Loading @@ -329,7 +330,7 @@ public class PackageArchiver { return true; } private IntentSender getOrCreateUnarchiveIntentSender(int userId, String packageName) { private IntentSender getOrCreateLauncherListener(int userId, String packageName) { Pair<Integer, String> key = Pair.create(userId, packageName); synchronized (mLauncherIntentSenders) { IntentSender intentSender = mLauncherIntentSenders.get(key); Loading Loading @@ -515,7 +516,6 @@ public class PackageArchiver { /** * Returns true if the app is archivable. */ // TODO(b/299299569) Exclude system apps public boolean isAppArchivable(@NonNull String packageName, @NonNull UserHandle user) { Objects.requireNonNull(packageName); Objects.requireNonNull(user); Loading Loading @@ -685,15 +685,14 @@ public class PackageArchiver { PackageInstaller.SessionParams.MODE_FULL_INSTALL); sessionParams.setAppPackageName(packageName); sessionParams.installFlags = INSTALL_UNARCHIVE_DRAFT; sessionParams.unarchiveIntentSender = statusReceiver; int installerUid = mPm.snapshotComputer().getPackageUid(installerPackage, 0, userId); // Handles case of repeated unarchival calls for the same package. // TODO(b/316881759) Allow attaching multiple intentSenders to one session. int existingSessionId = mPm.mInstallerService.getExistingDraftSessionId(installerUid, sessionParams, userId); if (existingSessionId != PackageInstaller.SessionInfo.INVALID_ID) { attachListenerToSession(statusReceiver, existingSessionId, userId); return existingSessionId; } Loading @@ -702,12 +701,34 @@ public class PackageArchiver { installerPackage, mContext.getAttributionTag(), installerUid, userId); attachListenerToSession(statusReceiver, sessionId, userId); // TODO(b/297358628) Also cleanup sessions upon device restart. mPm.mHandler.postDelayed(() -> mPm.mInstallerService.cleanupDraftIfUnclaimed(sessionId), getUnarchiveForegroundTimeout()); return sessionId; } private void attachListenerToSession(IntentSender statusReceiver, int existingSessionId, int userId) { PackageInstallerSession session = mPm.mInstallerService.getSession(existingSessionId); int status = session.getUnarchivalStatus(); // Here we handle a race condition that might happen when an installer reports UNARCHIVAL_OK // but hasn't created a session yet. Without this the listener would never receive a success // response. if (status == UNARCHIVAL_OK) { notifyUnarchivalListener(UNARCHIVAL_OK, session.getInstallerPackageName(), session.params.appPackageName, /* requiredStorageBytes= */ 0, /* userActionIntent= */ null, Set.of(statusReceiver), userId); return; } else if (status != UNARCHIVAL_STATUS_UNSET) { throw new IllegalStateException(TextUtils.formatSimple("Session %s has unarchive status" + "%s but is still active.", session.sessionId, status)); } session.registerUnarchivalListener(statusReceiver); } /** * Returns the icon of an archived app. This is the icon of the main activity of the app. * Loading Loading @@ -883,13 +904,7 @@ public class PackageArchiver { void notifyUnarchivalListener(int status, String installerPackageName, String appPackageName, long requiredStorageBytes, @Nullable PendingIntent userActionIntent, @Nullable IntentSender unarchiveIntentSender, int userId) { if (unarchiveIntentSender == null) { // Maybe this can happen if the installer calls reportUnarchivalStatus twice in quick // succession. return; } Set<IntentSender> unarchiveIntentSenders, int userId) { final Intent broadcastIntent = new Intent(); broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, appPackageName); broadcastIntent.putExtra(EXTRA_UNARCHIVE_STATUS, status); Loading @@ -909,10 +924,10 @@ public class PackageArchiver { final BroadcastOptions options = BroadcastOptions.makeBasic(); options.setPendingIntentBackgroundActivityStartMode( MODE_BACKGROUND_ACTIVITY_START_DENIED); for (IntentSender intentSender : unarchiveIntentSenders) { try { unarchiveIntentSender.sendIntent(mContext, 0, broadcastIntent, /* onFinished= */ null, /* handler= */ null, /* requiredPermission= */ null, options.toBundle()); intentSender.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); } finally { Loading @@ -921,6 +936,7 @@ public class PackageArchiver { } } } } @Nullable private Intent createErrorDialogIntent(int status, String installerPackageName, Loading
services/core/java/com/android/server/pm/PackageInstallerService.java +2 −20 Original line number Diff line number Diff line Loading @@ -1759,26 +1759,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements binderUid, unarchiveId)); } IntentSender unarchiveIntentSender = session.params.unarchiveIntentSender; if (unarchiveIntentSender == null) { throw new IllegalStateException( TextUtils.formatSimple( "Unarchival status for ID %s has already been set or a " + "session has been created for it already by the " + "caller.", unarchiveId)); } // Execute expensive calls outside the sync block. mPm.mHandler.post( () -> mPackageArchiver.notifyUnarchivalListener(status, session.getInstallerPackageName(), session.params.appPackageName, requiredStorageBytes, userActionIntent, unarchiveIntentSender, userId)); session.params.unarchiveIntentSender = null; if (status != UNARCHIVAL_OK) { Binder.withCleanCallingIdentity(session::abandon); } session.reportUnarchivalStatus(unarchiveId, status, requiredStorageBytes, userActionIntent); } } Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +49 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDAT import static android.content.pm.DataLoaderType.INCREMENTAL; import static android.content.pm.DataLoaderType.STREAMING; import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET; import static android.content.pm.PackageItemInfo.MAX_SAFE_LABEL_LENGTH; import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED; import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE; Loading Loading @@ -65,6 +67,7 @@ import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; Loading Loading @@ -97,6 +100,7 @@ import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.PreapprovalDetails; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageInstaller.UnarchivalStatus; import android.content.pm.PackageInstaller.UserActionReason; import android.content.pm.PackageManager; import android.content.pm.PackageManager.PackageInfoFlags; Loading Loading @@ -771,6 +775,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final List<String> mResolvedInstructionSets = new ArrayList<>(); @GuardedBy("mLock") private final List<String> mResolvedNativeLibPaths = new ArrayList<>(); @GuardedBy("mLock") private final Set<IntentSender> mUnarchivalListeners = new ArraySet<>(); @GuardedBy("mLock") private File mInheritedFilesBase; @GuardedBy("mLock") Loading @@ -796,6 +804,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private int mValidatedTargetSdk = INVALID_TARGET_SDK_VERSION; @UnarchivalStatus private int mUnarchivalStatus = UNARCHIVAL_STATUS_UNSET; private static final FileFilter sAddedApkFilter = new FileFilter() { @Override public boolean accept(File file) { Loading Loading @@ -5088,6 +5099,44 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } void registerUnarchivalListener(IntentSender intentSender) { synchronized (mLock) { this.mUnarchivalListeners.add(intentSender); } } Set<IntentSender> getUnarchivalListeners() { synchronized (mLock) { return new ArraySet<>(mUnarchivalListeners); } } void reportUnarchivalStatus(@UnarchivalStatus int status, int unarchiveId, long requiredStorageBytes, PendingIntent userActionIntent) { if (getUnarchivalStatus() != UNARCHIVAL_STATUS_UNSET) { throw new IllegalStateException( TextUtils.formatSimple( "Unarchival status for ID %s has already been set or a session has " + "been created for it already by the caller.", unarchiveId)); } mUnarchivalStatus = status; // Execute expensive calls outside the sync block. mPm.mHandler.post( () -> mPm.mInstallerService.mPackageArchiver.notifyUnarchivalListener(status, getInstallerPackageName(), params.appPackageName, requiredStorageBytes, userActionIntent, getUnarchivalListeners(), userId)); if (status != UNARCHIVAL_OK) { Binder.withCleanCallingIdentity(this::abandon); } } @UnarchivalStatus int getUnarchivalStatus() { return this.mUnarchivalStatus; } /** * Free up storage used by this session and its children. * Must not be called on a child session. Loading
services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +3 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,9 @@ public class PackageArchiverTest { anyInt())).thenReturn(1); when(mInstallerService.getExistingDraftSessionId(anyInt(), any(), anyInt())).thenReturn( PackageInstaller.SessionInfo.INVALID_ID); PackageInstallerSession session = mock(PackageInstallerSession.class); when(mInstallerService.getSession(anyInt())).thenReturn(session); when(session.getUnarchivalStatus()).thenReturn(PackageInstaller.UNARCHIVAL_STATUS_UNSET); doReturn(new ParceledListSlice<>(List.of(mock(ResolveInfo.class)))) .when(mPackageManagerService).queryIntentReceivers(any(), any(), any(), anyLong(), eq(mUserId)); Loading