diff options
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/os/storage/StorageManager.java | 13 | ||||
| -rw-r--r-- | services/core/java/com/android/server/StorageManagerService.java | 5 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/StagingManager.java | 22 |
4 files changed, 35 insertions, 6 deletions
diff --git a/api/current.txt b/api/current.txt index d69032d1c627..c86506b09d55 100644 --- a/api/current.txt +++ b/api/current.txt @@ -35911,6 +35911,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); diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index deeeddc5fb71..2d70986dddee 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -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") diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index dcc690fa09b4..4a925aa522a3 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -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(); } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 3390ca780e7d..5bb42d46b746 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -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. |