summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/system-current.txt1
-rw-r--r--core/java/android/content/rollback/RollbackInfo.java19
-rw-r--r--services/core/java/com/android/server/rollback/RollbackData.java8
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java52
-rw-r--r--services/core/java/com/android/server/rollback/RollbackStore.java19
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);