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

Commit 0caddb10 authored by Jakob Schneider's avatar Jakob Schneider Committed by Android (Google) Code Review
Browse files

Merge "Check if installer supports unarchival before archiving." into main

parents 6566cc3d 667a3785
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);
@@ -268,27 +269,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;
@@ -44,6 +45,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;
@@ -122,6 +125,8 @@ public class PackageArchiverTest {

    private PackageSetting mPackageSetting;

    private PackageManagerService mPackageManagerService;

    private PackageArchiver mArchiveManager;

    @Before
@@ -130,7 +135,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,
@@ -154,15 +159,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(
@@ -236,6 +244,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(