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

Commit cc4c7d8c authored by Mohammad Samiul Islam's avatar Mohammad Samiul Islam
Browse files

Prevent staging multiple sessions on devices not supporting checkpoint

Bug: 141843321
Test: atest StagedInstallTest#testFailStagingMultipleSessionsIfNoCheckPoint
Change-Id: I118ae628649e9bef82641ef18841205091e98a6a
parent 1d758938
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -35908,6 +35908,7 @@ package android.os.storage {
    method public boolean isAllocationSupported(@NonNull java.io.FileDescriptor);
    method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException;
    method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
    method public boolean isCheckpointSupported();
    method public boolean isEncrypted(java.io.File);
    method public boolean isObbMounted(String);
    method public boolean mountObb(String, String, android.os.storage.OnObbStateChangeListener);
+13 −0
Original line number Diff line number Diff line
@@ -2362,6 +2362,19 @@ public class StorageManager {
        }
    }

    /**
     * Check whether the device supports filesystem checkpoint.
     *
     * @return true if the device supports filesystem checkpoint, false otherwise.
     */
    public boolean isCheckpointSupported() {
        try {
            return mStorageManager.supportsCheckpoint();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    private final Object mFuseAppLoopLock = new Object();

    @GuardedBy("mFuseAppLoopLock")
+0 −5
Original line number Diff line number Diff line
@@ -2771,11 +2771,6 @@ class StorageManagerService extends IStorageManager.Stub
     */
    @Override
    public boolean supportsCheckpoint() throws RemoteException {
        // Only the system process is permitted to start checkpoints
        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
            throw new SecurityException("no permission to check filesystem checkpoint support");
        }

        return mVold.supportsCheckpoint();
    }

+21 −1
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.StorageManager;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -75,6 +76,7 @@ public class StagingManager {
    private final PackageInstallerService mPi;
    private final ApexManager mApexManager;
    private final PowerManager mPowerManager;
    private final Context mContext;
    private final PreRebootVerificationHandler mPreRebootVerificationHandler;

    @GuardedBy("mStagedSessions")
@@ -83,6 +85,7 @@ public class StagingManager {
    StagingManager(PackageInstallerService pi, ApexManager am, Context context) {
        mPi = pi;
        mApexManager = am;
        mContext = context;
        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mPreRebootVerificationHandler = new PreRebootVerificationHandler(
                BackgroundThread.get().getLooper());
@@ -539,6 +542,10 @@ public class StagingManager {
        mPreRebootVerificationHandler.startPreRebootVerification(session.sessionId);
    }

    private int parentOrOwnSessionId(PackageInstallerSession session) {
        return session.hasParentSessionId() ? session.getParentSessionId() : session.sessionId;
    }

    /**
     * <p> Check if the session provided is non-overlapping with the active staged sessions.
     *
@@ -561,6 +568,9 @@ public class StagingManager {
                    "Cannot stage session " + session.sessionId + " with package name null");
        }

        boolean supportsCheckpoint = ((StorageManager) mContext.getSystemService(
                Context.STORAGE_SERVICE)).isCheckpointSupported();

        synchronized (mStagedSessions) {
            for (int i = 0; i < mStagedSessions.size(); i++) {
                final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
@@ -601,7 +611,17 @@ public class StagingManager {
                                    + stagedSession.sessionId, null);
                }

                // TODO(b/141843321): Add support for staging multiple sessions in apexd
                // Staging multiple root sessions is not allowed if device doesn't support
                // checkpoint. If session and stagedSession do not have common ancestor, they are
                // from two different root sessions.
                if (!supportsCheckpoint
                        && parentOrOwnSessionId(session) != parentOrOwnSessionId(stagedSession)) {
                    throw new PackageManagerException(
                            PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
                            "Cannot stage multiple sessions without checkpoint support", null);
                }

                // TODO:b/141843321 Add support for staging multiple sessions in apexd
                // Since apexd doesn't support multiple staged sessions yet, we have to careful how
                // we handle apex sessions. We want to allow a set of apex sessions under the same
                // parent to be staged when there is no previously staged apex sessions.