Merge "Merge "Ensure race between rollback and roll forward is properly handled" into qt-dev am: 07a9e9f9f9" into qt-dev-plus-aosp

This commit is contained in:
Android Build Merger (Role)
2019-05-03 19:19:14 +00:00
committed by Android (Google) Code Review
11 changed files with 202 additions and 27 deletions

View File

@@ -1318,6 +1318,8 @@ public class PackageInstaller {
public boolean isMultiPackage;
/** {@hide} */
public boolean isStaged;
/** {@hide} */
public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
/**
* Construct parameters for a new package install session.
@@ -1350,6 +1352,7 @@ public class PackageInstaller {
installerPackageName = source.readString();
isMultiPackage = source.readBoolean();
isStaged = source.readBoolean();
requiredInstalledVersionCode = source.readLong();
}
/** {@hide} */
@@ -1372,6 +1375,7 @@ public class PackageInstaller {
ret.installerPackageName = installerPackageName;
ret.isMultiPackage = isMultiPackage;
ret.isStaged = isStaged;
ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
return ret;
}
@@ -1562,6 +1566,19 @@ public class PackageInstaller {
}
}
/**
* Require the given version of the package be installed.
* The install will only be allowed if the existing version code of
* the package installed on the device matches the given version code.
* Use {@link * PackageManager#VERSION_CODE_HIGHEST} to allow
* installation regardless of the currently installed package version.
*
* @hide
*/
public void setRequiredInstalledVersionCode(long versionCode) {
requiredInstalledVersionCode = versionCode;
}
/** {@hide} */
public void setInstallFlagsForcePermissionPrompt() {
installFlags |= PackageManager.INSTALL_FORCE_PERMISSION_PROMPT;
@@ -1703,6 +1720,7 @@ public class PackageInstaller {
pw.printPair("installerPackageName", installerPackageName);
pw.printPair("isMultiPackage", isMultiPackage);
pw.printPair("isStaged", isStaged);
pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
pw.println();
}
@@ -1731,6 +1749,7 @@ public class PackageInstaller {
dest.writeString(installerPackageName);
dest.writeBoolean(isMultiPackage);
dest.writeBoolean(isStaged);
dest.writeLong(requiredInstalledVersionCode);
}
public static final Parcelable.Creator<SessionParams>

View File

@@ -1423,6 +1423,14 @@ public abstract class PackageManager {
*/
public static final int INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY = -120;
/**
* Installation failed return code: the required installed version code
* does not match the currently installed package version code.
*
* @hide
*/
public static final int INSTALL_FAILED_WRONG_INSTALLED_VERSION = -121;
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
@@ -6918,6 +6926,7 @@ public abstract class PackageManager {
case INSTALL_FAILED_BAD_DEX_METADATA: return "INSTALL_FAILED_BAD_DEX_METADATA";
case INSTALL_FAILED_MISSING_SPLIT: return "INSTALL_FAILED_MISSING_SPLIT";
case INSTALL_FAILED_BAD_SIGNATURE: return "INSTALL_FAILED_BAD_SIGNATURE";
case INSTALL_FAILED_WRONG_INSTALLED_VERSION: return "INSTALL_FAILED_WRONG_INSTALLED_VERSION";
default: return Integer.toString(status);
}
}

View File

@@ -64,6 +64,8 @@ public class PackageHelper {
public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5;
public static final int RECOMMEND_FAILED_INVALID_URI = -6;
public static final int RECOMMEND_FAILED_VERSION_DOWNGRADE = -7;
/** {@hide} */
public static final int RECOMMEND_FAILED_WRONG_INSTALLED_VERSION = -8;
private static final String TAG = "PackageHelper";
// App installation location settings values

View File

@@ -14996,12 +14996,14 @@ public class PackageManagerService extends IPackageManager.Stub
final int installReason;
@Nullable
MultiPackageInstallParams mParentInstallParams;
final long requiredInstalledVersionCode;
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
PackageParser.SigningDetails signingDetails, int installReason) {
PackageParser.SigningDetails signingDetails, int installReason,
long requiredInstalledVersionCode) {
super(user);
this.origin = origin;
this.move = move;
@@ -15015,6 +15017,7 @@ public class PackageManagerService extends IPackageManager.Stub
this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
this.signingDetails = signingDetails;
this.installReason = installReason;
this.requiredInstalledVersionCode = requiredInstalledVersionCode;
}
InstallParams(ActiveInstallSession activeInstallSession) {
@@ -15045,6 +15048,8 @@ public class PackageManagerService extends IPackageManager.Stub
whitelistedRestrictedPermissions = activeInstallSession.getSessionParams()
.whitelistedRestrictedPermissions;
signingDetails = activeInstallSession.getSigningDetails();
requiredInstalledVersionCode = activeInstallSession.getSessionParams()
.requiredInstalledVersionCode;
}
@Override
@@ -15073,6 +15078,23 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
if (dataOwnerPkg == null) {
Slog.w(TAG, "Required installed version code was "
+ requiredInstalledVersionCode
+ " but package is not installed");
return PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION;
}
if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
Slog.w(TAG, "Required installed version code was "
+ requiredInstalledVersionCode
+ " but actual installed version is "
+ dataOwnerPkg.getLongVersionCode());
return PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION;
}
}
if (dataOwnerPkg != null) {
if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
dataOwnerPkg.applicationInfo.flags)) {
@@ -15199,6 +15221,8 @@ public class PackageManagerService extends IPackageManager.Stub
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
} else if (!onInt) {
// Override install location with flags
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
@@ -23311,7 +23335,7 @@ public class PackageManagerService extends IPackageManager.Stub
installerPackageName, volumeUuid, null /*verificationInfo*/, user,
packageAbiOverride, null /*grantedPermissions*/,
null /*whitelistedRestrictedPermissions*/, PackageParser.SigningDetails.UNKNOWN,
PackageManager.INSTALL_REASON_UNKNOWN);
PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.VERSION_CODE_HIGHEST);
params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;

View File

@@ -163,6 +163,22 @@ public class StagingManager {
continue;
}
long activeVersion = activePackage.applicationInfo.longVersionCode;
if (session.params.requiredInstalledVersionCode
!= PackageManager.VERSION_CODE_HIGHEST) {
if (activeVersion != session.params.requiredInstalledVersionCode) {
session.setStagedSessionFailed(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Installed version of APEX package " + newPackage.packageName
+ " does not match required. Active version: " + activeVersion
+ " required: " + session.params.requiredInstalledVersionCode);
if (!mApexManager.abortActiveSession()) {
Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
}
return false;
}
}
boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
session.params.installFlags, activePackage.applicationInfo.flags);
if (activeVersion > newPackage.versionCode && !allowsDowngrade) {

View File

@@ -357,31 +357,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
return;
}
// Verify the RollbackData is up to date with what's installed on
// device.
// TODO: We assume that between now and the time we commit the
// downgrade install, the currently installed package version does not
// change. This is not safe to assume, particularly in the case of a
// rollback racing with a roll-forward fix of a buggy package.
// Figure out how to ensure we don't commit the rollback if
// roll forward happens at the same time.
for (PackageRollbackInfo info : data.info.getPackages()) {
VersionedPackage installedVersion = getInstalledPackageVersion(info.getPackageName());
if (installedVersion == null) {
// TODO: Test this case
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
"Package to roll back is not installed");
return;
}
if (!packageVersionsEqual(info.getVersionRolledBackFrom(), installedVersion)) {
// TODO: Test this case
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
"Package version to roll back not installed.");
return;
}
}
// Get a context for the caller to use to install the downgraded
// version of the package.
Context context = null;
@@ -420,6 +395,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
}
params.setRequestDowngrade(true);
params.setRequiredInstalledVersionCode(
info.getVersionRolledBackFrom().getLongVersionCode());
if (data.isStaged()) {
params.setStaged();
}

View File

@@ -28,6 +28,14 @@ android_test_helper_app {
resource_dirs: ["TestApp/res_v2"],
}
android_test_helper_app {
name: "RollbackTestAppAv3",
manifest: "TestApp/Av3.xml",
sdk_version: "current",
srcs: ["TestApp/src/**/*.java"],
resource_dirs: ["TestApp/res_v3"],
}
android_test_helper_app {
name: "RollbackTestAppACrashingV2",
manifest: "TestApp/ACrashingV2.xml",
@@ -118,6 +126,7 @@ android_test {
java_resources: [
":RollbackTestAppAv1",
":RollbackTestAppAv2",
":RollbackTestAppAv3",
":RollbackTestAppACrashingV2",
":RollbackTestAppBv1",
":RollbackTestAppBv2",

View File

@@ -871,6 +871,51 @@ public class RollbackTest {
}
}
/**
* Test race between roll back and roll forward.
*/
@Test
public void testRollForwardRace() throws Exception {
try {
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
RollbackTestUtils.uninstall(TEST_APP_A);
RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
RollbackInfo rollback = getUniqueRollbackInfoForPackage(
rm.getAvailableRollbacks(), TEST_APP_A);
assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
// Install a new version of package A, then immediately rollback
// the previous version. We expect the rollback to fail, because
// it is no longer available.
// There are a couple different ways this could fail depending on
// thread interleaving, so don't ignore flaky failures.
RollbackTestUtils.install("RollbackTestAppAv3.apk", false);
try {
RollbackTestUtils.rollback(rollback.getRollbackId());
// Note: Don't ignore flaky failures here.
fail("Expected rollback to fail, but it did not.");
} catch (AssertionError e) {
Log.i(TAG, "Note expected failure: ", e);
// Expected
}
// Note: Don't ignore flaky failures here.
assertEquals(3, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
} finally {
RollbackTestUtils.dropShellPermissionIdentity();
}
}
// Helper function to test that the given rollback info is a rollback for
// the atomic set {A2, B2} -> {A1, B1}.
private void assertRollbackInfoForAandB(RollbackInfo rollback) {

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.tests.rollback.testapp.A"
android:versionCode="3"
android:versionName="3.0" >
<uses-sdk android:minSdkVersion="19" />
<application android:label="Rollback Test App A v3">
<receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.tests.rollback.testapp.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2019 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<integer name="split_version">3</integer>
</resources>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2019 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<integer name="app_version">3</integer>
<integer name="split_version">0</integer>
</resources>