Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 667a3785 authored by Jakob Schneider's avatar Jakob Schneider
Browse files

Check if installer supports unarchival before archiving.

Bug: 291060290
Test: PackageInstallerArchiveTest
Change-Id: I075ada858430cd45f588fc89184bd49601bcec5e
parent 15c2cf07
Loading
Loading
Loading
Loading
+21 −13
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.VersionedPackage;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -48,6 +50,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelableException;
import android.os.Process;
import android.os.SELinux;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -162,15 +165,13 @@ public class PackageArchiver {
                        });
    }

    /**
     * Creates archived state for the package and user.
     */
    public CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId)
    /** 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(),
                Binder.getCallingUid(), userId);
        String responsibleInstallerPackage = getResponsibleInstallerPackage(ps);
        verifyInstaller(responsibleInstallerPackage);
        verifyInstaller(responsibleInstallerPackage, userId);

        List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps.getPackageName(),
                userId);
@@ -260,27 +261,34 @@ public class PackageArchiver {
        return iconFile.toPath();
    }

    private void verifyInstaller(String installerPackage)
    private void verifyInstaller(String installerPackage, int userId)
            throws PackageManager.NameNotFoundException {
        if (TextUtils.isEmpty(installerPackage)) {
            throw new PackageManager.NameNotFoundException("No installer found");
        }
        if (!verifySupportsUnarchival(installerPackage)) {
        // Allow shell for easier development.
        if ((Binder.getCallingUid() != Process.SHELL_UID)
                && !verifySupportsUnarchival(installerPackage, userId)) {
            throw new PackageManager.NameNotFoundException("Installer does not support unarchival");
        }
    }

    /**
     * @return true if installerPackage support unarchival:
     * - has an action Intent.ACTION_UNARCHIVE_PACKAGE,
     * - has permissions to install packages.
     * Returns true if {@code installerPackage} supports unarchival being able to handle
     * {@link Intent#ACTION_UNARCHIVE_PACKAGE}
     */
    public boolean verifySupportsUnarchival(String installerPackage) {
        // TODO(b/278553670) Check if installerPackage supports unarchival.
    public boolean verifySupportsUnarchival(String installerPackage, int userId) {
        if (TextUtils.isEmpty(installerPackage)) {
            return false;
        }
        return true;

        Intent intent = new Intent(Intent.ACTION_UNARCHIVE_PACKAGE).setPackage(installerPackage);

        ParceledListSlice<ResolveInfo> intentReceivers =
                Binder.withCleanCallingIdentity(
                        () -> mPm.queryIntentReceivers(mPm.snapshotComputer(),
                                intent, /* resolvedType= */ null, /* flags= */ 0, userId));
        return intentReceivers != null && !intentReceivers.getList().isEmpty();
    }

    void requestUnarchive(
+1 −1
Original line number Diff line number Diff line
@@ -3445,7 +3445,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            }

            if (!mPm.mInstallerService.mPackageArchiver.verifySupportsUnarchival(
                    getInstallSource().mInstallerPackageName)) {
                    getInstallSource().mInstallerPackageName, userId)) {
                throw new PackageManagerException(
                        PackageManager.INSTALL_FAILED_SESSION_INVALID,
                        "Installer has to support unarchival in order to install archived "
+26 −3
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doReturn;
@@ -43,6 +44,8 @@ import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.VersionedPackage;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -121,6 +124,8 @@ public class PackageArchiverTest {

    private PackageSetting mPackageSetting;

    private PackageManagerService mPackageManagerService;

    private PackageArchiver mArchiveManager;

    @Before
@@ -129,7 +134,7 @@ public class PackageArchiverTest {
        rule.system().stageNominalSystemState();
        when(rule.mocks().getInjector().getPackageInstallerService()).thenReturn(
                mInstallerService);
        PackageManagerService pm = spy(new PackageManagerService(rule.mocks().getInjector(),
        mPackageManagerService = spy(new PackageManagerService(rule.mocks().getInjector(),
                /* factoryTest= */false,
                MockSystem.Companion.getDEFAULT_VERSION_INFO().fingerprint,
                /* isEngBuild= */ false,
@@ -153,15 +158,18 @@ public class PackageArchiverTest {
        when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps);
        when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn(
                mLauncherActivityInfos);
        doReturn(mComputer).when(pm).snapshotComputer();
        doReturn(mComputer).when(mPackageManagerService).snapshotComputer();
        when(mComputer.getPackageUid(eq(CALLER_PACKAGE), eq(0L), eq(mUserId))).thenReturn(
                Binder.getCallingUid());

        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        when(mPackageManager.getResourcesForApplication(eq(PACKAGE))).thenReturn(
                mock(Resources.class));
        doReturn(new ParceledListSlice<>(List.of(mock(ResolveInfo.class))))
                .when(mPackageManagerService).queryIntentReceivers(any(), any(), any(), anyLong(),
                        eq(mUserId));

        mArchiveManager = spy(new PackageArchiver(mContext, pm));
        mArchiveManager = spy(new PackageArchiver(mContext, mPackageManagerService));
        doReturn(ICON_PATH).when(mArchiveManager).storeIcon(eq(PACKAGE),
                any(LauncherActivityInfo.class), eq(mUserId), anyInt());
        doReturn(mIcon).when(mArchiveManager).decodeIcon(
@@ -235,6 +243,21 @@ public class PackageArchiverTest {
        assertThat(e.getCause()).hasMessageThat().isEqualTo("No installer found");
    }

    @Test
    public void archiveApp_installerDoesntSupportUnarchival() {
        doReturn(new ParceledListSlice<>(List.of()))
                .when(mPackageManagerService).queryIntentReceivers(any(), any(), any(), anyLong(),
                        eq(mUserId));

        Exception e = assertThrows(
                ParcelableException.class,
                () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender,
                        UserHandle.CURRENT));
        assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
        assertThat(e.getCause()).hasMessageThat().isEqualTo(
                "Installer does not support unarchival");
    }

    @Test
    public void archiveApp_noMainActivities() {
        when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn(