Merge changes I7fd7d98a,If770a615 into rvc-dev am: 266fba1670 am: 87193786f0
Change-Id: I7ead6adf31880ff1d29f42806290ba637c1fe5b3
This commit is contained in:
@@ -27,6 +27,7 @@ import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.pm.VersionedPackage;
|
||||
import android.content.rollback.PackageRollbackInfo;
|
||||
@@ -36,6 +37,7 @@ import android.os.Binder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.ext.SdkExtensions;
|
||||
import android.text.TextUtils;
|
||||
import android.util.IntArray;
|
||||
import android.util.Slog;
|
||||
@@ -43,8 +45,11 @@ import android.util.SparseIntArray;
|
||||
import android.util.SparseLongArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -175,10 +180,9 @@ class Rollback {
|
||||
private int mNumPackageSessionsWithSuccess;
|
||||
|
||||
/**
|
||||
* The extension versions supported at the time of rollback creation. May be null if not set
|
||||
* at creation time.
|
||||
* The extension versions supported at the time of rollback creation.
|
||||
*/
|
||||
@Nullable private final SparseIntArray mExtensionVersions;
|
||||
private final SparseIntArray mExtensionVersions;
|
||||
|
||||
/**
|
||||
* Constructs a new, empty Rollback instance.
|
||||
@@ -211,7 +215,8 @@ class Rollback {
|
||||
|
||||
Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId,
|
||||
String installerPackageName) {
|
||||
this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null, null);
|
||||
this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null,
|
||||
new SparseIntArray(0));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,7 +302,7 @@ class Rollback {
|
||||
* Returns the extension versions that were supported at the time that the rollback was created,
|
||||
* as a mapping from SdkVersion to ExtensionVersion.
|
||||
*/
|
||||
@Nullable SparseIntArray getExtensionVersions() {
|
||||
SparseIntArray getExtensionVersions() {
|
||||
return mExtensionVersions;
|
||||
}
|
||||
|
||||
@@ -470,6 +475,15 @@ class Rollback {
|
||||
return;
|
||||
}
|
||||
|
||||
if (containsApex() && wasCreatedAtLowerExtensionVersion()) {
|
||||
PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
|
||||
if (extensionVersionReductionWouldViolateConstraint(mExtensionVersions, pmi)) {
|
||||
sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
|
||||
"Rollback may violate a minExtensionVersion constraint");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get a context to use to install the downgraded version of the package.
|
||||
Context pkgContext;
|
||||
try {
|
||||
@@ -845,6 +859,56 @@ class Rollback {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is an app installed that specifies a minExtensionVersion greater
|
||||
* than what was present at the time this Rollback was created.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static boolean extensionVersionReductionWouldViolateConstraint(
|
||||
SparseIntArray rollbackExtVers, PackageManagerInternal pmi) {
|
||||
if (rollbackExtVers.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
List<String> packages = pmi.getPackageList().getPackageNames();
|
||||
for (int i = 0; i < packages.size(); i++) {
|
||||
AndroidPackage pkg = pmi.getPackage(packages.get(i));
|
||||
SparseIntArray minExtVers = pkg.getMinExtensionVersions();
|
||||
if (minExtVers == null) {
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < rollbackExtVers.size(); j++) {
|
||||
int minExt = minExtVers.get(rollbackExtVers.keyAt(j), -1);
|
||||
if (rollbackExtVers.valueAt(j) < minExt) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if for any SDK version, the extension version recorded at the time of rollback
|
||||
* creation is lower than the current extension version.
|
||||
*/
|
||||
private boolean wasCreatedAtLowerExtensionVersion() {
|
||||
for (int i = 0; i < mExtensionVersions.size(); i++) {
|
||||
if (SdkExtensions.getExtensionVersion(mExtensionVersions.keyAt(i))
|
||||
> mExtensionVersions.valueAt(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean containsApex() {
|
||||
for (PackageRollbackInfo pkgInfo : info.getPackages()) {
|
||||
if (pkgInfo.isApex()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void dump(IndentingPrintWriter ipw) {
|
||||
synchronized (mLock) {
|
||||
ipw.println(info.getRollbackId() + ":");
|
||||
@@ -871,6 +935,12 @@ class Rollback {
|
||||
ipw.decreaseIndent();
|
||||
ipw.println("-committedSessionId: " + info.getCommittedSessionId());
|
||||
}
|
||||
if (mExtensionVersions.size() > 0) {
|
||||
ipw.println("-extensionVersions:");
|
||||
ipw.increaseIndent();
|
||||
ipw.println(mExtensionVersions.toString());
|
||||
ipw.decreaseIndent();
|
||||
}
|
||||
ipw.decreaseIndent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,10 +179,7 @@ class RollbackStore {
|
||||
}
|
||||
|
||||
private static @Nullable JSONArray extensionVersionsToJson(
|
||||
@Nullable SparseIntArray extensionVersions) throws JSONException {
|
||||
if (extensionVersions == null) {
|
||||
return null;
|
||||
}
|
||||
SparseIntArray extensionVersions) throws JSONException {
|
||||
JSONArray array = new JSONArray();
|
||||
for (int i = 0; i < extensionVersions.size(); i++) {
|
||||
JSONObject entryJson = new JSONObject();
|
||||
@@ -193,10 +190,10 @@ class RollbackStore {
|
||||
return array;
|
||||
}
|
||||
|
||||
private static @Nullable SparseIntArray extensionVersionsFromJson(@Nullable JSONArray json)
|
||||
private static @Nullable SparseIntArray extensionVersionsFromJson(JSONArray json)
|
||||
throws JSONException {
|
||||
if (json == null) {
|
||||
return null;
|
||||
return new SparseIntArray(0);
|
||||
}
|
||||
SparseIntArray extensionVersions = new SparseIntArray(json.length());
|
||||
for (int i = 0; i < json.length(); i++) {
|
||||
|
||||
@@ -234,8 +234,8 @@ public class RollbackStoreTest {
|
||||
|
||||
@Test
|
||||
public void loadFromJsonNoExtensionVersions() throws Exception {
|
||||
Rollback expectedRb =
|
||||
mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null, null);
|
||||
Rollback expectedRb = mRollbackStore.createNonStagedRollback(
|
||||
ID, USER, INSTALLER, null, new SparseIntArray(0));
|
||||
|
||||
expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z"));
|
||||
expectedRb.setRestoreUserDataInProgress(true);
|
||||
@@ -337,7 +337,8 @@ public class RollbackStoreTest {
|
||||
|
||||
@Test
|
||||
public void saveAndDelete() {
|
||||
Rollback rollback = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null, null);
|
||||
Rollback rollback = mRollbackStore.createNonStagedRollback(
|
||||
ID, USER, INSTALLER, null, new SparseIntArray(0));
|
||||
|
||||
RollbackStore.saveRollback(rollback);
|
||||
|
||||
|
||||
@@ -24,12 +24,18 @@ import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.VersionedPackage;
|
||||
import android.content.rollback.PackageRollbackInfo;
|
||||
import android.util.IntArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.SparseLongArray;
|
||||
|
||||
import com.android.server.pm.PackageList;
|
||||
import com.android.server.pm.parsing.pkg.PackageImpl;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -44,6 +50,7 @@ import java.io.File;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class RollbackUnitTest {
|
||||
@@ -56,10 +63,17 @@ public class RollbackUnitTest {
|
||||
private static final String INSTALLER = "some.installer";
|
||||
|
||||
@Mock private AppDataRollbackHelper mMockDataHelper;
|
||||
@Mock private PackageManagerInternal mMockPmi;
|
||||
|
||||
private List<String> mPackages;
|
||||
private PackageList mPackageList;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mPackages = new ArrayList<>();
|
||||
mPackageList = new PackageList(mPackages, null);
|
||||
when(mMockPmi.getPackageList()).thenReturn(mPackageList);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -340,6 +354,85 @@ public class RollbackUnitTest {
|
||||
assertThat(rollback.allPackagesEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minExtVerConstraintNotViolated() {
|
||||
addPkgWithMinExtVersions("pkg0", new int[][] {{30, 4}});
|
||||
addPkgWithMinExtVersions("pkg1", new int[][] {});
|
||||
addPkgWithMinExtVersions("pkg2", new int[][] {{30, 5}, {31, 1}});
|
||||
addPkgWithMinExtVersions("pkg3", new int[][] {{31, 7}, {32, 15}});
|
||||
|
||||
assertThat(Rollback.extensionVersionReductionWouldViolateConstraint(
|
||||
sparseArrayFrom(new int[][] {{30, 5}}), mMockPmi)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minExtVerConstraintExists() {
|
||||
addPkgWithMinExtVersions("pkg0", null);
|
||||
addPkgWithMinExtVersions("pkg1", new int[][] {{30, 5}, {31, 1}});
|
||||
|
||||
assertThat(Rollback.extensionVersionReductionWouldViolateConstraint(
|
||||
sparseArrayFrom(new int[][] {{30, 4}}), mMockPmi)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minExtVerConstraintExistsOnOnePackage() {
|
||||
addPkgWithMinExtVersions("pkg0", new int[][] {{30, 4}});
|
||||
addPkgWithMinExtVersions("pkg1", new int[][] {});
|
||||
addPkgWithMinExtVersions("pkg2", new int[][] {{30, 5}, {31, 1}});
|
||||
addPkgWithMinExtVersions("pkg3", new int[][] {{31, 7}, {32, 15}});
|
||||
|
||||
assertThat(Rollback.extensionVersionReductionWouldViolateConstraint(
|
||||
sparseArrayFrom(new int[][] {{30, 4}}), mMockPmi)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minExtVerConstraintDifferentSdk() {
|
||||
addPkgWithMinExtVersions("pkg0", null);
|
||||
addPkgWithMinExtVersions("pkg1", new int[][] {{30, 5}, {31, 1}});
|
||||
|
||||
assertThat(Rollback.extensionVersionReductionWouldViolateConstraint(
|
||||
sparseArrayFrom(new int[][] {{32, 4}}), mMockPmi)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minExtVerConstraintNoneRecordedOnRollback() {
|
||||
addPkgWithMinExtVersions("pkg0", new int[][] {{30, 4}});
|
||||
addPkgWithMinExtVersions("pkg1", new int[][] {});
|
||||
addPkgWithMinExtVersions("pkg2", new int[][] {{30, 5}, {31, 1}});
|
||||
addPkgWithMinExtVersions("pkg3", new int[][] {{31, 7}, {32, 15}});
|
||||
|
||||
assertThat(Rollback.extensionVersionReductionWouldViolateConstraint(
|
||||
new SparseIntArray(0), mMockPmi)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minExtVerConstraintNoMinsRecorded() {
|
||||
addPkgWithMinExtVersions("pkg0", null);
|
||||
addPkgWithMinExtVersions("pkg1", null);
|
||||
|
||||
assertThat(Rollback.extensionVersionReductionWouldViolateConstraint(
|
||||
sparseArrayFrom(new int[][] {{32, 4}}), mMockPmi)).isFalse();
|
||||
}
|
||||
|
||||
private void addPkgWithMinExtVersions(String pkg, int[][] minExtVersions) {
|
||||
mPackages.add(pkg);
|
||||
PackageImpl pkgImpl = new PackageImpl(pkg, "baseCodePath", "codePath", null, false);
|
||||
pkgImpl.setMinExtensionVersions(sparseArrayFrom(minExtVersions));
|
||||
|
||||
when(mMockPmi.getPackage(pkg)).thenReturn(pkgImpl);
|
||||
}
|
||||
|
||||
private static SparseIntArray sparseArrayFrom(int[][] arr) {
|
||||
if (arr == null) {
|
||||
return null;
|
||||
}
|
||||
SparseIntArray result = new SparseIntArray(arr.length);
|
||||
for (int[] pair : arr) {
|
||||
result.put(pair[0], pair[1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static PackageRollbackInfo newPkgInfoFor(
|
||||
String packageName, long fromVersion, long toVersion, boolean isApex) {
|
||||
return new PackageRollbackInfo(new VersionedPackage(packageName, fromVersion),
|
||||
|
||||
Reference in New Issue
Block a user