diff options
12 files changed, 261 insertions, 79 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 61415839ea2c..3e4b98dcc213 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3790,6 +3790,10 @@ package android.content.pm { field @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) public static final int FLAG_GET_PERSONS_DATA = 2048; // 0x800 } + public class PackageArchiver { + method @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void requestArchive(@NonNull String, @NonNull android.content.IntentSender) throws android.content.pm.PackageManager.NameNotFoundException; + } + public class PackageInstaller { method @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull java.io.File, int) throws android.content.pm.PackageInstaller.PackageParsingException; method @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull android.os.ParcelFileDescriptor, @Nullable String, int) throws android.content.pm.PackageInstaller.PackageParsingException; @@ -3887,6 +3891,7 @@ package android.content.pm { method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps(); method @Deprecated @NonNull public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(@NonNull String); method @Deprecated @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(@NonNull String, int); + method @NonNull public android.content.pm.PackageArchiver getPackageArchiver(); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public int getPackageUidAsUser(@NonNull String, @NonNull android.content.pm.PackageManager.PackageInfoFlags, int) throws android.content.pm.PackageManager.NameNotFoundException; method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] getUnsuspendablePackages(@NonNull String[]); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 02558602acd3..fcd13b840cb1 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -64,6 +64,7 @@ import android.content.pm.InstrumentationInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.KeySet; import android.content.pm.ModuleInfo; +import android.content.pm.PackageArchiver; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageItemInfo; @@ -172,6 +173,7 @@ public class ApplicationPackageManager extends PackageManager { private volatile UserManager mUserManager; private volatile PermissionManager mPermissionManager; private volatile PackageInstaller mInstaller; + private volatile PackageArchiver mPackageArchiver; private volatile ArtManager mArtManager; private volatile DevicePolicyManager mDevicePolicyManager; private volatile String mPermissionsControllerPackageName; @@ -3282,6 +3284,18 @@ public class ApplicationPackageManager extends PackageManager { } @Override + public PackageArchiver getPackageArchiver() { + if (mPackageArchiver == null) { + try { + mPackageArchiver = new PackageArchiver(mContext, mPM.getPackageArchiverService()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return mPackageArchiver; + } + + @Override public boolean isPackageAvailable(String packageName) { try { return mPM.isPackageAvailable(packageName, getUserId()); diff --git a/core/java/android/content/pm/IPackageArchiverService.aidl b/core/java/android/content/pm/IPackageArchiverService.aidl new file mode 100644 index 000000000000..fc471c451370 --- /dev/null +++ b/core/java/android/content/pm/IPackageArchiverService.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.content.pm; + +import android.content.IntentSender; +import android.os.UserHandle; + +/** {@hide} */ +interface IPackageArchiverService { + + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES,android.Manifest.permission.REQUEST_DELETE_PACKAGES})") + void requestArchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle); +}
\ No newline at end of file diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index ea0f5ff2896e..4ed4dd3c015a 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -25,6 +25,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ChangedPackages; import android.content.pm.InstantAppInfo; import android.content.pm.FeatureInfo; +import android.content.pm.IPackageArchiverService; import android.content.pm.IDexModuleRegisterCallback; import android.content.pm.InstallSourceInfo; import android.content.pm.IOnChecksumsReadyListener; @@ -650,6 +651,8 @@ interface IPackageManager { @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) IPackageInstaller getPackageInstaller(); + IPackageArchiverService getPackageArchiverService(); + @EnforcePermission("DELETE_PACKAGES") boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId); @UnsupportedAppUsage diff --git a/core/java/android/content/pm/PackageArchiver.java b/core/java/android/content/pm/PackageArchiver.java new file mode 100644 index 000000000000..d739d5054800 --- /dev/null +++ b/core/java/android/content/pm/PackageArchiver.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.content.IntentSender; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.ParcelableException; +import android.os.RemoteException; + +/** + * {@code ArchiveManager} is used to archive apps. During the archival process, the apps APKs and + * cache are removed from the device while the user data is kept. Through the + * {@code requestUnarchive()} call, apps can be restored again through their responsible app store. + * + * <p> Archived apps are returned as displayable apps through the {@link LauncherApps} APIs and + * will be displayed to users with UI treatment to highlight that said apps are archived. If + * a user taps on an archived app, the app will be unarchived and the restoration process is + * communicated. + * + * @hide + */ +// TODO(b/278560219) Improve public documentation. +@SystemApi +public class PackageArchiver { + + private final Context mContext; + private final IPackageArchiverService mService; + + /** + * @hide + */ + public PackageArchiver(Context context, IPackageArchiverService service) { + mContext = context; + mService = service; + } + + /** + * Requests to archive a package which is currently installed. + * + * @param statusReceiver Callback used to notify when the operation is completed. + * @throws NameNotFoundException If {@code packageName} isn't found or not available to the + * caller. + * @hide + */ + @RequiresPermission(anyOf = { + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.REQUEST_DELETE_PACKAGES}) + @SystemApi + public void requestArchive(@NonNull String packageName, @NonNull IntentSender statusReceiver) + throws NameNotFoundException { + try { + mService.requestArchive(packageName, mContext.getPackageName(), statusReceiver, + mContext.getUser()); + } catch (ParcelableException e) { + e.maybeRethrow(NameNotFoundException.class); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 885e67e1a8c8..d2173a6d44bd 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -9934,6 +9934,16 @@ public abstract class PackageManager { public abstract @NonNull PackageInstaller getPackageInstaller(); /** + * {@link PackageArchiver} can be used to archive and restore archived packages. + * + * @hide + */ + @SystemApi + public @NonNull PackageArchiver getPackageArchiver() { + throw new UnsupportedOperationException( + "getPackageArchiver not implemented in subclass"); + } + /** * Adds a {@code CrossProfileIntentFilter}. After calling this method all * intents sent from the user with id sourceUserId can also be be resolved * by activities in the user with id targetUserId if they match the diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index 76203ac7650d..8f7b7217d005 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -30,6 +30,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageArchiverService; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageDeleteObserver2; import android.content.pm.IPackageInstaller; @@ -99,6 +100,9 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { private final PackageInstallerService mInstallerService; @NonNull + private final PackageArchiverService mPackageArchiverService; + + @NonNull private final PackageProperty mPackageProperty; @NonNull @@ -127,7 +131,8 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { @Nullable ComponentName instantAppResolverSettingsComponent, @NonNull String requiredSupplementalProcessPackage, @Nullable String servicesExtensionPackageName, - @Nullable String sharedSystemSharedLibraryPackageName) { + @Nullable String sharedSystemSharedLibraryPackageName, + @NonNull PackageArchiverService packageArchiverService) { mService = service; mContext = context; mDexOptHelper = dexOptHelper; @@ -143,6 +148,7 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { mRequiredSupplementalProcessPackage = requiredSupplementalProcessPackage; mServicesExtensionPackageName = servicesExtensionPackageName; mSharedSystemSharedLibraryPackageName = sharedSystemSharedLibraryPackageName; + mPackageArchiverService = packageArchiverService; } protected Computer snapshot() { @@ -616,6 +622,12 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { @Override @Deprecated + public final IPackageArchiverService getPackageArchiverService() { + return mPackageArchiverService; + } + + @Override + @Deprecated public final void getPackageSizeInfo(final String packageName, int userId, final IPackageStatsObserver observer) { throw new UnsupportedOperationException( diff --git a/services/core/java/com/android/server/pm/ArchiveManager.java b/services/core/java/com/android/server/pm/PackageArchiverService.java index 54352060cd38..9c31dc9a1215 100644 --- a/services/core/java/com/android/server/pm/ArchiveManager.java +++ b/services/core/java/com/android/server/pm/PackageArchiverService.java @@ -22,11 +22,13 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.IntentSender; +import android.content.pm.IPackageArchiverService; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; import android.os.Binder; +import android.os.ParcelableException; import android.os.UserHandle; import android.text.TextUtils; @@ -47,7 +49,9 @@ import java.util.Objects; * while the data directory is kept. Archived apps are included in the list of launcher apps where * tapping them re-installs the full app. */ -final class ArchiveManager { +public class PackageArchiverService extends IPackageArchiverService.Stub { + + private static final String TAG = "PackageArchiver"; private final Context mContext; private final PackageManagerService mPm; @@ -55,36 +59,39 @@ final class ArchiveManager { @Nullable private LauncherApps mLauncherApps; - ArchiveManager(Context context, PackageManagerService mPm) { + public PackageArchiverService(Context context, PackageManagerService mPm) { this.mContext = context; this.mPm = mPm; } - void archiveApp( + @Override + public void requestArchive( @NonNull String packageName, @NonNull String callerPackageName, - @NonNull UserHandle user, - @NonNull IntentSender intentSender) throws PackageManager.NameNotFoundException { + @NonNull IntentSender intentSender, + @NonNull UserHandle userHandle) { Objects.requireNonNull(packageName); Objects.requireNonNull(callerPackageName); - Objects.requireNonNull(user); Objects.requireNonNull(intentSender); + Objects.requireNonNull(userHandle); Computer snapshot = mPm.snapshotComputer(); - int callingUid = Binder.getCallingUid(); - int userId = user.getIdentifier(); - String callingPackageName = snapshot.getNameForUid(callingUid); - snapshot.enforceCrossUserPermission(callingUid, userId, true, true, + int userId = userHandle.getIdentifier(); + int binderUid = Binder.getCallingUid(); + int providedUid = snapshot.getPackageUid(callerPackageName, 0, userId); + snapshot.enforceCrossUserPermission(binderUid, userId, true, true, "archiveApp"); - verifyCaller(callerPackageName, callingPackageName); - PackageStateInternal ps = getPackageState(packageName, snapshot, callingUid, user); - verifyInstaller(packageName, ps.getInstallSource()); + verifyCaller(providedUid, binderUid); + PackageStateInternal ps = getPackageState(packageName, snapshot, binderUid, userId); + verifyInstaller(packageName, ps); + // TODO(b/291569242) Verify that this list is not empty and return failure with + // intentsender List<LauncherActivityInfo> mainActivities = getLauncherApps().getActivityList( ps.getPackageName(), new UserHandle(userId)); - // TODO(b/291569242) Verify that this list is not empty and return failure with intentsender + // TODO(b/282952870) Bug: should happen after the uninstall completes successfully storeArchiveState(ps, mainActivities, userId); // TODO(b/278553670) Add special strings for the delete dialog @@ -93,15 +100,25 @@ final class ArchiveManager { callerPackageName, DELETE_KEEP_DATA, intentSender, userId); } + private static void verifyInstaller(String packageName, PackageStateInternal ps) { + if (ps.getInstallSource().mUpdateOwnerPackageName == null + && ps.getInstallSource().mInstallerPackageName == null) { + throw new ParcelableException( + new PackageManager.NameNotFoundException( + TextUtils.formatSimple("No installer found to archive app %s.", + packageName))); + } + } + @NonNull private static PackageStateInternal getPackageState(String packageName, - Computer snapshot, int callingUid, UserHandle user) - throws PackageManager.NameNotFoundException { + Computer snapshot, int callingUid, int userId) { PackageStateInternal ps = snapshot.getPackageStateFiltered(packageName, callingUid, - user.getIdentifier()); + userId); if (ps == null) { - throw new PackageManager.NameNotFoundException( - TextUtils.formatSimple("Package %s not found.", packageName)); + throw new ParcelableException( + new PackageManager.NameNotFoundException( + TextUtils.formatSimple("Package %s not found.", packageName))); } return ps; } @@ -114,8 +131,7 @@ final class ArchiveManager { } private void storeArchiveState(PackageStateInternal ps, - List<LauncherActivityInfo> mainActivities, int userId) - throws PackageManager.NameNotFoundException { + List<LauncherActivityInfo> mainActivities, int userId) { List<ArchiveActivityInfo> activityInfos = new ArrayList<>(); for (int i = 0; i < mainActivities.size(); i++) { // TODO(b/278553670) Extract and store launcher icons @@ -130,41 +146,34 @@ final class ArchiveManager { ? installSource.mUpdateOwnerPackageName : installSource.mInstallerPackageName; synchronized (mPm.mLock) { - getPackageSetting(ps.getPackageName(), userId).modifyUserState(userId).setArchiveState( - new ArchiveState(activityInfos, installerPackageName)); + PackageSetting packageSetting = getPackageSettingLocked(ps.getPackageName(), userId); + packageSetting + .modifyUserState(userId) + .setArchiveState(new ArchiveState(activityInfos, installerPackageName)); } } @NonNull @GuardedBy("mPm.mLock") - private PackageSetting getPackageSetting(String packageName, int userId) - throws PackageManager.NameNotFoundException { + private PackageSetting getPackageSettingLocked(String packageName, int userId) { PackageSetting ps = mPm.mSettings.getPackageLPr(packageName); + // Shouldn't happen, we already verify presence of the package in getPackageState() if (ps == null || !ps.getUserStateOrDefault(userId).isInstalled()) { - throw new PackageManager.NameNotFoundException( - TextUtils.formatSimple("Package %s not found.", packageName)); + throw new ParcelableException( + new PackageManager.NameNotFoundException( + TextUtils.formatSimple("Package %s not found.", packageName))); } return ps; } - private static void verifyCaller(String callerPackageName, String callingPackageName) { - if (!TextUtils.equals(callingPackageName, callerPackageName)) { + private static void verifyCaller(int providedUid, int binderUid) { + if (providedUid != binderUid) { throw new SecurityException( TextUtils.formatSimple( - "The callerPackageName %s set by the caller doesn't match the " - + "caller's own package name %s.", - callerPackageName, - callingPackageName)); - } - } - - private static void verifyInstaller(String packageName, InstallSource installSource) { - // TODO(b/291060290) Verify installer supports unarchiving - if (installSource.mUpdateOwnerPackageName == null - && installSource.mInstallerPackageName == null) { - throw new SecurityException( - TextUtils.formatSimple("No installer found to archive app %s.", - packageName)); + "The UID %s of callerPackageName set by the caller doesn't match the " + + "caller's actual UID %s.", + providedUid, + binderUid)); } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 6c0aeecbf68b..3af4d0d75c8a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -796,6 +796,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService final PackageInstallerService mInstallerService; + final PackageArchiverService mArchiverService; + final ArtManagerService mArtManagerService; // TODO(b/260124949): Remove these. @@ -1624,7 +1626,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService (i, pm) -> new CrossProfileIntentFilterHelper(i.getSettings(), i.getUserManagerService(), i.getLock(), i.getUserManagerInternal(), context), - (i, pm) -> new UpdateOwnershipHelper()); + (i, pm) -> new UpdateOwnershipHelper(), + (i, pm) -> new PackageArchiverService(i.getContext(), pm)); if (Build.VERSION.SDK_INT <= 0) { Slog.w(TAG, "**** ro.build.version.sdk not set!"); @@ -1769,6 +1772,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService mFactoryTest = testParams.factoryTest; mIncrementalManager = testParams.incrementalManager; mInstallerService = testParams.installerService; + mArchiverService = testParams.archiverService; mInstantAppRegistry = testParams.instantAppRegistry; mChangedPackagesTracker = testParams.changedPackagesTracker; mInstantAppResolverConnection = testParams.instantAppResolverConnection; @@ -2348,6 +2352,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService }); mInstallerService = mInjector.getPackageInstallerService(); + mArchiverService = mInjector.getPackageArchiverService(); final ComponentName instantAppResolverComponent = getInstantAppResolver(computer); if (instantAppResolverComponent != null) { if (DEBUG_INSTANT) { @@ -4608,7 +4613,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService mDomainVerificationConnection, mInstallerService, mPackageProperty, mResolveComponentName, mInstantAppResolverSettingsComponent, mRequiredSdkSandboxPackage, mServicesExtensionPackageName, - mSharedSystemSharedLibraryPackageName); + mSharedSystemSharedLibraryPackageName, mArchiverService); } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java index 51840e70ed26..9495279c65b8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java @@ -127,6 +127,8 @@ public class PackageManagerServiceInjector { mPreparingPackageParserProducer; private final Singleton<PackageInstallerService> mPackageInstallerServiceProducer; + private final Singleton<PackageArchiverService> + mPackageArchiverServiceProducer; private final ProducerWithArgument<InstantAppResolverConnection, ComponentName> mInstantAppResolverConnectionProducer; private final Singleton<LegacyPermissionManagerInternal> @@ -185,7 +187,8 @@ public class PackageManagerServiceInjector { Producer<IBackupManager> iBackupManager, Producer<SharedLibrariesImpl> sharedLibrariesProducer, Producer<CrossProfileIntentFilterHelper> crossProfileIntentFilterHelperProducer, - Producer<UpdateOwnershipHelper> updateOwnershipHelperProducer) { + Producer<UpdateOwnershipHelper> updateOwnershipHelperProducer, + Producer<PackageArchiverService> packageArchiverServiceProducer) { mContext = context; mLock = lock; mInstaller = installer; @@ -241,6 +244,7 @@ public class PackageManagerServiceInjector { mCrossProfileIntentFilterHelperProducer = new Singleton<>( crossProfileIntentFilterHelperProducer); mUpdateOwnershipHelperProducer = new Singleton<>(updateOwnershipHelperProducer); + mPackageArchiverServiceProducer = new Singleton<>(packageArchiverServiceProducer); } /** @@ -387,6 +391,10 @@ public class PackageManagerServiceInjector { return mPackageInstallerServiceProducer.get(this, mPackageManager); } + public PackageArchiverService getPackageArchiverService() { + return mPackageArchiverServiceProducer.get(this, mPackageManager); + } + public InstantAppResolverConnection getInstantAppResolverConnection( ComponentName instantAppResolverComponent) { return mInstantAppResolverConnectionProducer.produce( diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java index ca572091486e..b91ce4be8ca1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java @@ -60,6 +60,7 @@ public final class PackageManagerServiceTestParams { public @Nullable String incidentReportApproverPackage; public IncrementalManager incrementalManager; public PackageInstallerService installerService; + public PackageArchiverService archiverService; public InstantAppRegistry instantAppRegistry; public ChangedPackagesTracker changedPackagesTracker = new ChangedPackagesTracker(); public InstantAppResolverConnection instantAppResolverConnection; diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ArchiveManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java index a8b0a7b5633d..c7e1bda2e1b8 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/ArchiveManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java @@ -37,10 +37,9 @@ import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; import android.os.Binder; import android.os.Build; -import android.os.Process; +import android.os.ParcelableException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; -import android.text.TextUtils; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -62,7 +61,7 @@ import java.util.List; @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) -public class ArchiveManagerTest { +public class PackageArchiverServiceTest { private static final String PACKAGE = "com.example"; private static final String CALLER_PACKAGE = "com.vending"; @@ -95,10 +94,11 @@ public class ArchiveManagerTest { private final List<LauncherActivityInfo> mLauncherActivityInfos = createLauncherActivities(); + private final int mUserId = UserHandle.CURRENT.getIdentifier(); + private PackageSetting mPackageSetting; - private PackageManagerService mPm; - private ArchiveManager mArchiveManager; + private PackageArchiverService mArchiveService; @Before public void setUp() throws Exception { @@ -106,7 +106,7 @@ public class ArchiveManagerTest { mMockSystem.system().stageNominalSystemState(); when(mMockSystem.mocks().getInjector().getPackageInstallerService()).thenReturn( mInstallerService); - mPm = spy(new PackageManagerService(mMockSystem.mocks().getInjector(), + PackageManagerService pm = spy(new PackageManagerService(mMockSystem.mocks().getInjector(), /* factoryTest= */false, MockSystem.Companion.getDEFAULT_VERSION_INFO().fingerprint, /* isEngBuild= */ false, @@ -124,37 +124,42 @@ public class ArchiveManagerTest { when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps); when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn( mLauncherActivityInfos); - doReturn(mComputer).when(mPm).snapshotComputer(); - when(mComputer.getNameForUid(eq(Binder.getCallingUid()))).thenReturn(CALLER_PACKAGE); - mArchiveManager = new ArchiveManager(mContext, mPm); + doReturn(mComputer).when(pm).snapshotComputer(); + when(mComputer.getPackageUid(eq(CALLER_PACKAGE), eq(0L), eq(mUserId))).thenReturn( + Binder.getCallingUid()); + mArchiveService = new PackageArchiverService(mContext, pm); } @Test public void archiveApp_callerPackageNameIncorrect() { Exception e = assertThrows( SecurityException.class, - () -> mArchiveManager.archiveApp(PACKAGE, "different", UserHandle.CURRENT, - mIntentSender) + () -> mArchiveService.requestArchive(PACKAGE, "different", mIntentSender, + UserHandle.CURRENT + ) ); assertThat(e).hasMessageThat().isEqualTo( String.format( - "The callerPackageName %s set by the caller doesn't match the " - + "caller's own package name %s.", - "different", - CALLER_PACKAGE)); + "The UID %s of callerPackageName set by the caller doesn't match the " + + "caller's actual UID %s.", + 0, + Binder.getCallingUid())); } @Test public void archiveApp_packageNotInstalled() { - when(mMockSystem.mocks().getSettings().getPackageLPr(eq(PACKAGE))).thenReturn( + when(mComputer.getPackageStateFiltered(eq(PACKAGE), anyInt(), anyInt())).thenReturn( null); Exception e = assertThrows( - PackageManager.NameNotFoundException.class, - () -> mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, UserHandle.CURRENT, - mIntentSender) + ParcelableException.class, + () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, + UserHandle.CURRENT + ) ); - assertThat(e).hasMessageThat().isEqualTo(String.format("Package %s not found.", PACKAGE)); + assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); + assertThat(e.getCause()).hasMessageThat().isEqualTo( + String.format("Package %s not found.", PACKAGE)); } @Test @@ -162,11 +167,14 @@ public class ArchiveManagerTest { mPackageSetting.modifyUserState(UserHandle.CURRENT.getIdentifier()).setInstalled(false); Exception e = assertThrows( - PackageManager.NameNotFoundException.class, - () -> mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, UserHandle.CURRENT, - mIntentSender) + ParcelableException.class, + () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, + UserHandle.CURRENT + ) ); - assertThat(e).hasMessageThat().isEqualTo(String.format("Package %s not found.", PACKAGE)); + assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); + assertThat(e.getCause()).hasMessageThat().isEqualTo( + String.format("Package %s not found.", PACKAGE)); } @Test @@ -183,17 +191,18 @@ public class ArchiveManagerTest { when(mPackageState.getInstallSource()).thenReturn(otherInstallSource); Exception e = assertThrows( - SecurityException.class, - () -> mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, Process.myUserHandle(), - mIntentSender) + ParcelableException.class, + () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, + UserHandle.CURRENT + ) ); - assertThat(e).hasMessageThat().isEqualTo( - TextUtils.formatSimple("No installer found to archive app %s.", - PACKAGE)); + assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); + assertThat(e.getCause()).hasMessageThat().isEqualTo( + String.format("No installer found to archive app %s.", PACKAGE)); } @Test - public void archiveApp_success() throws PackageManager.NameNotFoundException { + public void archiveApp_success() { List<ArchiveState.ArchiveActivityInfo> activityInfos = new ArrayList<>(); for (LauncherActivityInfo mainActivity : createLauncherActivities()) { // TODO(b/278553670) Extract and store launcher icons @@ -203,7 +212,8 @@ public class ArchiveManagerTest { activityInfos.add(activityInfo); } - mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, UserHandle.CURRENT, mIntentSender); + mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); + verify(mInstallerService).uninstall( eq(new VersionedPackage(PACKAGE, PackageManager.VERSION_CODE_HIGHEST)), eq(CALLER_PACKAGE), eq(DELETE_KEEP_DATA), eq(mIntentSender), |