Merge changes from topic "apex-installers-restriction" into sc-dev
* changes: Reject non-staged APEX install if there is staged install of same APEX Restrict what APEXes different installers can update
This commit is contained in:
@@ -241,7 +241,11 @@ public class SystemConfig {
|
|||||||
|
|
||||||
private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
|
private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
|
||||||
private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>();
|
private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>();
|
||||||
private final ArraySet<String> mAllowedVendorApexes = new ArraySet<>();
|
// A map from package name of vendor APEXes that can be updated to an installer package name
|
||||||
|
// allowed to install updates for it.
|
||||||
|
private final ArrayMap<String, String> mAllowedVendorApexes = new ArrayMap<>();
|
||||||
|
|
||||||
|
private String mModulesInstallerPackageName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of system pre-defined, uniquely named actors; keys are namespace,
|
* Map of system pre-defined, uniquely named actors; keys are namespace,
|
||||||
@@ -412,10 +416,14 @@ public class SystemConfig {
|
|||||||
return mWhitelistedStagedInstallers;
|
return mWhitelistedStagedInstallers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getAllowedVendorApexes() {
|
public Map<String, String> getAllowedVendorApexes() {
|
||||||
return mAllowedVendorApexes;
|
return mAllowedVendorApexes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getModulesInstallerPackageName() {
|
||||||
|
return mModulesInstallerPackageName;
|
||||||
|
}
|
||||||
|
|
||||||
public ArraySet<String> getAppDataIsolationWhitelistedApps() {
|
public ArraySet<String> getAppDataIsolationWhitelistedApps() {
|
||||||
return mAppDataIsolationWhitelistedApps;
|
return mAppDataIsolationWhitelistedApps;
|
||||||
}
|
}
|
||||||
@@ -1210,12 +1218,21 @@ public class SystemConfig {
|
|||||||
case "whitelisted-staged-installer": {
|
case "whitelisted-staged-installer": {
|
||||||
if (allowAppConfigs) {
|
if (allowAppConfigs) {
|
||||||
String pkgname = parser.getAttributeValue(null, "package");
|
String pkgname = parser.getAttributeValue(null, "package");
|
||||||
|
boolean isModulesInstaller = XmlUtils.readBooleanAttribute(
|
||||||
|
parser, "isModulesInstaller", false);
|
||||||
if (pkgname == null) {
|
if (pkgname == null) {
|
||||||
Slog.w(TAG, "<" + name + "> without package in " + permFile
|
Slog.w(TAG, "<" + name + "> without package in " + permFile
|
||||||
+ " at " + parser.getPositionDescription());
|
+ " at " + parser.getPositionDescription());
|
||||||
} else {
|
} else {
|
||||||
mWhitelistedStagedInstallers.add(pkgname);
|
mWhitelistedStagedInstallers.add(pkgname);
|
||||||
}
|
}
|
||||||
|
if (isModulesInstaller) {
|
||||||
|
if (mModulesInstallerPackageName != null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Multiple modules installers");
|
||||||
|
}
|
||||||
|
mModulesInstallerPackageName = pkgname;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logNotAllowedInPartition(name, permFile, parser);
|
logNotAllowedInPartition(name, permFile, parser);
|
||||||
}
|
}
|
||||||
@@ -1224,11 +1241,18 @@ public class SystemConfig {
|
|||||||
case "allowed-vendor-apex": {
|
case "allowed-vendor-apex": {
|
||||||
if (allowVendorApex) {
|
if (allowVendorApex) {
|
||||||
String pkgName = parser.getAttributeValue(null, "package");
|
String pkgName = parser.getAttributeValue(null, "package");
|
||||||
|
String installerPkgName = parser.getAttributeValue(
|
||||||
|
null, "installerPackage");
|
||||||
if (pkgName == null) {
|
if (pkgName == null) {
|
||||||
Slog.w(TAG, "<" + name + "> without package in " + permFile
|
Slog.w(TAG, "<" + name + "> without package in " + permFile
|
||||||
+ " at " + parser.getPositionDescription());
|
+ " at " + parser.getPositionDescription());
|
||||||
} else {
|
}
|
||||||
mAllowedVendorApexes.add(pkgName);
|
if (installerPkgName == null) {
|
||||||
|
Slog.w(TAG, "<" + name + "> without installerPackage in " + permFile
|
||||||
|
+ " at " + parser.getPositionDescription());
|
||||||
|
}
|
||||||
|
if (pkgName != null && installerPkgName != null) {
|
||||||
|
mAllowedVendorApexes.put(pkgName, installerPkgName);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logNotAllowedInPartition(name, permFile, parser);
|
logNotAllowedInPartition(name, permFile, parser);
|
||||||
|
|||||||
@@ -2252,12 +2252,29 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
|||||||
(params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK)
|
(params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK)
|
||||||
== 0;
|
== 0;
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName)) {
|
if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName,
|
||||||
|
mInstallSource.installerPackageName)) {
|
||||||
onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
|
onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
|
||||||
"Update of APEX package " + mPackageName + " is not allowed");
|
"Update of APEX package " + mPackageName + " is not allowed for "
|
||||||
|
+ mInstallSource.installerPackageName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!params.isStaged) {
|
||||||
|
// For non-staged APEX installs also check if there is a staged session that
|
||||||
|
// contains the same APEX. If that's the case, we should fail this session.
|
||||||
|
synchronized (mLock) {
|
||||||
|
int sessionId = mStagingManager.getSessionIdByPackageName(mPackageName);
|
||||||
|
if (sessionId != -1) {
|
||||||
|
onSessionValidationFailure(
|
||||||
|
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
|
||||||
|
"Staged session " + sessionId + " already contains "
|
||||||
|
+ mPackageName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.isStaged) {
|
if (params.isStaged) {
|
||||||
@@ -2798,9 +2815,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
|||||||
return sessionContains((s) -> !s.isApexSession());
|
return sessionContains((s) -> !s.isApexSession());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isApexUpdateAllowed(String apexPackageName) {
|
private boolean isApexUpdateAllowed(String apexPackageName, String installerPackageName) {
|
||||||
return mPm.getModuleInfo(apexPackageName, 0) != null
|
if (mPm.getModuleInfo(apexPackageName, 0) != null) {
|
||||||
|| SystemConfig.getInstance().getAllowedVendorApexes().contains(apexPackageName);
|
final String modulesInstaller =
|
||||||
|
SystemConfig.getInstance().getModulesInstallerPackageName();
|
||||||
|
if (modulesInstaller == null) {
|
||||||
|
Slog.w(TAG, "No modules installer defined");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return modulesInstaller.equals(installerPackageName);
|
||||||
|
}
|
||||||
|
final String vendorApexInstaller =
|
||||||
|
SystemConfig.getInstance().getAllowedVendorApexes().get(apexPackageName);
|
||||||
|
if (vendorApexInstaller == null) {
|
||||||
|
Slog.w(TAG, apexPackageName + " is not allowed to be updated");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return vendorApexInstaller.equals(installerPackageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -777,6 +777,26 @@ public class StagingManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns id of a committed and non-finalized stated session that contains same
|
||||||
|
* {@code packageName}, or {@code -1} if no sessions have this {@code packageName} staged.
|
||||||
|
*/
|
||||||
|
int getSessionIdByPackageName(@NonNull String packageName) {
|
||||||
|
synchronized (mStagedSessions) {
|
||||||
|
for (int i = 0; i < mStagedSessions.size(); i++) {
|
||||||
|
StagedSession stagedSession = mStagedSessions.valueAt(i);
|
||||||
|
if (!stagedSession.isCommitted() || stagedSession.isDestroyed()
|
||||||
|
|| stagedSession.isInTerminalState()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (stagedSession.getPackageName().equals(packageName)) {
|
||||||
|
return stagedSession.sessionId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void createSession(@NonNull StagedSession sessionInfo) {
|
void createSession(@NonNull StagedSession sessionInfo) {
|
||||||
synchronized (mStagedSessions) {
|
synchronized (mStagedSessions) {
|
||||||
|
|||||||
@@ -459,6 +459,66 @@ public class StagingManagerTest {
|
|||||||
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
|
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSessionIdByPackageName() throws Exception {
|
||||||
|
FakeStagedSession session = new FakeStagedSession(239);
|
||||||
|
session.setCommitted(true);
|
||||||
|
session.setSessionReady();
|
||||||
|
session.setPackageName("com.foo");
|
||||||
|
|
||||||
|
mStagingManager.createSession(session);
|
||||||
|
assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(239);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSessionIdByPackageName_appliedSession_ignores() throws Exception {
|
||||||
|
FakeStagedSession session = new FakeStagedSession(37);
|
||||||
|
session.setCommitted(true);
|
||||||
|
session.setSessionApplied();
|
||||||
|
session.setPackageName("com.foo");
|
||||||
|
|
||||||
|
mStagingManager.createSession(session);
|
||||||
|
assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSessionIdByPackageName_failedSession_ignores() throws Exception {
|
||||||
|
FakeStagedSession session = new FakeStagedSession(73);
|
||||||
|
session.setCommitted(true);
|
||||||
|
session.setSessionFailed(1, "whatevs");
|
||||||
|
session.setPackageName("com.foo");
|
||||||
|
|
||||||
|
mStagingManager.createSession(session);
|
||||||
|
assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSessionIdByPackageName_destroyedSession_ignores() throws Exception {
|
||||||
|
FakeStagedSession session = new FakeStagedSession(23);
|
||||||
|
session.setCommitted(true);
|
||||||
|
session.setDestroyed(true);
|
||||||
|
session.setPackageName("com.foo");
|
||||||
|
|
||||||
|
mStagingManager.createSession(session);
|
||||||
|
assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSessionIdByPackageName_noSessions() throws Exception {
|
||||||
|
assertThat(mStagingManager.getSessionIdByPackageName("com.foo")).isEqualTo(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSessionIdByPackageName_noSessionHasThisPackage() throws Exception {
|
||||||
|
FakeStagedSession session = new FakeStagedSession(37);
|
||||||
|
session.setCommitted(true);
|
||||||
|
session.setSessionApplied();
|
||||||
|
session.setPackageName("com.foo");
|
||||||
|
|
||||||
|
mStagingManager.createSession(session);
|
||||||
|
assertThat(mStagingManager.getSessionIdByPackageName("com.bar")).isEqualTo(-1);
|
||||||
|
}
|
||||||
|
|
||||||
private StagingManager.StagedSession createSession(int sessionId, String packageName,
|
private StagingManager.StagedSession createSession(int sessionId, String packageName,
|
||||||
long committedMillis) {
|
long committedMillis) {
|
||||||
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
|
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.server.systemconfig;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.expectThrows;
|
||||||
|
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
@@ -200,6 +201,46 @@ public class SystemConfigTest {
|
|||||||
|
|
||||||
assertThat(mSysConfig.getWhitelistedStagedInstallers())
|
assertThat(mSysConfig.getWhitelistedStagedInstallers())
|
||||||
.containsExactly("com.android.package1");
|
.containsExactly("com.android.package1");
|
||||||
|
assertThat(mSysConfig.getModulesInstallerPackageName()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readPermissions_parsesStagedInstallerWhitelist_modulesInstaller()
|
||||||
|
throws IOException {
|
||||||
|
final String contents =
|
||||||
|
"<config>\n"
|
||||||
|
+ " <whitelisted-staged-installer package=\"com.android.package1\" "
|
||||||
|
+ " isModulesInstaller=\"true\" />\n"
|
||||||
|
+ "</config>";
|
||||||
|
final File folder = createTempSubfolder("folder");
|
||||||
|
createTempFile(folder, "staged-installer-whitelist.xml", contents);
|
||||||
|
|
||||||
|
mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
|
||||||
|
|
||||||
|
assertThat(mSysConfig.getWhitelistedStagedInstallers())
|
||||||
|
.containsExactly("com.android.package1");
|
||||||
|
assertThat(mSysConfig.getModulesInstallerPackageName())
|
||||||
|
.isEqualTo("com.android.package1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readPermissions_parsesStagedInstallerWhitelist_multipleModulesInstallers()
|
||||||
|
throws IOException {
|
||||||
|
final String contents =
|
||||||
|
"<config>\n"
|
||||||
|
+ " <whitelisted-staged-installer package=\"com.android.package1\" "
|
||||||
|
+ " isModulesInstaller=\"true\" />\n"
|
||||||
|
+ " <whitelisted-staged-installer package=\"com.android.package2\" "
|
||||||
|
+ " isModulesInstaller=\"true\" />\n"
|
||||||
|
+ "</config>";
|
||||||
|
final File folder = createTempSubfolder("folder");
|
||||||
|
createTempFile(folder, "staged-installer-whitelist.xml", contents);
|
||||||
|
|
||||||
|
IllegalStateException e = expectThrows(
|
||||||
|
IllegalStateException.class,
|
||||||
|
() -> mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0));
|
||||||
|
|
||||||
|
assertThat(e).hasMessageThat().contains("Multiple modules installers");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -230,14 +271,16 @@ public class SystemConfigTest {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
final String contents =
|
final String contents =
|
||||||
"<config>\n"
|
"<config>\n"
|
||||||
+ " <allowed-vendor-apex package=\"com.android.apex1\" />\n"
|
+ " <allowed-vendor-apex package=\"com.android.apex1\" "
|
||||||
|
+ "installerPackage=\"com.installer\" />\n"
|
||||||
+ "</config>";
|
+ "</config>";
|
||||||
final File folder = createTempSubfolder("folder");
|
final File folder = createTempSubfolder("folder");
|
||||||
createTempFile(folder, "vendor-apex-allowlist.xml", contents);
|
createTempFile(folder, "vendor-apex-allowlist.xml", contents);
|
||||||
|
|
||||||
mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
|
mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
|
||||||
|
|
||||||
assertThat(mSysConfig.getAllowedVendorApexes()).containsExactly("com.android.apex1");
|
assertThat(mSysConfig.getAllowedVendorApexes())
|
||||||
|
.containsExactly("com.android.apex1", "com.installer");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ android_test_helper_app {
|
|||||||
test_suites: ["general-tests"],
|
test_suites: ["general-tests"],
|
||||||
java_resources: [
|
java_resources: [
|
||||||
":com.android.apex.apkrollback.test_v2",
|
":com.android.apex.apkrollback.test_v2",
|
||||||
|
":StagedInstallTestApexV2",
|
||||||
":StagedInstallTestApexV2_WrongSha",
|
":StagedInstallTestApexV2_WrongSha",
|
||||||
":test.rebootless_apex_v1",
|
":test.rebootless_apex_v1",
|
||||||
":test.rebootless_apex_v2",
|
":test.rebootless_apex_v2",
|
||||||
|
|||||||
@@ -55,8 +55,11 @@ public class StagedInstallInternalTest {
|
|||||||
private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
|
private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
|
||||||
APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
|
APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
|
||||||
private static final TestApp APEX_WRONG_SHA_V2 = new TestApp(
|
private static final TestApp APEX_WRONG_SHA_V2 = new TestApp(
|
||||||
"ApexWrongSha2", SHIM_APEX_PACKAGE_NAME, 2, /*isApex*/true,
|
"ApexWrongSha2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
|
||||||
"com.android.apex.cts.shim.v2_wrong_sha.apex");
|
"com.android.apex.cts.shim.v2_wrong_sha.apex");
|
||||||
|
private static final TestApp APEX_V2 = new TestApp(
|
||||||
|
"ApexV2", SHIM_APEX_PACKAGE_NAME, 2, /* isApex= */ true,
|
||||||
|
"com.android.apex.cts.shim.v2.apex");
|
||||||
|
|
||||||
private File mTestStateFile = new File(
|
private File mTestStateFile = new File(
|
||||||
InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
|
InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(),
|
||||||
@@ -236,6 +239,96 @@ public class StagedInstallInternalTest {
|
|||||||
assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
|
assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApexInstallerNotInAllowListCanNotInstall_staged() throws Exception {
|
||||||
|
assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
|
||||||
|
// We don't really care which APEX we are trying to install here, since the session creation
|
||||||
|
// should fail immediately.
|
||||||
|
InstallUtils.commitExpectingFailure(
|
||||||
|
SecurityException.class,
|
||||||
|
"Installer not allowed to commit staged install",
|
||||||
|
Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false)
|
||||||
|
.setStaged());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApexInstallerNotInAllowListCanNotInstall_nonStaged() throws Exception {
|
||||||
|
assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
|
||||||
|
// We don't really care which APEX we are trying to install here, since the session creation
|
||||||
|
// should fail immediately.
|
||||||
|
InstallUtils.commitExpectingFailure(
|
||||||
|
SecurityException.class,
|
||||||
|
"Installer not allowed to commit non-staged APEX install",
|
||||||
|
Install.single(APEX_WRONG_SHA_V2).setBypassStangedInstallerCheck(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApexNotInAllowListCanNotInstall_staged() throws Exception {
|
||||||
|
assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
|
||||||
|
TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
|
||||||
|
/* isApex= */ true, "test.rebootless_apex_v2.apex");
|
||||||
|
InstallUtils.commitExpectingFailure(
|
||||||
|
AssertionError.class,
|
||||||
|
"Update of APEX package test.apex.rebootless is not allowed "
|
||||||
|
+ "for com.android.tests.stagedinstallinternal",
|
||||||
|
Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApexNotInAllowListCanNotInstall_nonStaged() throws Exception {
|
||||||
|
assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
|
||||||
|
TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
|
||||||
|
/* isApex= */ true, "test.rebootless_apex_v2.apex");
|
||||||
|
InstallUtils.commitExpectingFailure(
|
||||||
|
AssertionError.class,
|
||||||
|
"Update of APEX package test.apex.rebootless is not allowed "
|
||||||
|
+ "for com.android.tests.stagedinstallinternal",
|
||||||
|
Install.single(apex).setBypassAllowedApexUpdateCheck(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVendorApexWrongInstaller_staged() throws Exception {
|
||||||
|
assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
|
||||||
|
TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
|
||||||
|
/* isApex= */ true, "test.rebootless_apex_v2.apex");
|
||||||
|
InstallUtils.commitExpectingFailure(
|
||||||
|
AssertionError.class,
|
||||||
|
"Update of APEX package test.apex.rebootless is not allowed "
|
||||||
|
+ "for com.android.tests.stagedinstallinternal",
|
||||||
|
Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVendorApexWrongInstaller_nonStaged() throws Exception {
|
||||||
|
assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
|
||||||
|
TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
|
||||||
|
/* isApex= */ true, "test.rebootless_apex_v2.apex");
|
||||||
|
InstallUtils.commitExpectingFailure(
|
||||||
|
AssertionError.class,
|
||||||
|
"Update of APEX package test.apex.rebootless is not allowed "
|
||||||
|
+ "for com.android.tests.stagedinstallinternal",
|
||||||
|
Install.single(apex).setBypassAllowedApexUpdateCheck(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVendorApexCorrectInstaller_staged() throws Exception {
|
||||||
|
assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
|
||||||
|
TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
|
||||||
|
/* isApex= */ true, "test.rebootless_apex_v2.apex");
|
||||||
|
int sessionId =
|
||||||
|
Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged().commit();
|
||||||
|
InstallUtils.getPackageInstaller().abandonSession(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVendorApexCorrectInstaller_nonStaged() throws Exception {
|
||||||
|
assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1);
|
||||||
|
TestApp apex = new TestApp("apex", "test.apex.rebootless", 2,
|
||||||
|
/* isApex= */ true, "test.rebootless_apex_v2.apex");
|
||||||
|
Install.single(apex).setBypassAllowedApexUpdateCheck(false).commit();
|
||||||
|
assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRebootlessUpdates() throws Exception {
|
public void testRebootlessUpdates() throws Exception {
|
||||||
InstallUtils.dropShellPermissionIdentity();
|
InstallUtils.dropShellPermissionIdentity();
|
||||||
@@ -298,6 +391,19 @@ public class StagedInstallInternalTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
|
||||||
|
assertThat(InstallUtils.getInstalledVersion(SHIM_APEX_PACKAGE_NAME)).isEqualTo(1);
|
||||||
|
|
||||||
|
int sessionId = Install.single(APEX_V2).setStaged().commit();
|
||||||
|
assertSessionReady(sessionId);
|
||||||
|
InstallUtils.commitExpectingFailure(
|
||||||
|
AssertionError.class,
|
||||||
|
"Staged session " + sessionId + " already contains " + SHIM_APEX_PACKAGE_NAME,
|
||||||
|
Install.single(APEX_V2));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static void assertSessionApplied(int sessionId) {
|
private static void assertSessionApplied(int sessionId) {
|
||||||
assertSessionState(sessionId, (session) -> {
|
assertSessionState(sessionId, (session) -> {
|
||||||
assertThat(session.isStagedSessionApplied()).isTrue();
|
assertThat(session.isStagedSessionApplied()).isTrue();
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ import org.junit.Rule;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -60,6 +62,9 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
|
|||||||
private static final String APK_A = "TestAppAv1.apk";
|
private static final String APK_A = "TestAppAv1.apk";
|
||||||
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
|
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
|
||||||
|
|
||||||
|
private static final String TEST_VENDOR_APEX_ALLOW_LIST =
|
||||||
|
"/vendor/etc/sysconfig/test-vendor-apex-allow-list.xml";
|
||||||
|
|
||||||
private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
|
private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,7 +92,8 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
|
|||||||
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
|
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
|
||||||
"/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
|
"/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
|
||||||
"/system/apex/test.rebootless_apex_v1.apex",
|
"/system/apex/test.rebootless_apex_v1.apex",
|
||||||
"/data/apex/active/test.apex.rebootless*.apex");
|
"/data/apex/active/test.apex.rebootless*.apex",
|
||||||
|
TEST_VENDOR_APEX_ALLOW_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -134,7 +140,23 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
|
|||||||
}
|
}
|
||||||
getDevice().remountSystemWritable();
|
getDevice().remountSystemWritable();
|
||||||
assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
|
assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
|
||||||
getDevice().reboot();
|
}
|
||||||
|
|
||||||
|
private void pushTestVendorApexAllowList(String installerPackageName) throws Exception {
|
||||||
|
if (!getDevice().isAdbRoot()) {
|
||||||
|
getDevice().enableAdbRoot();
|
||||||
|
}
|
||||||
|
getDevice().remountSystemWritable();
|
||||||
|
File file = File.createTempFile("test-vendor-apex-allow-list", ".xml");
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||||
|
final String fmt =
|
||||||
|
"<config>\n"
|
||||||
|
+ " <allowed-vendor-apex package=\"test.apex.rebootless\" "
|
||||||
|
+ " installerPackage=\"%s\" />\n"
|
||||||
|
+ "</config>";
|
||||||
|
writer.write(String.format(fmt, installerPackageName));
|
||||||
|
}
|
||||||
|
getDevice().pushFile(file, TEST_VENDOR_APEX_ALLOW_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -144,6 +166,8 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
|
|||||||
@LargeTest
|
@LargeTest
|
||||||
public void testDuplicateApkInApexShouldFail() throws Exception {
|
public void testDuplicateApkInApexShouldFail() throws Exception {
|
||||||
pushTestApex(APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
|
pushTestApex(APK_IN_APEX_TESTAPEX_NAME + "_v1.apex");
|
||||||
|
getDevice().reboot();
|
||||||
|
|
||||||
runPhase("testDuplicateApkInApexShouldFail_Commit");
|
runPhase("testDuplicateApkInApexShouldFail_Commit");
|
||||||
getDevice().reboot();
|
getDevice().reboot();
|
||||||
runPhase("testDuplicateApkInApexShouldFail_Verify");
|
runPhase("testDuplicateApkInApexShouldFail_Verify");
|
||||||
@@ -388,12 +412,72 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
|
|||||||
runPhase("testApexIsNotActivatedIfNotInCheckpointMode_VerifyPostReboot");
|
runPhase("testApexIsNotActivatedIfNotInCheckpointMode_VerifyPostReboot");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApexInstallerNotInAllowListCanNotInstall() throws Exception {
|
||||||
|
assumeTrue("Device does not support updating APEX",
|
||||||
|
mHostUtils.isApexUpdateSupported());
|
||||||
|
|
||||||
|
runPhase("testApexInstallerNotInAllowListCanNotInstall_staged");
|
||||||
|
runPhase("testApexInstallerNotInAllowListCanNotInstall_nonStaged");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@LargeTest
|
||||||
|
public void testApexNotInAllowListCanNotInstall() throws Exception {
|
||||||
|
assumeTrue("Device does not support updating APEX",
|
||||||
|
mHostUtils.isApexUpdateSupported());
|
||||||
|
|
||||||
|
pushTestApex("test.rebootless_apex_v1.apex");
|
||||||
|
getDevice().reboot();
|
||||||
|
|
||||||
|
runPhase("testApexNotInAllowListCanNotInstall_staged");
|
||||||
|
runPhase("testApexNotInAllowListCanNotInstall_nonStaged");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@LargeTest
|
||||||
|
public void testVendorApexWrongInstaller() throws Exception {
|
||||||
|
assumeTrue("Device does not support updating APEX",
|
||||||
|
mHostUtils.isApexUpdateSupported());
|
||||||
|
|
||||||
|
pushTestVendorApexAllowList("com.wrong.installer");
|
||||||
|
pushTestApex("test.rebootless_apex_v1.apex");
|
||||||
|
getDevice().reboot();
|
||||||
|
|
||||||
|
runPhase("testVendorApexWrongInstaller_staged");
|
||||||
|
runPhase("testVendorApexWrongInstaller_nonStaged");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@LargeTest
|
||||||
|
public void testVendorApexCorrectInstaller() throws Exception {
|
||||||
|
assumeTrue("Device does not support updating APEX",
|
||||||
|
mHostUtils.isApexUpdateSupported());
|
||||||
|
|
||||||
|
pushTestVendorApexAllowList("com.android.tests.stagedinstallinternal");
|
||||||
|
pushTestApex("test.rebootless_apex_v1.apex");
|
||||||
|
getDevice().reboot();
|
||||||
|
|
||||||
|
runPhase("testVendorApexCorrectInstaller_staged");
|
||||||
|
runPhase("testVendorApexCorrectInstaller_nonStaged");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRebootlessUpdates() throws Exception {
|
public void testRebootlessUpdates() throws Exception {
|
||||||
pushTestApex("test.rebootless_apex_v1.apex");
|
pushTestApex("test.rebootless_apex_v1.apex");
|
||||||
|
getDevice().reboot();
|
||||||
|
|
||||||
runPhase("testRebootlessUpdates");
|
runPhase("testRebootlessUpdates");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRebootlessUpdate_hasStagedSessionWithSameApex_fails() throws Exception {
|
||||||
|
assumeTrue("Device does not support updating APEX",
|
||||||
|
mHostUtils.isApexUpdateSupported());
|
||||||
|
|
||||||
|
runPhase("testRebootlessUpdate_hasStagedSessionWithSameApex_fails");
|
||||||
|
}
|
||||||
|
|
||||||
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
|
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
|
||||||
String baseDir = "/data/app-staging";
|
String baseDir = "/data/app-staging";
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user