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

Commit 71a7e46d authored by Mohammad Samiul Islam's avatar Mohammad Samiul Islam Committed by Android (Google) Code Review
Browse files

Merge changes I34d7ee3b,I99337ea2,I5c190938,If79073a9,Ie3343681 into qt-qpr1-dev

* changes:
  Reschedule the pre-reboot verification after boot completed.
  Prevent sessions from resuming once boot is completed
  Prevent extra sessions owned by staged install from living across restarts
  Prevent exceptions during staged install from crashing system server
  Prevent exceptions in pre-reboot verification from crashing system server
parents 7a85d4de 7347288f
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -218,6 +218,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements

    public void systemReady() {
        mAppOps = mContext.getSystemService(AppOpsManager.class);
        mStagingManager.systemReady();

        synchronized (mSessions) {
            readSessionsLocked();
@@ -380,6 +381,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
                            Slog.w(TAG, "Abandoning old session created at "
                                        + session.createdMillis);
                            valid = false;
                        } else if (isExtraSessionForStagedInstall(session)) {
                            valid = false;
                        } else {
                            valid = true;
                        }
@@ -410,6 +413,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        }
    }

    // Extra sessions are created during staged install on temporary basis. They should not be
    // allowed to live across system server restart.
    private boolean isExtraSessionForStagedInstall(PackageInstallerSession session) {
        return (session.params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0
                || (session.params.installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0;
    }

    @GuardedBy("mSessions")
    private void addHistoricalSessionLocked(PackageInstallerSession session) {
        CharArrayWriter writer = new CharArrayWriter();
+136 −80
Original line number Diff line number Diff line
@@ -21,10 +21,12 @@ import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
@@ -44,6 +46,7 @@ import android.os.ParcelableException;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.util.Slog;
import android.util.SparseArray;
import android.util.apk.ApkSignatureVerifier;
@@ -72,12 +75,16 @@ public class StagingManager {
    private final PackageInstallerService mPi;
    private final ApexManager mApexManager;
    private final PowerManager mPowerManager;
    private final Context mContext;
    private final Handler mBgHandler;
    private PackageInstallerSession mPendingSession;
    private boolean mIsReady;

    @GuardedBy("mStagedSessions")
    private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();

    StagingManager(PackageInstallerService pi, ApexManager am, Context context) {
        mContext = context;
        mPi = pi;
        mApexManager = am;
        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -202,6 +209,12 @@ public class StagingManager {
    }

    private void preRebootVerification(@NonNull PackageInstallerSession session) {
        try {
            if (!mIsReady) {
                mPendingSession = session;
                return;
            }

            boolean success = true;

            final ApexInfoList apexInfoList = new ApexInfoList();
@@ -247,11 +260,12 @@ public class StagingManager {
                for (ApexInfo apexPackage : apexInfoList.apexInfos) {
                    if (!validateApexSignature(apexPackage.packagePath,
                            apexPackage.packageName)) {
                    session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                        session.setStagedSessionFailed(
                                SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                                "APK-container signature verification failed for package "
                                        + apexPackage.packageName + ". Signature of file "
                                    + apexPackage.packagePath + " does not match the signature of "
                                    + " the package already installed.");
                                        + apexPackage.packagePath + " does not match the signature"
                                        + " of the package already installed.");
                        // TODO(b/118865310): abort the session on apexd.
                        return;
                    }
@@ -260,8 +274,8 @@ public class StagingManager {

            if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                // If rollback is enabled for this session, we call through to the RollbackManager
            // with the list of sessions it must enable rollback for. Note that notifyStagedSession
            // is a synchronous operation.
                // with the list of sessions it must enable rollback for. Note that
                // notifyStagedSession is a synchronous operation.
                final IRollbackManager rm = IRollbackManager.Stub.asInterface(
                        ServiceManager.getService(Context.ROLLBACK_SERVICE));
                try {
@@ -282,6 +296,11 @@ public class StagingManager {
                        "APEX staging failed, check logcat messages from apexd for more "
                                + "details.");
            }
        } catch (Exception e) {
            Slog.e(TAG, "Pre-reboot verification failed due to unhandled exception", e);
            session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                    "Pre-reboot verification failed due to unhandled exception: " + e);
        }
    }


@@ -346,14 +365,23 @@ public class StagingManager {
        }
        // The APEX part of the session is activated, proceed with the installation of APKs.
        if (!installApksInSession(session, /* preReboot */ false)) {
            session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
                    "Staged installation of APKs failed. Check logcat messages for"
                        + "more information.");

            if (!hasApex) {
            onInstallationFailure(session, new PackageManagerException(
                    SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, "Staged installation of APKs "
                    + "failed. Check logcat messages for more information."));
            return;
        }

        session.setStagedSessionApplied();
        if (hasApex) {
            mApexManager.markStagedSessionSuccessful(session.sessionId);
        }
    }

    void onInstallationFailure(PackageInstallerSession session, PackageManagerException e) {
        session.setStagedSessionFailed(e.error, e.getMessage());
        if (!sessionContainsApex(session)) {
            return;
        }
        if (!mApexManager.abortActiveSession()) {
            Slog.e(TAG, "Failed to abort APEXd session");
        } else {
@@ -362,13 +390,6 @@ public class StagingManager {
                            + "to the previous state of APEXd.");
            mPowerManager.reboot(null);
        }
            return;
        }

        session.setStagedSessionApplied();
        if (hasApex) {
            mApexManager.markStagedSessionSuccessful(session.sessionId);
        }
    }

    private List<String> findAPKsInDir(File stageDir) {
@@ -648,6 +669,11 @@ public class StagingManager {
    }

    private void checkStateAndResume(@NonNull PackageInstallerSession session) {
        // Do not resume session if boot completed already
        if (SystemProperties.getBoolean("sys.boot_completed", false)) {
            return;
        }

        if (!session.isCommitted()) {
            // Session hasn't been committed yet, ignore.
            return;
@@ -664,7 +690,37 @@ public class StagingManager {
        } else {
            // Session had already being marked ready. Start the checks to verify if there is any
            // follow-up work.
            try {
                resumeSession(session);
            } catch (Exception e) {
                Slog.e(TAG, "Staged install failed due to unhandled exception", e);
                onInstallationFailure(session, new PackageManagerException(
                        SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
                        "Staged install failed due to unhandled exception: " + e));

            }
        }
    }

    void systemReady() {
        // Register the receiver of boot completed intent for staging manager.
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context ctx, Intent intent) {
                readyToStart();
                ctx.unregisterReceiver(this);
            }
        }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
    }

    // Notify the handler that system is ready, and reschedule the pre-reboot verifications.
    private synchronized void readyToStart() {
        mIsReady = true;
        if (mPendingSession != null) {
            mBgHandler.post(() -> {
                preRebootVerification(mPendingSession);
                mPendingSession = null;
            });
        }
    }