Merge changes Ic8db00b6,I68a91e07,I860ad443

* changes:
  Remove package name from ROLLBACK_EXECUTED broadcast.
  Use VersionedPackage in PackageRollbackInfo.
  Assign a rollbackId to all rollbacks.
This commit is contained in:
TreeHugger Robot
2019-01-23 15:49:41 +00:00
committed by Android (Google) Code Review
9 changed files with 190 additions and 173 deletions

View File

@@ -1672,22 +1672,17 @@ package android.content.pm.permission {
package android.content.rollback {
public final class PackageRollbackInfo implements android.os.Parcelable {
ctor public PackageRollbackInfo(String, android.content.rollback.PackageRollbackInfo.PackageVersion, android.content.rollback.PackageRollbackInfo.PackageVersion);
method public int describeContents();
method public String getPackageName();
method public android.content.pm.VersionedPackage getVersionRolledBackFrom();
method public android.content.pm.VersionedPackage getVersionRolledBackTo();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
field public final android.content.rollback.PackageRollbackInfo.PackageVersion higherVersion;
field public final android.content.rollback.PackageRollbackInfo.PackageVersion lowerVersion;
field public final String packageName;
}
public static class PackageRollbackInfo.PackageVersion {
ctor public PackageRollbackInfo.PackageVersion(long);
field public final long versionCode;
}
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;

View File

@@ -2377,7 +2377,6 @@ public class Intent implements Parcelable, Cloneable {
/**
* Broadcast Action: An existing version of an application package has been
* rolled back to a previous version.
* The data contains the name of the package.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.

View File

@@ -17,11 +17,10 @@
package android.content.rollback;
import android.annotation.SystemApi;
import android.content.pm.VersionedPackage;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* Information about a rollback available for a particular package.
*
@@ -29,59 +28,41 @@ import java.util.Objects;
*/
@SystemApi
public final class PackageRollbackInfo implements Parcelable {
/**
* The name of a package being rolled back.
*/
public final String packageName;
private final VersionedPackage mVersionRolledBackFrom;
private final VersionedPackage mVersionRolledBackTo;
/**
* The version the package was rolled back from.
* Returns the name of the package to roll back from.
*/
public final PackageVersion higherVersion;
/**
* The version the package was rolled back to.
*/
public final PackageVersion lowerVersion;
/**
* Represents a version of a package.
*/
public static class PackageVersion {
public final long versionCode;
// TODO(b/120200473): Include apk sha or some other way to distinguish
// between two different apks with the same version code.
public PackageVersion(long versionCode) {
this.versionCode = versionCode;
}
@Override
public boolean equals(Object other) {
if (other instanceof PackageVersion) {
PackageVersion otherVersion = (PackageVersion) other;
return versionCode == otherVersion.versionCode;
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(versionCode);
}
public String getPackageName() {
return mVersionRolledBackFrom.getPackageName();
}
public PackageRollbackInfo(String packageName,
PackageVersion higherVersion, PackageVersion lowerVersion) {
this.packageName = packageName;
this.higherVersion = higherVersion;
this.lowerVersion = lowerVersion;
/**
* Returns the version of the package rolled back from.
*/
public VersionedPackage getVersionRolledBackFrom() {
return mVersionRolledBackFrom;
}
/**
* Returns the version of the package rolled back to.
*/
public VersionedPackage getVersionRolledBackTo() {
return mVersionRolledBackTo;
}
/** @hide */
public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
VersionedPackage packageRolledBackTo) {
this.mVersionRolledBackFrom = packageRolledBackFrom;
this.mVersionRolledBackTo = packageRolledBackTo;
}
private PackageRollbackInfo(Parcel in) {
this.packageName = in.readString();
this.higherVersion = new PackageVersion(in.readLong());
this.lowerVersion = new PackageVersion(in.readLong());
this.mVersionRolledBackFrom = VersionedPackage.CREATOR.createFromParcel(in);
this.mVersionRolledBackTo = VersionedPackage.CREATOR.createFromParcel(in);
}
@Override
@@ -91,9 +72,8 @@ public final class PackageRollbackInfo implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(packageName);
out.writeLong(higherVersion.versionCode);
out.writeLong(lowerVersion.versionCode);
mVersionRolledBackFrom.writeToParcel(out, flags);
mVersionRolledBackTo.writeToParcel(out, flags);
}
public static final Parcelable.Creator<PackageRollbackInfo> CREATOR =

View File

@@ -29,6 +29,11 @@ import android.os.Parcelable;
@SystemApi
public final class RollbackInfo implements Parcelable {
/**
* A unique identifier for the rollback.
*/
private final int mRollbackId;
/**
* The package that needs to be rolled back.
*/
@@ -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);
}

View File

@@ -28,6 +28,11 @@ import java.util.List;
* packages.
*/
class RollbackData {
/**
* A unique identifier for this rollback.
*/
public final int rollbackId;
/**
* The per-package rollback information.
*/
@@ -44,7 +49,8 @@ class RollbackData {
*/
public Instant timestamp;
RollbackData(File backupDir) {
RollbackData(int rollbackId, File backupDir) {
this.rollbackId = rollbackId;
this.backupDir = backupDir;
}
}

View File

@@ -16,7 +16,6 @@
package com.android.server.rollback;
import android.Manifest;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -32,10 +31,10 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.StringParceledListSlice;
import android.content.pm.VersionedPackage;
import android.content.rollback.IRollbackManager;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -46,6 +45,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 +55,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 +84,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")
@@ -209,10 +218,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// it's out of date or not, so no need to check package versions here.
for (PackageRollbackInfo info : data.packages) {
if (info.packageName.equals(packageName)) {
if (info.getPackageName().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;
@@ -230,7 +239,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
RollbackData data = mAvailableRollbacks.get(i);
for (PackageRollbackInfo info : data.packages) {
packageNames.add(info.packageName);
packageNames.add(info.getPackageName());
}
}
}
@@ -272,7 +281,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
*/
private void executeRollbackInternal(RollbackInfo rollback,
String callerPackageName, IntentSender statusReceiver) {
String targetPackageName = rollback.targetPackage.packageName;
String targetPackageName = rollback.targetPackage.getPackageName();
Log.i(TAG, "Initiating rollback of " + targetPackageName);
// Get the latest RollbackData for the target package.
@@ -282,15 +291,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
@@ -302,15 +305,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// Figure out how to ensure we don't commit the rollback if
// roll forward happens at the same time.
for (PackageRollbackInfo info : data.packages) {
PackageRollbackInfo.PackageVersion installedVersion =
getInstalledPackageVersion(info.packageName);
VersionedPackage installedVersion = getInstalledPackageVersion(info.getPackageName());
if (installedVersion == null) {
// TODO: Test this case
sendFailure(statusReceiver, "Package to roll back is not installed");
return;
}
if (!info.higherVersion.equals(installedVersion)) {
if (!packageVersionsEqual(info.getVersionRolledBackFrom(), installedVersion)) {
// TODO: Test this case
sendFailure(statusReceiver, "Package version to roll back not installed.");
return;
@@ -353,7 +355,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// TODO: Will it always be called "base.apk"? What about splits?
// What about apex?
File packageDir = new File(data.backupDir, info.packageName);
File packageDir = new File(data.backupDir, info.getPackageName());
File baseApk = new File(packageDir, "base.apk");
try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(baseApk,
ParcelFileDescriptor.MODE_READ_ONLY)) {
@@ -380,12 +382,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
addRecentlyExecutedRollback(rollback);
sendSuccess(statusReceiver);
Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED,
Uri.fromParts("package", targetPackageName,
Manifest.permission.MANAGE_ROLLBACKS));
Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
// TODO: This call emits the warning "Calling a method in the
// system process without a qualified user". Fix that.
// TODO: Limit this to receivers holding the
// MANAGE_ROLLBACKS permission?
mContext.sendBroadcast(broadcast);
}
);
@@ -427,7 +429,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
while (iter.hasNext()) {
RollbackData data = iter.next();
for (PackageRollbackInfo info : data.packages) {
if (info.packageName.equals(packageName)) {
if (info.getPackageName().equals(packageName)) {
iter.remove();
mRollbackStore.deleteAvailableRollback(data);
break;
@@ -469,7 +471,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);
}
@@ -481,8 +491,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private void onPackageReplaced(String packageName) {
// TODO: Could this end up incorrectly deleting a rollback for a
// package that is about to be installed?
PackageRollbackInfo.PackageVersion installedVersion =
getInstalledPackageVersion(packageName);
VersionedPackage installedVersion = getInstalledPackageVersion(packageName);
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
@@ -490,8 +499,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
while (iter.hasNext()) {
RollbackData data = iter.next();
for (PackageRollbackInfo info : data.packages) {
if (info.packageName.equals(packageName)
&& !info.higherVersion.equals(installedVersion)) {
if (info.getPackageName().equals(packageName)
&& !packageVersionsEqual(
info.getVersionRolledBackFrom(),
installedVersion)) {
iter.remove();
mRollbackStore.deleteAvailableRollback(data);
break;
@@ -514,7 +525,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
boolean changed = false;
while (iter.hasNext()) {
RollbackInfo rollback = iter.next();
if (packageName.equals(rollback.targetPackage.packageName)) {
if (packageName.equals(rollback.targetPackage.getPackageName())) {
iter.remove();
changed = true;
}
@@ -689,8 +700,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
return false;
}
PackageRollbackInfo.PackageVersion newVersion =
new PackageRollbackInfo.PackageVersion(newPackage.versionCode);
VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode);
// Get information about the currently installed package.
PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
@@ -701,8 +711,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
Log.e(TAG, packageName + " is not installed");
return false;
}
PackageRollbackInfo.PackageVersion installedVersion =
new PackageRollbackInfo.PackageVersion(installedPackage.getLongVersionCode());
VersionedPackage installedVersion = new VersionedPackage(packageName,
installedPackage.getLongVersionCode());
for (int user : installedUsers) {
final int storageFlags;
@@ -723,8 +733,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
}
PackageRollbackInfo info = new PackageRollbackInfo(
packageName, newVersion, installedVersion);
PackageRollbackInfo info = new PackageRollbackInfo(newVersion, installedVersion);
RollbackData data;
try {
@@ -732,7 +741,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);
@@ -819,7 +829,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
* Gets the version of the package currently installed.
* Returns null if the package is not currently installed.
*/
private PackageRollbackInfo.PackageVersion getInstalledPackageVersion(String packageName) {
private VersionedPackage getInstalledPackageVersion(String packageName) {
PackageManager pm = mContext.getPackageManager();
PackageInfo pkgInfo = null;
try {
@@ -828,7 +838,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
return null;
}
return new PackageRollbackInfo.PackageVersion(pkgInfo.getLongVersionCode());
return new VersionedPackage(packageName, pkgInfo.getLongVersionCode());
}
private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
return a.getPackageName().equals(b.getPackageName())
&& a.getLongVersionCode() == b.getLongVersionCode();
}
private class SessionCallback extends PackageInstaller.SessionCallback {
@@ -904,7 +919,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
RollbackData data = mAvailableRollbacks.get(i);
for (PackageRollbackInfo info : data.packages) {
if (info.packageName.equals(packageName)) {
if (info.getPackageName().equals(packageName)) {
return data;
}
}
@@ -912,4 +927,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");
}
}

View File

@@ -16,6 +16,7 @@
package com.android.server.rollback;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.util.Log;
@@ -29,7 +30,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 +58,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 +113,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);
PackageRollbackInfo target = new PackageRollbackInfo(
new VersionedPackage(packageName, higherVersionCode),
new VersionedPackage(packageName, lowerVersionCode));
RollbackInfo rollback = new RollbackInfo(rollbackId, target);
recentlyExecutedRollbacks.add(rollback);
}
} catch (IOException | JSONException e) {
@@ -135,9 +136,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);
}
/**
@@ -157,11 +158,14 @@ class RollbackStore {
JSONArray packagesJson = new JSONArray();
for (PackageRollbackInfo info : data.packages) {
JSONObject infoJson = new JSONObject();
infoJson.put("packageName", info.packageName);
infoJson.put("higherVersionCode", info.higherVersion.versionCode);
infoJson.put("lowerVersionCode", info.lowerVersion.versionCode);
infoJson.put("packageName", info.getPackageName());
infoJson.put("higherVersionCode",
info.getVersionRolledBackFrom().getLongVersionCode());
infoJson.put("lowerVersionCode",
info.getVersionRolledBackTo().getVersionCode());
packagesJson.put(infoJson);
}
dataJson.put("rollbackId", data.rollbackId);
dataJson.put("packages", packagesJson);
dataJson.put("timestamp", data.timestamp.toString());
@@ -195,9 +199,12 @@ class RollbackStore {
for (int i = 0; i < recentlyExecutedRollbacks.size(); ++i) {
RollbackInfo rollback = recentlyExecutedRollbacks.get(i);
JSONObject element = new JSONObject();
element.put("packageName", rollback.targetPackage.packageName);
element.put("higherVersionCode", rollback.targetPackage.higherVersion.versionCode);
element.put("lowerVersionCode", rollback.targetPackage.lowerVersion.versionCode);
element.put("rollbackId", rollback.getRollbackId());
element.put("packageName", rollback.targetPackage.getPackageName());
element.put("higherVersionCode",
rollback.targetPackage.getVersionRolledBackFrom().getLongVersionCode());
element.put("lowerVersionCode",
rollback.targetPackage.getVersionRolledBackTo().getLongVersionCode());
array.put(element);
}
@@ -216,19 +223,22 @@ 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);
String packageName = infoJson.getString("packageName");
long higherVersionCode = infoJson.getLong("higherVersionCode");
long lowerVersionCode = infoJson.getLong("lowerVersionCode");
data.packages.add(new PackageRollbackInfo(packageName,
new PackageRollbackInfo.PackageVersion(higherVersionCode),
new PackageRollbackInfo.PackageVersion(lowerVersionCode)));
data.packages.add(new PackageRollbackInfo(
new VersionedPackage(packageName, higherVersionCode),
new VersionedPackage(packageName, lowerVersionCode)));
}
data.timestamp = Instant.parse(dataJson.getString("timestamp"));

View File

@@ -44,7 +44,6 @@ class RollbackBroadcastReceiver extends BroadcastReceiver {
RollbackBroadcastReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
filter.addDataScheme("package");
InstrumentationRegistry.getContext().registerReceiver(this, filter);
}

View File

@@ -22,9 +22,9 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.test.InstrumentationRegistry;
@@ -98,7 +98,7 @@ public class RollbackTest {
// so that's not the case!
for (int i = 0; i < 5; ++i) {
for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
if (TEST_APP_A.equals(info.targetPackage.packageName)) {
if (TEST_APP_A.equals(info.targetPackage.getPackageName())) {
Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
Thread.sleep(1000);
break;
@@ -116,7 +116,7 @@ public class RollbackTest {
// There should be no recently executed rollbacks for this package.
for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
assertNotEquals(TEST_APP_A, info.targetPackage.packageName);
assertNotEquals(TEST_APP_A, info.targetPackage.getPackageName());
}
// Install v1 of the app (without rollbacks enabled).
@@ -135,9 +135,7 @@ public class RollbackTest {
assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
assertNotNull(rollback);
assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
// We should not have received any rollback requests yet.
// TODO: Possibly flaky if, by chance, some other app on device
@@ -153,21 +151,18 @@ public class RollbackTest {
// received could lead to test flakiness.
Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
assertNotNull(broadcast);
assertEquals(TEST_APP_A, broadcast.getData().getSchemeSpecificPart());
assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
// Verify the recent rollback has been recorded.
rollback = null;
for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
if (TEST_APP_A.equals(r.targetPackage.packageName)) {
if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
assertNull(rollback);
rollback = r;
}
}
assertNotNull(rollback);
assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
broadcastReceiver.unregister();
context.unregisterReceiver(enableRollbackReceiver);
@@ -208,16 +203,12 @@ public class RollbackTest {
assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
assertNotNull(rollbackA);
assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName);
assertEquals(2, rollbackA.targetPackage.higherVersion.versionCode);
assertEquals(1, rollbackA.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
assertNotNull(rollbackB);
assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName);
assertEquals(2, rollbackB.targetPackage.higherVersion.versionCode);
assertEquals(1, rollbackB.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
// Reload the persisted data.
rm.reloadPersistedData();
@@ -225,16 +216,12 @@ public class RollbackTest {
// The apps should still be available for rollback.
rollbackA = rm.getAvailableRollback(TEST_APP_A);
assertNotNull(rollbackA);
assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName);
assertEquals(2, rollbackA.targetPackage.higherVersion.versionCode);
assertEquals(1, rollbackA.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
rollbackB = rm.getAvailableRollback(TEST_APP_B);
assertNotNull(rollbackB);
assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName);
assertEquals(2, rollbackB.targetPackage.higherVersion.versionCode);
assertEquals(1, rollbackB.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
// Rollback of B should not rollback A
RollbackTestUtils.rollback(rollbackB);
@@ -278,16 +265,12 @@ public class RollbackTest {
assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
assertNotNull(rollbackA);
assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName);
assertEquals(2, rollbackA.targetPackage.higherVersion.versionCode);
assertEquals(1, rollbackA.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
assertNotNull(rollbackB);
assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName);
assertEquals(2, rollbackB.targetPackage.higherVersion.versionCode);
assertEquals(1, rollbackB.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
// Reload the persisted data.
rm.reloadPersistedData();
@@ -295,16 +278,12 @@ public class RollbackTest {
// The apps should still be available for rollback.
rollbackA = rm.getAvailableRollback(TEST_APP_A);
assertNotNull(rollbackA);
assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName);
assertEquals(2, rollbackA.targetPackage.higherVersion.versionCode);
assertEquals(1, rollbackA.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
rollbackB = rm.getAvailableRollback(TEST_APP_B);
assertNotNull(rollbackB);
assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName);
assertEquals(2, rollbackB.targetPackage.higherVersion.versionCode);
assertEquals(1, rollbackB.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
// Rollback of B should rollback A as well
RollbackTestUtils.rollback(rollbackB);
@@ -348,15 +327,13 @@ public class RollbackTest {
// Verify the recent rollback has been recorded.
rollback = null;
for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
if (TEST_APP_A.equals(r.targetPackage.packageName)) {
if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
assertNull(rollback);
rollback = r;
}
}
assertNotNull(rollback);
assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
// Reload the persisted data.
rm.reloadPersistedData();
@@ -364,15 +341,13 @@ public class RollbackTest {
// Verify the recent rollback is still recorded.
rollback = null;
for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
if (TEST_APP_A.equals(r.targetPackage.packageName)) {
if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
assertNull(rollback);
rollback = r;
}
}
assertNotNull(rollback);
assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
} finally {
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -404,9 +379,7 @@ public class RollbackTest {
assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
assertNotNull(rollback);
assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
// Expire the rollback.
rm.expireRollbackForPackage(TEST_APP_A);
@@ -499,8 +472,7 @@ public class RollbackTest {
@Test
public void testRollbackBroadcastRestrictions() throws Exception {
RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED,
Uri.fromParts("package", "com.android.tests.rollback.bogus", null));
Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
try {
InstrumentationRegistry.getContext().sendBroadcast(broadcast);
fail("Succeeded in sending restricted broadcast from app context.");
@@ -549,11 +521,11 @@ public class RollbackTest {
Thread.sleep(1000);
RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
assertNotNull(rollbackA);
assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName);
assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
assertNotNull(rollbackB);
assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName);
assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
// Executing rollback should roll back the correct package.
RollbackTestUtils.rollback(rollbackA);
@@ -670,7 +642,7 @@ public class RollbackTest {
// We should not see a recent rollback listed for TEST_APP_B
for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
assertNotEquals(TEST_APP_B, r.targetPackage.packageName);
assertNotEquals(TEST_APP_B, r.targetPackage.getPackageName());
}
// TODO: Test the listed dependent apps for the recently executed
@@ -680,4 +652,15 @@ public class RollbackTest {
RollbackTestUtils.dropShellPermissionIdentity();
}
}
// Helper function to test the value of a PackageRollbackInfo
private void assertPackageRollbackInfoEquals(String packageName,
long versionRolledBackFrom, long versionRolledBackTo,
PackageRollbackInfo info) {
assertEquals(packageName, info.getPackageName());
assertEquals(packageName, info.getVersionRolledBackFrom().getPackageName());
assertEquals(versionRolledBackFrom, info.getVersionRolledBackFrom().getLongVersionCode());
assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
}
}