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

Commit 399338b3 authored by Chun-Wei Wang's avatar Chun-Wei Wang Committed by Android (Google) Code Review
Browse files

Merge "Move apex-update-allowed check"

parents 9e47c41d 2159d03c
Loading
Loading
Loading
Loading
+0 −42
Original line number Diff line number Diff line
@@ -151,7 +151,6 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -2357,28 +2356,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            return;
        }


        // Check if APEX update is allowed. We do this check in handleInstall, since this is one of
        // the places that:
        //   * Shared between staged and non-staged APEX update flows.
        //   * Only is called after boot completes.
        // The later is important, since isApexUpdateAllowed check depends on the
        // ModuleInfoProvider, which is only populated after device has booted.
        if (isApexSession()) {
            boolean checkApexUpdateAllowed =
                    (params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK)
                        == 0;
            synchronized (mLock) {
                if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName,
                          mInstallSource.installerPackageName)) {
                    onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
                            "Update of APEX package " + mPackageName + " is not allowed for "
                                    + mInstallSource.installerPackageName);
                    return;
                }
            }
        }

        if (params.isStaged) {
            // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even
            //  though ideally, we just need to send session committed broadcast.
@@ -2825,25 +2802,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        return sessionContains((s) -> !s.isApexSession());
    }

    private boolean isApexUpdateAllowed(String apexPackageName, String installerPackageName) {
        if (mPm.getModuleInfo(apexPackageName, 0) != null) {
            final String modulesInstaller =
                    SystemConfig.getInstance().getModulesInstallerPackageName();
            if (modulesInstaller == null) {
                Slog.w(TAG, "No modules installer defined");
                return false;
            }
            return modulesInstaller.equals(installerPackageName);
        }
        final String vendorApexInstaller =
                SystemConfig.getInstance().getAllowedVendorApexes().get(apexPackageName);
        if (vendorApexInstaller == null) {
            Slog.w(TAG, apexPackageName + " is not allowed to be updated");
            return false;
        }
        return vendorApexInstaller.equals(installerPackageName);
    }

    /**
     * Validate apex install.
     * <p>
+48 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.util.apk.ApkSignatureVerifier;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageHelper;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.rollback.RollbackManagerInternal;
@@ -99,9 +100,11 @@ final class PackageSessionVerifier {
                storeSession(session.mStagedSession);
                if (session.isMultiPackage()) {
                    for (PackageInstallerSession child : session.getChildSessions()) {
                        checkApexUpdateAllowed(child);
                        checkRebootlessApex(child);
                    }
                } else {
                    checkApexUpdateAllowed(session);
                    checkRebootlessApex(session);
                }
                verifyAPK(session, callback);
@@ -461,6 +464,51 @@ final class PackageSessionVerifier {
        return mApexManager.abortStagedSession(sessionId);
    }

    private boolean isApexUpdateAllowed(String apexPackageName, String installerPackageName) {
        if (mPm.getModuleInfo(apexPackageName, 0) != null) {
            final String modulesInstaller =
                    SystemConfig.getInstance().getModulesInstallerPackageName();
            if (modulesInstaller == null) {
                Slog.w(TAG, "No modules installer defined");
                return false;
            }
            return modulesInstaller.equals(installerPackageName);
        }
        final String vendorApexInstaller =
                SystemConfig.getInstance().getAllowedVendorApexes().get(apexPackageName);
        if (vendorApexInstaller == null) {
            Slog.w(TAG, apexPackageName + " is not allowed to be updated");
            return false;
        }
        return vendorApexInstaller.equals(installerPackageName);
    }

    /**
     * Checks if APEX update is allowed.
     *
     * This phase is shared between staged and non-staged sessions and should be called after
     * boot is completed since this check depends on the ModuleInfoProvider, which is only populated
     * after device has booted.
     */
    private void checkApexUpdateAllowed(PackageInstallerSession session)
            throws PackageManagerException {
        if (!session.isApexSession()) {
            return;
        }
        final int installFlags = session.params.installFlags;
        if ((installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK) != 0) {
            return;
        }
        final String packageName = session.getPackageName();
        final String installerPackageName = session.getInstallSource().installerPackageName;
        if (!isApexUpdateAllowed(packageName, installerPackageName)) {
            throw new PackageManagerException(
                    PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
                    "Update of APEX package " + packageName + " is not allowed for "
                            + installerPackageName);
        }
    }

    /**
     * Fails this rebootless APEX session if the same package name found in any staged sessions.
     */
+24 −12
Original line number Diff line number Diff line
@@ -303,11 +303,14 @@ public class StagedInstallInternalTest {
        assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
        TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
                /* isApex= */ true, "test.rebootless_apex_v2.apex");
        String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed "
                + "for com.android.tests.stagedinstallinternal";
        InstallUtils.commitExpectingFailure(
                AssertionError.class,
                "Update of APEX package test.apex.rebootless is not allowed "
                        + "for com.android.tests.stagedinstallinternal",
                AssertionError.class, expectedFailMessage,
                Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
        InstallUtils.commitExpectingFailure(
                AssertionError.class, expectedFailMessage,
                Install.multi(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
    }

    @Test
@@ -315,11 +318,14 @@ public class StagedInstallInternalTest {
        assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
        TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
                /* isApex= */ true, "test.rebootless_apex_v2.apex");
        String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed "
                + "for com.android.tests.stagedinstallinternal";
        InstallUtils.commitExpectingFailure(
                AssertionError.class,
                "Update of APEX package test.apex.rebootless is not allowed "
                        + "for com.android.tests.stagedinstallinternal",
                AssertionError.class, expectedFailMessage,
                Install.single(apex).setBypassAllowedApexUpdateCheck(false));
        InstallUtils.commitExpectingFailure(
                AssertionError.class, expectedFailMessage,
                Install.multi(apex).setBypassAllowedApexUpdateCheck(false));
    }

    @Test
@@ -327,11 +333,14 @@ public class StagedInstallInternalTest {
        assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
        TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
                /* isApex= */ true, "test.rebootless_apex_v2.apex");
        String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed "
                + "for com.android.tests.stagedinstallinternal";
        InstallUtils.commitExpectingFailure(
                AssertionError.class,
                "Update of APEX package test.apex.rebootless is not allowed "
                        + "for com.android.tests.stagedinstallinternal",
                AssertionError.class, expectedFailMessage,
                Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
        InstallUtils.commitExpectingFailure(
                AssertionError.class, expectedFailMessage,
                Install.multi(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
    }

    @Test
@@ -339,11 +348,14 @@ public class StagedInstallInternalTest {
        assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
        TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
                /* isApex= */ true, "test.rebootless_apex_v2.apex");
        String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed "
                + "for com.android.tests.stagedinstallinternal";
        InstallUtils.commitExpectingFailure(
                AssertionError.class,
                "Update of APEX package test.apex.rebootless is not allowed "
                        + "for com.android.tests.stagedinstallinternal",
                AssertionError.class, expectedFailMessage,
                Install.single(apex).setBypassAllowedApexUpdateCheck(false));
        InstallUtils.commitExpectingFailure(
                AssertionError.class, expectedFailMessage,
                Install.multi(apex).setBypassAllowedApexUpdateCheck(false));
    }

    @Test