summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mohammad Samiul Islam <samiul@google.com> 2019-11-05 18:18:28 +0000
committer Mohammad Samiul Islam <samiul@google.com> 2019-11-21 14:30:34 +0000
commitcc4c7d8cc69a90762e88d307fed3331322385cc6 (patch)
tree2252b5dce9df2924c0ed99f06b3c703a0da9b2e4
parent1d7589382804c4e6d435e7838f854d371a5dbf2b (diff)
Prevent staging multiple sessions on devices not supporting checkpoint
Bug: 141843321 Test: atest StagedInstallTest#testFailStagingMultipleSessionsIfNoCheckPoint Change-Id: I118ae628649e9bef82641ef18841205091e98a6a
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/os/storage/StorageManager.java13
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java5
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java22
4 files changed, 35 insertions, 6 deletions
diff --git a/api/current.txt b/api/current.txt
index a45583a432ce..135ec5a81af8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -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);
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 00b525742332..c6d8112d6f5d 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.