diff options
5 files changed, 77 insertions, 22 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index cdd2d804844b..2bd06bdcb2ef 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1688,6 +1688,7 @@ package android.content.rollback { public final class RollbackInfo implements android.os.Parcelable { method public int describeContents(); + method public int getRollbackId(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR; field public final android.content.rollback.PackageRollbackInfo targetPackage; diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java index 66df4fea3f23..0803a7c1d651 100644 --- a/core/java/android/content/rollback/RollbackInfo.java +++ b/core/java/android/content/rollback/RollbackInfo.java @@ -30,6 +30,11 @@ import android.os.Parcelable; public final class RollbackInfo implements Parcelable { /** + * A unique identifier for the rollback. + */ + private final int mRollbackId; + + /** * The package that needs to be rolled back. */ public final PackageRollbackInfo targetPackage; @@ -40,12 +45,21 @@ public final class RollbackInfo implements Parcelable { // staged installs is supported. /** @hide */ - public RollbackInfo(PackageRollbackInfo targetPackage) { + public RollbackInfo(int rollbackId, PackageRollbackInfo targetPackage) { + this.mRollbackId = rollbackId; this.targetPackage = targetPackage; } private RollbackInfo(Parcel in) { - this.targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in); + mRollbackId = in.readInt(); + targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in); + } + + /** + * Returns a unique identifier for this rollback. + */ + public int getRollbackId() { + return mRollbackId; } @Override @@ -55,6 +69,7 @@ public final class RollbackInfo implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { + out.writeInt(mRollbackId); targetPackage.writeToParcel(out, flags); } diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/RollbackData.java index f0589aac8239..4015c4f7b391 100644 --- a/services/core/java/com/android/server/rollback/RollbackData.java +++ b/services/core/java/com/android/server/rollback/RollbackData.java @@ -29,6 +29,11 @@ import java.util.List; */ class RollbackData { /** + * A unique identifier for this rollback. + */ + public final int rollbackId; + + /** * The per-package rollback information. */ public final List<PackageRollbackInfo> packages = new ArrayList<>(); @@ -44,7 +49,8 @@ class RollbackData { */ public Instant timestamp; - RollbackData(File backupDir) { + RollbackData(int rollbackId, File backupDir) { + this.rollbackId = rollbackId; this.backupDir = backupDir; } } diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 085b4afac0e2..0b0f1dca98d3 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -46,6 +46,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.storage.StorageManager; import android.util.Log; +import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; @@ -55,14 +56,16 @@ import com.android.server.pm.PackageManagerServiceUtils; import java.io.File; import java.io.IOException; +import java.security.SecureRandom; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Random; import java.util.Set; import java.util.function.Consumer; @@ -82,6 +85,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // mLock is held when they are called. private final Object mLock = new Object(); + // Used for generating rollback IDs. + private final Random mRandom = new SecureRandom(); + + // Set of allocated rollback ids + @GuardedBy("mLock") + private final SparseBooleanArray mAllocatedRollbackIds = new SparseBooleanArray(); + // Package rollback data for rollback-enabled installs that have not yet // been committed. Maps from sessionId to rollback data. @GuardedBy("mLock") @@ -212,7 +222,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { if (info.packageName.equals(packageName)) { // TODO: Once the RollbackInfo API supports info about // dependant packages, add that info here. - return new RollbackInfo(info); + return new RollbackInfo(data.rollbackId, info); } } return null; @@ -282,15 +292,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return; } - // Verify the latest rollback matches the version requested. - // TODO: Check dependant packages too once RollbackInfo includes that - // information. - for (PackageRollbackInfo info : data.packages) { - if (info.packageName.equals(targetPackageName) - && !rollback.targetPackage.higherVersion.equals(info.higherVersion)) { - sendFailure(statusReceiver, "Rollback is out of date."); - return; - } + if (data.rollbackId != rollback.getRollbackId()) { + sendFailure(statusReceiver, "Rollback for package is out of date"); + return; } // Verify the RollbackData is up to date with what's installed on @@ -469,7 +473,15 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @GuardedBy("mLock") private void loadAllRollbackDataLocked() { mAvailableRollbacks = mRollbackStore.loadAvailableRollbacks(); + for (RollbackData data : mAvailableRollbacks) { + mAllocatedRollbackIds.put(data.rollbackId, true); + } + mRecentlyExecutedRollbacks = mRollbackStore.loadRecentlyExecutedRollbacks(); + for (RollbackInfo info : mRecentlyExecutedRollbacks) { + mAllocatedRollbackIds.put(info.getRollbackId(), true); + } + scheduleExpiration(0); } @@ -732,7 +744,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { mChildSessions.put(childSessionId, parentSessionId); data = mPendingRollbacks.get(parentSessionId); if (data == null) { - data = mRollbackStore.createAvailableRollback(); + int rollbackId = allocateRollbackIdLocked(); + data = mRollbackStore.createAvailableRollback(rollbackId); mPendingRollbacks.put(parentSessionId, data); } data.packages.add(info); @@ -912,4 +925,19 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } return null; } + + @GuardedBy("mLock") + private int allocateRollbackIdLocked() throws IOException { + int n = 0; + int rollbackId; + do { + rollbackId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; + if (!mAllocatedRollbackIds.get(rollbackId, false)) { + mAllocatedRollbackIds.put(rollbackId, true); + return rollbackId; + } + } while (n++ < 32); + + throw new IOException("Failed to allocate rollback ID"); + } } diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index eb06bb24c24c..52208597af2b 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -29,7 +29,6 @@ import org.json.JSONObject; import java.io.File; import java.io.IOException; import java.io.PrintWriter; -import java.nio.file.Files; import java.time.Instant; import java.time.format.DateTimeParseException; import java.util.ArrayList; @@ -58,7 +57,7 @@ class RollbackStore { // base.apk // recently_executed.json // - // * XXX, YYY are random strings from Files.createTempDirectory + // * XXX, YYY are the rollbackIds for the corresponding rollbacks. // * rollback.json contains all relevant metadata for the rollback. This // file is not written until the rollback is made available. // @@ -113,13 +112,14 @@ class RollbackStore { JSONArray array = object.getJSONArray("recentlyExecuted"); for (int i = 0; i < array.length(); ++i) { JSONObject element = array.getJSONObject(i); + int rollbackId = element.getInt("rollbackId"); String packageName = element.getString("packageName"); long higherVersionCode = element.getLong("higherVersionCode"); long lowerVersionCode = element.getLong("lowerVersionCode"); PackageRollbackInfo target = new PackageRollbackInfo(packageName, new PackageRollbackInfo.PackageVersion(higherVersionCode), new PackageRollbackInfo.PackageVersion(lowerVersionCode)); - RollbackInfo rollback = new RollbackInfo(target); + RollbackInfo rollback = new RollbackInfo(rollbackId, target); recentlyExecutedRollbacks.add(rollback); } } catch (IOException | JSONException e) { @@ -135,9 +135,9 @@ class RollbackStore { /** * Creates a new RollbackData instance with backupDir assigned. */ - RollbackData createAvailableRollback() throws IOException { - File backupDir = Files.createTempDirectory(mAvailableRollbacksDir.toPath(), null).toFile(); - return new RollbackData(backupDir); + RollbackData createAvailableRollback(int rollbackId) throws IOException { + File backupDir = new File(mAvailableRollbacksDir, Integer.toString(rollbackId)); + return new RollbackData(rollbackId, backupDir); } /** @@ -162,6 +162,7 @@ class RollbackStore { infoJson.put("lowerVersionCode", info.lowerVersion.versionCode); packagesJson.put(infoJson); } + dataJson.put("rollbackId", data.rollbackId); dataJson.put("packages", packagesJson); dataJson.put("timestamp", data.timestamp.toString()); @@ -195,6 +196,7 @@ class RollbackStore { for (int i = 0; i < recentlyExecutedRollbacks.size(); ++i) { RollbackInfo rollback = recentlyExecutedRollbacks.get(i); JSONObject element = new JSONObject(); + element.put("rollbackId", rollback.getRollbackId()); element.put("packageName", rollback.targetPackage.packageName); element.put("higherVersionCode", rollback.targetPackage.higherVersion.versionCode); element.put("lowerVersionCode", rollback.targetPackage.lowerVersion.versionCode); @@ -216,10 +218,13 @@ class RollbackStore { */ private RollbackData loadRollbackData(File backupDir) throws IOException { try { - RollbackData data = new RollbackData(backupDir); File rollbackJsonFile = new File(backupDir, "rollback.json"); JSONObject dataJson = new JSONObject( IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath())); + + int rollbackId = dataJson.getInt("rollbackId"); + RollbackData data = new RollbackData(rollbackId, backupDir); + JSONArray packagesJson = dataJson.getJSONArray("packages"); for (int i = 0; i < packagesJson.length(); ++i) { JSONObject infoJson = packagesJson.getJSONObject(i); |