Merge "Verify that only apps with main activities can be archived and remove the need for holding the query_all permission." into main
diff --git a/services/core/java/com/android/server/pm/PackageArchiverService.java b/services/core/java/com/android/server/pm/PackageArchiverService.java
index 1b25d6d..29f49c8 100644
--- a/services/core/java/com/android/server/pm/PackageArchiverService.java
+++ b/services/core/java/com/android/server/pm/PackageArchiverService.java
@@ -61,8 +61,6 @@
*/
public class PackageArchiverService extends IPackageArchiverService.Stub {
- private static final String TAG = "PackageArchiver";
-
/**
* The maximum time granted for an app store to start a foreground service when unarchival
* is requested.
@@ -99,29 +97,45 @@
snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
"archiveApp");
verifyCaller(providedUid, binderUid);
- PackageStateInternal ps = getPackageState(packageName, snapshot, binderUid, userId);
- if (getResponsibleInstallerPackage(ps) == null) {
- throw new ParcelableException(
- new PackageManager.NameNotFoundException(
- TextUtils.formatSimple("No installer found to archive app %s.",
- packageName)));
+ ArchiveState archiveState;
+ try {
+ archiveState = createArchiveState(packageName, userId);
+ // TODO(b/282952870) Should be reverted if uninstall fails/cancels
+ storeArchiveState(packageName, archiveState, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new ParcelableException(e);
}
- // 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/282952870) Bug: should happen after the uninstall completes successfully
- storeArchiveState(ps, mainActivities, userId);
-
// TODO(b/278553670) Add special strings for the delete dialog
mPm.mInstallerService.uninstall(
new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
callerPackageName, DELETE_KEEP_DATA, intentSender, userId);
}
+ private ArchiveState createArchiveState(String packageName, int userId)
+ throws PackageManager.NameNotFoundException {
+ PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(),
+ Binder.getCallingUid(), userId);
+ String responsibleInstallerPackage = getResponsibleInstallerPackage(ps);
+ if (responsibleInstallerPackage == null) {
+ throw new PackageManager.NameNotFoundException(
+ TextUtils.formatSimple("No installer found to archive app %s.",
+ packageName));
+ }
+
+ List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps, userId);
+ List<ArchiveActivityInfo> archiveActivityInfos = new ArrayList<>();
+ for (int i = 0; i < mainActivities.size(); i++) {
+ // TODO(b/278553670) Extract and store launcher icons
+ ArchiveActivityInfo activityInfo = new ArchiveActivityInfo(
+ mainActivities.get(i).getLabel().toString(),
+ Path.of("/TODO"), null);
+ archiveActivityInfos.add(activityInfo);
+ }
+
+ return new ArchiveState(archiveActivityInfos, responsibleInstallerPackage);
+ }
+
@Override
public void requestUnarchive(
@NonNull String packageName,
@@ -138,8 +152,13 @@
snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
"unarchiveApp");
verifyCaller(providedUid, binderUid);
- PackageStateInternal ps = getPackageState(packageName, snapshot, binderUid, userId);
- verifyArchived(ps, userId);
+ PackageStateInternal ps;
+ try {
+ ps = getPackageState(packageName, snapshot, binderUid, userId);
+ verifyArchived(ps, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new ParcelableException(e);
+ }
String installerPackage = getResponsibleInstallerPackage(ps);
if (installerPackage == null) {
throw new ParcelableException(
@@ -151,14 +170,14 @@
mPm.mHandler.post(() -> unarchiveInternal(packageName, userHandle, installerPackage));
}
- private void verifyArchived(PackageStateInternal ps, int userId) {
+ private void verifyArchived(PackageStateInternal ps, int userId)
+ throws PackageManager.NameNotFoundException {
PackageUserStateInternal userState = ps.getUserStateOrDefault(userId);
// TODO(b/288142708) Check for isInstalled false here too.
if (userState.getArchiveState() == null) {
- throw new ParcelableException(
- new PackageManager.NameNotFoundException(
- TextUtils.formatSimple("Package %s is not currently archived.",
- ps.getPackageName())));
+ throw new PackageManager.NameNotFoundException(
+ TextUtils.formatSimple("Package %s is not currently archived.",
+ ps.getPackageName()));
}
}
@@ -196,6 +215,21 @@
/* initialExtras= */ null);
}
+ private List<LauncherActivityInfo> getLauncherActivityInfos(PackageStateInternal ps,
+ int userId) throws PackageManager.NameNotFoundException {
+ List<LauncherActivityInfo> mainActivities =
+ Binder.withCleanCallingIdentity(() -> getLauncherApps().getActivityList(
+ ps.getPackageName(),
+ new UserHandle(userId)));
+ if (mainActivities.isEmpty()) {
+ throw new PackageManager.NameNotFoundException(
+ TextUtils.formatSimple("The app %s does not have a main activity.",
+ ps.getPackageName()));
+ }
+
+ return mainActivities;
+ }
+
@RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
@@ -219,13 +253,13 @@
@NonNull
private static PackageStateInternal getPackageState(String packageName,
- Computer snapshot, int callingUid, int userId) {
+ Computer snapshot, int callingUid, int userId)
+ throws PackageManager.NameNotFoundException {
PackageStateInternal ps = snapshot.getPackageStateFiltered(packageName, callingUid,
userId);
if (ps == null) {
- throw new ParcelableException(
- new PackageManager.NameNotFoundException(
- TextUtils.formatSimple("Package %s not found.", packageName)));
+ throw new PackageManager.NameNotFoundException(
+ TextUtils.formatSimple("Package %s not found.", packageName));
}
return ps;
}
@@ -237,38 +271,25 @@
return mLauncherApps;
}
- private void storeArchiveState(PackageStateInternal ps,
- 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
- ArchiveActivityInfo activityInfo = new ArchiveActivityInfo(
- mainActivities.get(i).getLabel().toString(),
- Path.of("/TODO"), null);
- activityInfos.add(activityInfo);
- }
-
- InstallSource installSource = ps.getInstallSource();
- String installerPackageName = installSource.mUpdateOwnerPackageName != null
- ? installSource.mUpdateOwnerPackageName : installSource.mInstallerPackageName;
-
+ private void storeArchiveState(String packageName, ArchiveState archiveState, int userId)
+ throws PackageManager.NameNotFoundException {
synchronized (mPm.mLock) {
- PackageSetting packageSetting = getPackageSettingLocked(ps.getPackageName(), userId);
+ PackageSetting packageSetting = getPackageSettingLocked(packageName, userId);
packageSetting
.modifyUserState(userId)
- .setArchiveState(new ArchiveState(activityInfos, installerPackageName));
+ .setArchiveState(archiveState);
}
}
@NonNull
@GuardedBy("mPm.mLock")
- private PackageSetting getPackageSettingLocked(String packageName, int userId) {
+ private PackageSetting getPackageSettingLocked(String packageName, int userId)
+ throws PackageManager.NameNotFoundException {
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 ParcelableException(
- new PackageManager.NameNotFoundException(
- TextUtils.formatSimple("Package %s not found.", packageName)));
+ throw new PackageManager.NameNotFoundException(
+ TextUtils.formatSimple("Package %s not found.", packageName));
}
return ps;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
index 473cece..e58a234 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
@@ -47,6 +47,7 @@
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;
@@ -76,7 +77,6 @@
private static final String CALLER_PACKAGE = "com.caller";
private static final String INSTALLER_PACKAGE = "com.installer";
-
@Rule
public final MockSystemRule mMockSystem = new MockSystemRule();
@@ -212,6 +212,20 @@
}
@Test
+ public void archiveApp_noMainActivities() {
+ when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn(
+ List.of());
+
+ Exception e = assertThrows(
+ ParcelableException.class,
+ () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender,
+ UserHandle.CURRENT));
+ assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
+ assertThat(e.getCause()).hasMessageThat().isEqualTo(
+ TextUtils.formatSimple("The app %s does not have a main activity.", PACKAGE));
+ }
+
+ @Test
public void archiveApp_success() {
mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT);