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

Commit f1f0ff9f authored by Shrinidhi Hegde's avatar Shrinidhi Hegde
Browse files

Rollback during bootloop

In V as part of improvements to Rescue Party we added a mitigation to
try rolling back GMS core in response to bootloop. But during testing we
realized that RollbackPackageHealthObserver isnt even initialized when
noteBoot is called. On further testing we found out that none of the
existing mitigations were actually working for Rescue party where
noteBoot is currently called. So we decided to move RescueParty
initialization to much later in the boot process so that, if
system_server doesnt crash till then, Rescue party would get an
opportunity to apply mitigations.

When we tried rollback during boot, package varification would fail
because its too early in the initialization for it to work. Since
rollback wouldnt really need a package verification, we have disabled
package verification for rollback scenario. After this was fixed, found
that dexOpt was taking too long and watchdog would kill the thread that
was installing GMS core. To get through installation in emergency
scenarios disabled dexOpt for rollbacks.

Test: manual
Bug: 291137901
Change-Id: Ic46643525e28db9470a7ba0139cfba8526b4842d
parent cee37bf9
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApexStagedEvent;
import android.content.pm.Flags;
import android.content.pm.IPackageManagerNative;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageManager;
@@ -766,6 +767,10 @@ public final class DexOptHelper {
        final PackageSetting ps = installRequest.getScannedPackageSetting();
        final AndroidPackage pkg = ps.getPkg();
        final boolean onIncremental = isIncrementalPath(ps.getPathString());
        final boolean performDexOptForRollback = Flags.recoverabilityDetection()
                ? !(installRequest.isRollback()
                && installRequest.getInstallSource().mInitiatingPackageName.equals("android"))
                : true;

        return (!instantApp || Global.getInt(context.getContentResolver(),
                Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
@@ -773,7 +778,8 @@ public final class DexOptHelper {
                && !pkg.isDebuggable()
                && (!onIncremental)
                && dexoptOptions.isCompilationEnabled()
                && !isApex;
                && !isApex
                && performDexOptForRollback;
    }

    private static class StagedApexObserver extends IStagedApexObserver.Stub {
+11 −1
Original line number Diff line number Diff line
@@ -141,6 +141,8 @@ final class VerifyingSession {
    @NonNull
    private final PackageManagerService mPm;

    private final int mInstallReason;

    VerifyingSession(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
            PackageInstaller.SessionParams sessionParams, InstallSource installSource,
            int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite,
@@ -168,6 +170,7 @@ final class VerifyingSession {
        mUserActionRequiredType = sessionParams.requireUserAction;
        mIsInherit = sessionParams.mode == MODE_INHERIT_EXISTING;
        mIsStaged = sessionParams.isStaged;
        mInstallReason = sessionParams.installReason;
    }

    @Override
@@ -190,7 +193,9 @@ final class VerifyingSession {
        // Perform package verification and enable rollback (unless we are simply moving the
        // package).
        if (!mOriginInfo.mExisting) {
            if (!isApex() && !isArchivedInstallation()) {
            final boolean verifyForRollback = Flags.recoverabilityDetection()
                    ? !isARollback() : true;
            if (!isApex() && !isArchivedInstallation() && verifyForRollback) {
                // TODO(b/182426975): treat APEX as APK when APK verification is concerned
                sendApkVerificationRequest(pkgLite);
            }
@@ -200,6 +205,11 @@ final class VerifyingSession {
        }
    }

    private boolean isARollback() {
        return mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK
                && mInstallSource.mInitiatingPackageName.equals("android");
    }

    private void sendApkVerificationRequest(PackageInfoLite pkgLite) {
        final int verificationId = mPm.mPendingVerificationToken++;

+30 −8
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
import android.crashrecovery.flags.Flags;
import android.credentials.CredentialManager;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
@@ -1195,11 +1196,13 @@ public final class SystemServer implements Dumpable {
        mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
        t.traceEnd();

        if (!Flags.recoverabilityDetection()) {
            // Now that we have the bare essentials of the OS up and running, take
            // note that we just booted, which might send out a rescue party if
            // we're stuck in a runtime restart loop.
            RescueParty.registerHealthObserver(mSystemContext);
            PackageWatchdog.getInstance(mSystemContext).noteBoot();
        }

        // Manages LEDs and display backlight so we need it to bring up the display.
        t.traceBegin("StartLightsService");
@@ -1469,10 +1472,13 @@ public final class SystemServer implements Dumpable {
        boolean enableVrService = context.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);

        if (!Flags.recoverabilityDetection()) {
            // For debugging RescueParty
        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system", false)) {
            if (Build.IS_DEBUGGABLE
                    && SystemProperties.getBoolean("debug.crash_system", false)) {
                throw new RuntimeException();
            }
        }

        try {
            final String SECONDARY_ZYGOTE_PRELOAD = "SecondaryZygotePreload";
@@ -2909,6 +2915,14 @@ public final class SystemServer implements Dumpable {
        mPackageManagerService.systemReady();
        t.traceEnd();

        if (Flags.recoverabilityDetection()) {
            // Now that we have the essential services needed for rescue party, initialize
            // RescuParty. note that we just booted, which might send out a rescue party if
            // we're stuck in a runtime restart loop.
            RescueParty.registerHealthObserver(mSystemContext);
            PackageWatchdog.getInstance(mSystemContext).noteBoot();
        }

        t.traceBegin("MakeDisplayManagerServiceReady");
        try {
            // TODO: use boot phase and communicate this flag some other way
@@ -3312,6 +3326,14 @@ public final class SystemServer implements Dumpable {
     * are updated outside of OTA; and to avoid breaking dependencies from system into apexes.
     */
    private void startApexServices(@NonNull TimingsTraceAndSlog t) {
        if (Flags.recoverabilityDetection()) {
            // For debugging RescueParty
            if (Build.IS_DEBUGGABLE
                    && SystemProperties.getBoolean("debug.crash_system", false)) {
                throw new RuntimeException();
            }
        }

        t.traceBegin("startApexServices");
        // TODO(b/192880996): get the list from "android" package, once the manifest entries
        // are migrated to system manifest.