Merge changes from topic "invalidate_idmap" into rvc-dev am: 6cb79cdfb7 am: 7cfbff64eb am: 3c0b8da2c1
Change-Id: Ic6a4dfa3b1955aa516924835fc506f241f9f0fad
This commit is contained in:
@@ -3,5 +3,10 @@
|
|||||||
{
|
{
|
||||||
"name" : "idmap2_tests"
|
"name" : "idmap2_tests"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"imports": [
|
||||||
|
{
|
||||||
|
"path": "frameworks/base/services/core/java/com/android/server/om"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,15 +149,21 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path,
|
|||||||
return error(idmap.GetErrorMessage());
|
return error(idmap.GetErrorMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap guarantees
|
||||||
|
// that existing memory maps will continue to be valid and unaffected.
|
||||||
|
unlink(idmap_path.c_str());
|
||||||
|
|
||||||
umask(kIdmapFilePermissionMask);
|
umask(kIdmapFilePermissionMask);
|
||||||
std::ofstream fout(idmap_path);
|
std::ofstream fout(idmap_path);
|
||||||
if (fout.fail()) {
|
if (fout.fail()) {
|
||||||
return error("failed to open idmap path " + idmap_path);
|
return error("failed to open idmap path " + idmap_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryStreamVisitor visitor(fout);
|
BinaryStreamVisitor visitor(fout);
|
||||||
(*idmap)->accept(&visitor);
|
(*idmap)->accept(&visitor);
|
||||||
fout.close();
|
fout.close();
|
||||||
if (fout.fail()) {
|
if (fout.fail()) {
|
||||||
|
unlink(idmap_path.c_str());
|
||||||
return error("failed to write to idmap path " + idmap_path);
|
return error("failed to write to idmap path " + idmap_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ public class ResourcesManager {
|
|||||||
ApkAssets apkAssets = null;
|
ApkAssets apkAssets = null;
|
||||||
if (mLoadedApkAssets != null) {
|
if (mLoadedApkAssets != null) {
|
||||||
apkAssets = mLoadedApkAssets.get(newKey);
|
apkAssets = mLoadedApkAssets.get(newKey);
|
||||||
if (apkAssets != null) {
|
if (apkAssets != null && apkAssets.isUpToDate()) {
|
||||||
return apkAssets;
|
return apkAssets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,7 +353,7 @@ public class ResourcesManager {
|
|||||||
final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey);
|
final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey);
|
||||||
if (apkAssetsRef != null) {
|
if (apkAssetsRef != null) {
|
||||||
apkAssets = apkAssetsRef.get();
|
apkAssets = apkAssetsRef.get();
|
||||||
if (apkAssets != null) {
|
if (apkAssets != null && apkAssets.isUpToDate()) {
|
||||||
if (mLoadedApkAssets != null) {
|
if (mLoadedApkAssets != null) {
|
||||||
mLoadedApkAssets.put(newKey, apkAssets);
|
mLoadedApkAssets.put(newKey, apkAssets);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ java_test_host {
|
|||||||
name: "OverlayHostTests",
|
name: "OverlayHostTests",
|
||||||
srcs: ["src/**/*.java"],
|
srcs: ["src/**/*.java"],
|
||||||
libs: ["tradefed"],
|
libs: ["tradefed"],
|
||||||
test_suites: ["general-tests"],
|
test_suites: ["device-tests"],
|
||||||
target_required: [
|
target_required: [
|
||||||
"OverlayHostTests_NonPlatformSignatureOverlay",
|
"OverlayHostTests_NonPlatformSignatureOverlay",
|
||||||
"OverlayHostTests_PlatformSignatureStaticOverlay",
|
"OverlayHostTests_PlatformSignatureStaticOverlay",
|
||||||
|
|||||||
@@ -78,14 +78,9 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void failToInstallPlatformSignedStaticOverlay() throws Exception {
|
public void installedIsStaticOverlayIsMutable() throws Exception {
|
||||||
try {
|
installPackage("OverlayHostTests_PlatformSignatureStaticOverlay.apk");
|
||||||
installPackage("OverlayHostTests_PlatformSignatureStaticOverlay.apk");
|
assertTrue(isOverlayMutable(SIG_OVERLAY_PACKAGE_NAME));
|
||||||
fail("installed a static overlay");
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Expected.
|
|
||||||
}
|
|
||||||
assertFalse(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -229,6 +224,10 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
|
|||||||
return shell("cmd overlay list").contains(pkg);
|
return shell("cmd overlay list").contains(pkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOverlayMutable(String pkg) throws Exception {
|
||||||
|
return shell("cmd overlay dump ismutable " + pkg).contains("true");
|
||||||
|
}
|
||||||
|
|
||||||
private String shell(final String cmd) throws Exception {
|
private String shell(final String cmd) throws Exception {
|
||||||
return getDevice().executeShellCommand(cmd);
|
return getDevice().executeShellCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
LOCAL_PACKAGE_NAME := OverlayHostTests_NonPlatformSignatureOverlay
|
LOCAL_PACKAGE_NAME := OverlayHostTests_NonPlatformSignatureOverlay
|
||||||
LOCAL_SDK_VERSION := current
|
LOCAL_SDK_VERSION := current
|
||||||
LOCAL_COMPATIBILITY_SUITE := general-tests
|
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||||
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad
|
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad
|
||||||
include $(BUILD_PACKAGE)
|
include $(BUILD_PACKAGE)
|
||||||
|
|
||||||
@@ -28,7 +28,8 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureStaticOverlay
|
LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureStaticOverlay
|
||||||
LOCAL_SDK_VERSION := current
|
LOCAL_SDK_VERSION := current
|
||||||
LOCAL_COMPATIBILITY_SUITE := general-tests
|
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||||
|
LOCAL_CERTIFICATE := platform
|
||||||
LOCAL_MANIFEST_FILE := static/AndroidManifest.xml
|
LOCAL_MANIFEST_FILE := static/AndroidManifest.xml
|
||||||
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_static
|
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_static
|
||||||
include $(BUILD_PACKAGE)
|
include $(BUILD_PACKAGE)
|
||||||
@@ -37,7 +38,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureOverlay
|
LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureOverlay
|
||||||
LOCAL_SDK_VERSION := current
|
LOCAL_SDK_VERSION := current
|
||||||
LOCAL_COMPATIBILITY_SUITE := general-tests
|
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||||
LOCAL_CERTIFICATE := platform
|
LOCAL_CERTIFICATE := platform
|
||||||
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
|
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
|
||||||
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
|
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ LOCAL_MODULE_TAGS := tests
|
|||||||
LOCAL_SRC_FILES := $(call all-java-files-under,src)
|
LOCAL_SRC_FILES := $(call all-java-files-under,src)
|
||||||
LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay
|
LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay
|
||||||
LOCAL_SDK_VERSION := current
|
LOCAL_SDK_VERSION := current
|
||||||
LOCAL_COMPATIBILITY_SUITE := general-tests
|
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||||
LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
|
LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
|
||||||
LOCAL_USE_AAPT2 := true
|
LOCAL_USE_AAPT2 := true
|
||||||
LOCAL_AAPT_FLAGS := --no-resource-removal
|
LOCAL_AAPT_FLAGS := --no-resource-removal
|
||||||
@@ -31,7 +31,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV1
|
LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV1
|
||||||
LOCAL_SDK_VERSION := current
|
LOCAL_SDK_VERSION := current
|
||||||
LOCAL_COMPATIBILITY_SUITE := general-tests
|
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||||
LOCAL_CERTIFICATE := platform
|
LOCAL_CERTIFICATE := platform
|
||||||
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
|
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
|
||||||
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
|
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
|
||||||
@@ -43,7 +43,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV2
|
LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV2
|
||||||
LOCAL_SDK_VERSION := current
|
LOCAL_SDK_VERSION := current
|
||||||
LOCAL_COMPATIBILITY_SUITE := general-tests
|
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||||
LOCAL_CERTIFICATE := platform
|
LOCAL_CERTIFICATE := platform
|
||||||
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
|
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
|
||||||
LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
|
LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
|
||||||
@@ -57,7 +57,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1
|
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1
|
||||||
LOCAL_SDK_VERSION := current
|
LOCAL_SDK_VERSION := current
|
||||||
LOCAL_COMPATIBILITY_SUITE := general-tests
|
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||||
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
|
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
|
||||||
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
|
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
|
||||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res
|
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res
|
||||||
@@ -68,7 +68,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2
|
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2
|
||||||
LOCAL_SDK_VERSION := current
|
LOCAL_SDK_VERSION := current
|
||||||
LOCAL_COMPATIBILITY_SUITE := general-tests
|
LOCAL_COMPATIBILITY_SUITE := device-tests
|
||||||
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
|
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
|
||||||
LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
|
LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
|
||||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res
|
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res
|
||||||
|
|||||||
@@ -24,5 +24,7 @@ java_test_host {
|
|||||||
":OverlayRemountedTest_SharedLibrary",
|
":OverlayRemountedTest_SharedLibrary",
|
||||||
":OverlayRemountedTest_SharedLibraryOverlay",
|
":OverlayRemountedTest_SharedLibraryOverlay",
|
||||||
":OverlayRemountedTest_Target",
|
":OverlayRemountedTest_Target",
|
||||||
|
":OverlayRemountedTest_TargetUpgrade",
|
||||||
|
":OverlayRemountedTest_Overlay",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.overlaytest.remounted;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.android.tradefed.device.DeviceNotAvailableException;
|
||||||
|
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.rules.RuleChain;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
|
||||||
|
public class OverlayRemountedTestBase extends BaseHostJUnit4Test {
|
||||||
|
static final long ASSERT_RESOURCE_TIMEOUT_MS = 30000;
|
||||||
|
|
||||||
|
static final String TARGET_APK = "OverlayRemountedTest_Target.apk";
|
||||||
|
static final String TARGET_PACKAGE = "com.android.overlaytest.remounted.target";
|
||||||
|
static final String TARGET_UPGRADE_APK = "OverlayRemountedTest_TargetUpgrade.apk";
|
||||||
|
static final String OVERLAY_APK = "OverlayRemountedTest_Overlay.apk";
|
||||||
|
static final String OVERLAY_PACKAGE = "com.android.overlaytest.remounted.target.overlay";
|
||||||
|
static final String SHARED_LIBRARY_APK =
|
||||||
|
"OverlayRemountedTest_SharedLibrary.apk";
|
||||||
|
static final String SHARED_LIBRARY_PACKAGE =
|
||||||
|
"com.android.overlaytest.remounted.shared_library";
|
||||||
|
static final String SHARED_LIBRARY_OVERLAY_APK =
|
||||||
|
"OverlayRemountedTest_SharedLibraryOverlay.apk";
|
||||||
|
static final String SHARED_LIBRARY_OVERLAY_PACKAGE =
|
||||||
|
"com.android.overlaytest.remounted.shared_library.overlay";
|
||||||
|
|
||||||
|
private final TemporaryFolder mTemporaryFolder = new TemporaryFolder();
|
||||||
|
protected final SystemPreparer mPreparer = new SystemPreparer(mTemporaryFolder,
|
||||||
|
this::getDevice);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final RuleChain ruleChain = RuleChain.outerRule(mTemporaryFolder).around(mPreparer);
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void startBefore() throws DeviceNotAvailableException {
|
||||||
|
getDevice().waitForDeviceAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds the full name of a resource in the form package:type/entry. */
|
||||||
|
String resourceName(String pkg, String type, String entry) {
|
||||||
|
return String.format("%s:%s/%s", pkg, type, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void assertResource(String resourceName, String expectedValue)
|
||||||
|
throws DeviceNotAvailableException {
|
||||||
|
String result = null;
|
||||||
|
|
||||||
|
final long endMillis = System.currentTimeMillis() + ASSERT_RESOURCE_TIMEOUT_MS;
|
||||||
|
while (System.currentTimeMillis() <= endMillis) {
|
||||||
|
result = getDevice().executeShellCommand(
|
||||||
|
String.format("cmd overlay lookup %s %s", TARGET_PACKAGE, resourceName));
|
||||||
|
if (result.equals(expectedValue + "\n") ||
|
||||||
|
result.endsWith("-> " + expectedValue + "\n")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(200);
|
||||||
|
} catch (InterruptedException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fail(String.format("expected: <[%s]> in: <[%s]>", expectedValue, result));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,42 +16,13 @@
|
|||||||
|
|
||||||
package com.android.overlaytest.remounted;
|
package com.android.overlaytest.remounted;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import com.android.tradefed.device.DeviceNotAvailableException;
|
|
||||||
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
|
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
|
||||||
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.RuleChain;
|
|
||||||
import org.junit.rules.TemporaryFolder;
|
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
@RunWith(DeviceJUnit4ClassRunner.class)
|
@RunWith(DeviceJUnit4ClassRunner.class)
|
||||||
public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
|
public class OverlaySharedLibraryTest extends OverlayRemountedTestBase {
|
||||||
private static final String TARGET_APK = "OverlayRemountedTest_Target.apk";
|
|
||||||
private static final String TARGET_PACKAGE = "com.android.overlaytest.remounted.target";
|
|
||||||
private static final String SHARED_LIBRARY_APK =
|
|
||||||
"OverlayRemountedTest_SharedLibrary.apk";
|
|
||||||
private static final String SHARED_LIBRARY_PACKAGE =
|
|
||||||
"com.android.overlaytest.remounted.shared_library";
|
|
||||||
private static final String SHARED_LIBRARY_OVERLAY_APK =
|
|
||||||
"OverlayRemountedTest_SharedLibraryOverlay.apk";
|
|
||||||
private static final String SHARED_LIBRARY_OVERLAY_PACKAGE =
|
|
||||||
"com.android.overlaytest.remounted.shared_library.overlay";
|
|
||||||
|
|
||||||
public final TemporaryFolder temporaryFolder = new TemporaryFolder();
|
|
||||||
public final SystemPreparer preparer = new SystemPreparer(temporaryFolder, this::getDevice);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final RuleChain ruleChain = RuleChain.outerRule(temporaryFolder).around(preparer);
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void startBefore() throws DeviceNotAvailableException {
|
|
||||||
getDevice().waitForDeviceAvailable();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSharedLibrary() throws Exception {
|
public void testSharedLibrary() throws Exception {
|
||||||
@@ -60,7 +31,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
|
|||||||
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
|
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
|
||||||
"shared_library_overlaid");
|
"shared_library_overlaid");
|
||||||
|
|
||||||
preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
|
mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
|
||||||
.installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE)
|
.installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE)
|
||||||
.reboot()
|
.reboot()
|
||||||
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, false)
|
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, false)
|
||||||
@@ -71,7 +42,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
|
|||||||
assertResource(libraryResource, "false");
|
assertResource(libraryResource, "false");
|
||||||
|
|
||||||
// Overlay the shared library resource.
|
// Overlay the shared library resource.
|
||||||
preparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true);
|
mPreparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true);
|
||||||
assertResource(targetResource, "true");
|
assertResource(targetResource, "true");
|
||||||
assertResource(libraryResource, "true");
|
assertResource(libraryResource, "true");
|
||||||
}
|
}
|
||||||
@@ -83,7 +54,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
|
|||||||
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
|
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
|
||||||
"shared_library_overlaid");
|
"shared_library_overlaid");
|
||||||
|
|
||||||
preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
|
mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
|
||||||
.installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE)
|
.installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE)
|
||||||
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true)
|
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true)
|
||||||
.reboot()
|
.reboot()
|
||||||
@@ -92,18 +63,4 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
|
|||||||
assertResource(targetResource, "true");
|
assertResource(targetResource, "true");
|
||||||
assertResource(libraryResource, "true");
|
assertResource(libraryResource, "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Builds the full name of a resource in the form package:type/entry. */
|
|
||||||
String resourceName(String pkg, String type, String entry) {
|
|
||||||
return String.format("%s:%s/%s", pkg, type, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void assertResource(String resourceName, String expectedValue)
|
|
||||||
throws DeviceNotAvailableException {
|
|
||||||
final String result = getDevice().executeShellCommand(
|
|
||||||
String.format("cmd overlay lookup %s %s", TARGET_PACKAGE, resourceName));
|
|
||||||
assertTrue(String.format("expected: <[%s]> in: <[%s]>", expectedValue, result),
|
|
||||||
result.equals(expectedValue + "\n") ||
|
|
||||||
result.endsWith("-> " + expectedValue + "\n"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.overlaytest.remounted;
|
||||||
|
|
||||||
|
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(DeviceJUnit4ClassRunner.class)
|
||||||
|
public class PackagedUpgradedTest extends OverlayRemountedTestBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTargetUpgrade() throws Exception {
|
||||||
|
final String targetOverlaid = resourceName(TARGET_PACKAGE, "bool", "target_overlaid");
|
||||||
|
final String targetReference = resourceName(TARGET_PACKAGE, "bool", "target_reference");
|
||||||
|
|
||||||
|
mPreparer.pushResourceFile(TARGET_APK, "/product/app/OverlayTarget.apk")
|
||||||
|
.reboot()
|
||||||
|
.installResourceApk(OVERLAY_APK, OVERLAY_PACKAGE)
|
||||||
|
.setOverlayEnabled(OVERLAY_PACKAGE, true);
|
||||||
|
|
||||||
|
assertResource(targetReference, "@" + 0x7f010000 + " -> true");
|
||||||
|
assertResource(targetOverlaid, "true");
|
||||||
|
|
||||||
|
mPreparer.installResourceApk(TARGET_UPGRADE_APK, TARGET_PACKAGE);
|
||||||
|
|
||||||
|
assertResource(targetReference, "@" + 0x7f0100ff + " -> true");
|
||||||
|
assertResource(targetOverlaid, "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTargetRelocated() throws Exception {
|
||||||
|
final String targetOverlaid = resourceName(TARGET_PACKAGE, "bool", "target_overlaid");
|
||||||
|
final String originalPath = "/product/app/OverlayTarget.apk";
|
||||||
|
|
||||||
|
mPreparer.pushResourceFile(TARGET_APK, originalPath)
|
||||||
|
.reboot()
|
||||||
|
.installResourceApk(OVERLAY_APK, OVERLAY_PACKAGE)
|
||||||
|
.setOverlayEnabled(OVERLAY_PACKAGE, true);
|
||||||
|
|
||||||
|
assertResource(targetOverlaid, "true");
|
||||||
|
|
||||||
|
mPreparer.remount();
|
||||||
|
getDevice().deleteFile(originalPath);
|
||||||
|
mPreparer.pushResourceFile(TARGET_UPGRADE_APK, "/product/app/OverlayTarget2.apk")
|
||||||
|
.reboot();
|
||||||
|
|
||||||
|
assertResource(targetOverlaid, "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,8 +18,6 @@ package com.android.overlaytest.remounted;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|
||||||
|
|
||||||
import com.android.tradefed.device.DeviceNotAvailableException;
|
import com.android.tradefed.device.DeviceNotAvailableException;
|
||||||
import com.android.tradefed.device.ITestDevice;
|
import com.android.tradefed.device.ITestDevice;
|
||||||
|
|
||||||
@@ -32,10 +30,6 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.FutureTask;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
class SystemPreparer extends ExternalResource {
|
class SystemPreparer extends ExternalResource {
|
||||||
private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
|
private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
|
||||||
@@ -58,7 +52,7 @@ class SystemPreparer extends ExternalResource {
|
|||||||
SystemPreparer pushResourceFile(String resourcePath,
|
SystemPreparer pushResourceFile(String resourcePath,
|
||||||
String outputPath) throws DeviceNotAvailableException, IOException {
|
String outputPath) throws DeviceNotAvailableException, IOException {
|
||||||
final ITestDevice device = mDeviceProvider.getDevice();
|
final ITestDevice device = mDeviceProvider.getDevice();
|
||||||
device.executeAdbCommand("remount");
|
remount();
|
||||||
assertTrue(device.pushFile(copyResourceToTemp(resourcePath), outputPath));
|
assertTrue(device.pushFile(copyResourceToTemp(resourcePath), outputPath));
|
||||||
mPushedFiles.add(outputPath);
|
mPushedFiles.add(outputPath);
|
||||||
return this;
|
return this;
|
||||||
@@ -69,7 +63,7 @@ class SystemPreparer extends ExternalResource {
|
|||||||
throws DeviceNotAvailableException, IOException {
|
throws DeviceNotAvailableException, IOException {
|
||||||
final ITestDevice device = mDeviceProvider.getDevice();
|
final ITestDevice device = mDeviceProvider.getDevice();
|
||||||
final File tmpFile = copyResourceToTemp(resourcePath);
|
final File tmpFile = copyResourceToTemp(resourcePath);
|
||||||
final String result = device.installPackage(tmpFile, true);
|
final String result = device.installPackage(tmpFile, true /* reinstall */);
|
||||||
Assert.assertNull(result);
|
Assert.assertNull(result);
|
||||||
mInstalledPackages.add(packageName);
|
mInstalledPackages.add(packageName);
|
||||||
return this;
|
return this;
|
||||||
@@ -77,34 +71,29 @@ class SystemPreparer extends ExternalResource {
|
|||||||
|
|
||||||
/** Sets the enable state of an overlay pacakage. */
|
/** Sets the enable state of an overlay pacakage. */
|
||||||
SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
|
SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
|
||||||
throws ExecutionException, DeviceNotAvailableException {
|
throws DeviceNotAvailableException {
|
||||||
final ITestDevice device = mDeviceProvider.getDevice();
|
final ITestDevice device = mDeviceProvider.getDevice();
|
||||||
|
final String enable = enabled ? "enable" : "disable";
|
||||||
|
|
||||||
// Wait for the overlay to change its enabled state.
|
// Wait for the overlay to change its enabled state.
|
||||||
final FutureTask<Boolean> enabledListener = new FutureTask<>(() -> {
|
final long endMillis = System.currentTimeMillis() + OVERLAY_ENABLE_TIMEOUT_MS;
|
||||||
while (true) {
|
String result;
|
||||||
device.executeShellCommand(String.format("cmd overlay %s %s",
|
while (System.currentTimeMillis() <= endMillis) {
|
||||||
enabled ? "enable" : "disable", packageName));
|
device.executeShellCommand(String.format("cmd overlay %s %s", enable, packageName));
|
||||||
|
result = device.executeShellCommand("cmd overlay dump isenabled "
|
||||||
final String result = device.executeShellCommand("cmd overlay dump " + packageName);
|
+ packageName);
|
||||||
final int startIndex = result.indexOf("mIsEnabled");
|
if (((enabled) ? "true\n" : "false\n").equals(result)) {
|
||||||
final int endIndex = result.indexOf('\n', startIndex);
|
return this;
|
||||||
if (result.substring(startIndex, endIndex).contains((enabled) ? "true" : "false")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
final Executor executor = (cmd) -> new Thread(cmd).start();
|
try {
|
||||||
executor.execute(enabledListener);
|
Thread.sleep(200);
|
||||||
try {
|
} catch (InterruptedException ignore) {
|
||||||
enabledListener.get(OVERLAY_ENABLE_TIMEOUT_MS, MILLISECONDS);
|
}
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
throw new IllegalStateException(device.executeShellCommand("cmd overlay list"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
throw new IllegalStateException(String.format("Failed to %s overlay %s:\n%s", enable,
|
||||||
|
packageName, device.executeShellCommand("cmd overlay list")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Restarts the device and waits until after boot is completed. */
|
/** Restarts the device and waits until after boot is completed. */
|
||||||
@@ -114,6 +103,11 @@ class SystemPreparer extends ExternalResource {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SystemPreparer remount() throws DeviceNotAvailableException {
|
||||||
|
mDeviceProvider.getDevice().executeAdbCommand("remount");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Copies a file within the host test jar to a temporary file on the host machine. */
|
/** Copies a file within the host test jar to a temporary file on the host machine. */
|
||||||
private File copyResourceToTemp(String resourcePath) throws IOException {
|
private File copyResourceToTemp(String resourcePath) throws IOException {
|
||||||
final File tempFile = mHostTempFolder.newFile(resourcePath);
|
final File tempFile = mHostTempFolder.newFile(resourcePath);
|
||||||
@@ -138,7 +132,7 @@ class SystemPreparer extends ExternalResource {
|
|||||||
protected void after() {
|
protected void after() {
|
||||||
final ITestDevice device = mDeviceProvider.getDevice();
|
final ITestDevice device = mDeviceProvider.getDevice();
|
||||||
try {
|
try {
|
||||||
device.executeAdbCommand("remount");
|
remount();
|
||||||
for (final String file : mPushedFiles) {
|
for (final String file : mPushedFiles) {
|
||||||
device.deleteFile(file);
|
device.deleteFile(file);
|
||||||
}
|
}
|
||||||
18
core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
Normal file
18
core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
android_test_helper_app {
|
||||||
|
name: "OverlayRemountedTest_Overlay",
|
||||||
|
sdk_version: "current",
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2020 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.overlaytest.remounted.target.overlay">
|
||||||
|
<application android:hasCode="false" />
|
||||||
|
<overlay android:targetPackage="com.android.overlaytest.remounted.target"
|
||||||
|
android:targetName="TestResources" />
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2020 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>
|
||||||
|
<bool name="target_overlaid">true</bool>
|
||||||
|
</resources>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2018 The Android Open Source Project
|
// Copyright (C) 2019 The Android Open Source Project
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -14,7 +14,12 @@
|
|||||||
|
|
||||||
android_test_helper_app {
|
android_test_helper_app {
|
||||||
name: "OverlayRemountedTest_Target",
|
name: "OverlayRemountedTest_Target",
|
||||||
srcs: ["src/**/*.java"],
|
|
||||||
sdk_version: "test_current",
|
sdk_version: "test_current",
|
||||||
libs: ["OverlayRemountedTest_SharedLibrary"],
|
libs: ["OverlayRemountedTest_SharedLibrary"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android_test_helper_app {
|
||||||
|
name: "OverlayRemountedTest_TargetUpgrade",
|
||||||
|
resource_dirs: ["res_upgrade"],
|
||||||
|
sdk_version: "test_current",
|
||||||
|
}
|
||||||
@@ -19,8 +19,7 @@
|
|||||||
package="com.android.overlaytest.remounted.target">
|
package="com.android.overlaytest.remounted.target">
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
<uses-library android:name="android.test.runner" />
|
|
||||||
<uses-library android:name="com.android.overlaytest.remounted.shared_library"
|
<uses-library android:name="com.android.overlaytest.remounted.shared_library"
|
||||||
android:required="true" />
|
android:required="false" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2020 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>
|
||||||
|
<overlayable name="TestResources">
|
||||||
|
<policy type="public">
|
||||||
|
<item type="bool" name="target_overlaid" />
|
||||||
|
</policy>
|
||||||
|
</overlayable>
|
||||||
|
</resources>
|
||||||
@@ -17,4 +17,10 @@
|
|||||||
|
|
||||||
<resources xmlns:sharedlib="http://schemas.android.com/apk/res/com.android.overlaytest.remounted.shared_library">
|
<resources xmlns:sharedlib="http://schemas.android.com/apk/res/com.android.overlaytest.remounted.shared_library">
|
||||||
<bool name="uses_shared_library_overlaid">@sharedlib:bool/shared_library_overlaid</bool>
|
<bool name="uses_shared_library_overlaid">@sharedlib:bool/shared_library_overlaid</bool>
|
||||||
|
|
||||||
|
<!-- This resource has a different id in the updated version of this target app to test that the
|
||||||
|
idmap is regenerated when the target is updated. -->
|
||||||
|
<bool name="target_overlaid">false</bool>
|
||||||
|
<public type="bool" name="target_overlaid" id="0x7f010000" />
|
||||||
|
<bool name="target_reference">@bool/target_overlaid</bool>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2020 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>
|
||||||
|
<overlayable name="TestResources">
|
||||||
|
<policy type="public">
|
||||||
|
<item type="bool" name="target_overlaid" />
|
||||||
|
</policy>
|
||||||
|
</overlayable>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (C) 2020 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>
|
||||||
|
<!-- This resource has a different id in the updated target app than the base target app to test
|
||||||
|
that the idmap is regenerated when the target is updated. -->
|
||||||
|
<bool name="target_overlaid">false</bool>
|
||||||
|
<public type="bool" name="target_overlaid" id="0x7f0100ff" />
|
||||||
|
<bool name="target_reference">@bool/target_overlaid</bool>
|
||||||
|
</resources>
|
||||||
@@ -385,7 +385,7 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap
|
|||||||
const StringPiece idmap_data(
|
const StringPiece idmap_data(
|
||||||
reinterpret_cast<const char*>(idmap_asset->getBuffer(true /*wordAligned*/)),
|
reinterpret_cast<const char*>(idmap_asset->getBuffer(true /*wordAligned*/)),
|
||||||
static_cast<size_t>(idmap_asset->getLength()));
|
static_cast<size_t>(idmap_asset->getLength()));
|
||||||
std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_data);
|
std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_path, idmap_data);
|
||||||
if (loaded_idmap == nullptr) {
|
if (loaded_idmap == nullptr) {
|
||||||
LOG(ERROR) << "failed to load IDMAP " << idmap_path;
|
LOG(ERROR) << "failed to load IDMAP " << idmap_path;
|
||||||
return {};
|
return {};
|
||||||
@@ -538,8 +538,9 @@ bool ApkAssets::IsUpToDate() const {
|
|||||||
// Loaders are invalidated by the app, not the system, so assume they are up to date.
|
// Loaders are invalidated by the app, not the system, so assume they are up to date.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return (!loaded_idmap_ || loaded_idmap_->IsUpToDate()) &&
|
||||||
|
last_mod_time_ == getFileModDate(path_.c_str());
|
||||||
|
|
||||||
return last_mod_time_ == getFileModDate(path_.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "android-base/logging.h"
|
#include "android-base/logging.h"
|
||||||
#include "android-base/stringprintf.h"
|
#include "android-base/stringprintf.h"
|
||||||
|
#include "androidfw/misc.h"
|
||||||
#include "androidfw/ResourceTypes.h"
|
#include "androidfw/ResourceTypes.h"
|
||||||
#include "androidfw/Util.h"
|
#include "androidfw/Util.h"
|
||||||
#include "utils/ByteOrder.h"
|
#include "utils/ByteOrder.h"
|
||||||
@@ -192,7 +193,9 @@ static bool IsValidIdmapHeader(const StringPiece& data) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadedIdmap::LoadedIdmap(const Idmap_header* header,
|
LoadedIdmap::LoadedIdmap(std::string&& idmap_path,
|
||||||
|
const time_t last_mod_time,
|
||||||
|
const Idmap_header* header,
|
||||||
const Idmap_data_header* data_header,
|
const Idmap_data_header* data_header,
|
||||||
const Idmap_target_entry* target_entries,
|
const Idmap_target_entry* target_entries,
|
||||||
const Idmap_overlay_entry* overlay_entries,
|
const Idmap_overlay_entry* overlay_entries,
|
||||||
@@ -201,7 +204,9 @@ LoadedIdmap::LoadedIdmap(const Idmap_header* header,
|
|||||||
data_header_(data_header),
|
data_header_(data_header),
|
||||||
target_entries_(target_entries),
|
target_entries_(target_entries),
|
||||||
overlay_entries_(overlay_entries),
|
overlay_entries_(overlay_entries),
|
||||||
string_pool_(string_pool) {
|
string_pool_(string_pool),
|
||||||
|
idmap_path_(std::move(idmap_path)),
|
||||||
|
idmap_last_mod_time_(last_mod_time) {
|
||||||
|
|
||||||
size_t length = strnlen(reinterpret_cast<const char*>(header_->overlay_path),
|
size_t length = strnlen(reinterpret_cast<const char*>(header_->overlay_path),
|
||||||
arraysize(header_->overlay_path));
|
arraysize(header_->overlay_path));
|
||||||
@@ -212,7 +217,8 @@ LoadedIdmap::LoadedIdmap(const Idmap_header* header,
|
|||||||
target_apk_path_.assign(reinterpret_cast<const char*>(header_->target_path), length);
|
target_apk_path_.assign(reinterpret_cast<const char*>(header_->target_path), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_data) {
|
std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_path,
|
||||||
|
const StringPiece& idmap_data) {
|
||||||
ATRACE_CALL();
|
ATRACE_CALL();
|
||||||
if (!IsValidIdmapHeader(idmap_data)) {
|
if (!IsValidIdmapHeader(idmap_data)) {
|
||||||
return {};
|
return {};
|
||||||
@@ -275,10 +281,14 @@ std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_da
|
|||||||
|
|
||||||
// Can't use make_unique because LoadedIdmap constructor is private.
|
// Can't use make_unique because LoadedIdmap constructor is private.
|
||||||
std::unique_ptr<LoadedIdmap> loaded_idmap = std::unique_ptr<LoadedIdmap>(
|
std::unique_ptr<LoadedIdmap> loaded_idmap = std::unique_ptr<LoadedIdmap>(
|
||||||
new LoadedIdmap(header, data_header, target_entries, overlay_entries,
|
new LoadedIdmap(idmap_path.to_string(), getFileModDate(idmap_path.data()), header,
|
||||||
idmap_string_pool.release()));
|
data_header, target_entries, overlay_entries, idmap_string_pool.release()));
|
||||||
|
|
||||||
return std::move(loaded_idmap);
|
return std::move(loaded_idmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LoadedIdmap::IsUpToDate() const {
|
||||||
|
return idmap_last_mod_time_ == getFileModDate(idmap_path_.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|||||||
@@ -142,7 +142,13 @@ class IdmapResMap {
|
|||||||
class LoadedIdmap {
|
class LoadedIdmap {
|
||||||
public:
|
public:
|
||||||
// Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed.
|
// Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed.
|
||||||
static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_data);
|
static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_path,
|
||||||
|
const StringPiece& idmap_data);
|
||||||
|
|
||||||
|
// Returns the path to the IDMAP.
|
||||||
|
inline const std::string& IdmapPath() const {
|
||||||
|
return idmap_path_;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
|
// Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated.
|
||||||
inline const std::string& OverlayApkPath() const {
|
inline const std::string& OverlayApkPath() const {
|
||||||
@@ -167,6 +173,10 @@ class LoadedIdmap {
|
|||||||
return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id);
|
return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns whether the idmap file on disk has not been modified since the construction of this
|
||||||
|
// LoadedIdmap.
|
||||||
|
bool IsUpToDate() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Exposed as protected so that tests can subclass and mock this class out.
|
// Exposed as protected so that tests can subclass and mock this class out.
|
||||||
LoadedIdmap() = default;
|
LoadedIdmap() = default;
|
||||||
@@ -177,13 +187,17 @@ class LoadedIdmap {
|
|||||||
const Idmap_overlay_entry* overlay_entries_;
|
const Idmap_overlay_entry* overlay_entries_;
|
||||||
const std::unique_ptr<ResStringPool> string_pool_;
|
const std::unique_ptr<ResStringPool> string_pool_;
|
||||||
|
|
||||||
|
const std::string idmap_path_;
|
||||||
std::string overlay_apk_path_;
|
std::string overlay_apk_path_;
|
||||||
std::string target_apk_path_;
|
std::string target_apk_path_;
|
||||||
|
const time_t idmap_last_mod_time_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
|
DISALLOW_COPY_AND_ASSIGN(LoadedIdmap);
|
||||||
|
|
||||||
explicit LoadedIdmap(const Idmap_header* header,
|
explicit LoadedIdmap(std::string&& idmap_path,
|
||||||
|
time_t last_mod_time,
|
||||||
|
const Idmap_header* header,
|
||||||
const Idmap_data_header* data_header,
|
const Idmap_data_header* data_header,
|
||||||
const Idmap_target_entry* target_entries,
|
const Idmap_target_entry* target_entries,
|
||||||
const Idmap_overlay_entry* overlay_entries,
|
const Idmap_overlay_entry* overlay_entries,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class IdmapTest : public ::testing::Test {
|
|||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
// Move to the test data directory so the idmap can locate the overlay APK.
|
// Move to the test data directory so the idmap can locate the overlay APK.
|
||||||
std::string original_path = base::GetExecutableDirectory();
|
original_path = base::GetExecutableDirectory();
|
||||||
chdir(GetTestDataPath().c_str());
|
chdir(GetTestDataPath().c_str());
|
||||||
|
|
||||||
system_assets_ = ApkAssets::Load("system/system.apk");
|
system_assets_ = ApkAssets::Load("system/system.apk");
|
||||||
@@ -49,10 +49,14 @@ class IdmapTest : public ::testing::Test {
|
|||||||
|
|
||||||
overlayable_assets_ = ApkAssets::Load("overlayable/overlayable.apk");
|
overlayable_assets_ = ApkAssets::Load("overlayable/overlayable.apk");
|
||||||
ASSERT_NE(nullptr, overlayable_assets_);
|
ASSERT_NE(nullptr, overlayable_assets_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
chdir(original_path.c_str());
|
chdir(original_path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
std::string original_path;
|
||||||
std::unique_ptr<const ApkAssets> system_assets_;
|
std::unique_ptr<const ApkAssets> system_assets_;
|
||||||
std::unique_ptr<const ApkAssets> overlay_assets_;
|
std::unique_ptr<const ApkAssets> overlay_assets_;
|
||||||
std::unique_ptr<const ApkAssets> overlayable_assets_;
|
std::unique_ptr<const ApkAssets> overlayable_assets_;
|
||||||
@@ -221,8 +225,7 @@ TEST_F(IdmapTest, OverlaidResourceHasSameName) {
|
|||||||
|
|
||||||
TEST_F(IdmapTest, OverlayLoaderInterop) {
|
TEST_F(IdmapTest, OverlayLoaderInterop) {
|
||||||
std::string contents;
|
std::string contents;
|
||||||
auto loader_assets = ApkAssets::LoadTable(GetTestDataPath() + "/loader/resources.arsc",
|
auto loader_assets = ApkAssets::LoadTable("loader/resources.arsc", PROPERTY_LOADER);
|
||||||
PROPERTY_LOADER);
|
|
||||||
|
|
||||||
AssetManager2 asset_manager;
|
AssetManager2 asset_manager;
|
||||||
asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(),
|
asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(),
|
||||||
@@ -241,4 +244,25 @@ TEST_F(IdmapTest, OverlayLoaderInterop) {
|
|||||||
ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "loader");
|
ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "loader");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(IdmapTest, OverlayAssetsIsUpToDate) {
|
||||||
|
std::string idmap_contents;
|
||||||
|
ASSERT_TRUE(base::ReadFileToString("overlay/overlay.idmap", &idmap_contents));
|
||||||
|
|
||||||
|
TemporaryFile temp_file;
|
||||||
|
ASSERT_TRUE(base::WriteStringToFile(idmap_contents, temp_file.path));
|
||||||
|
|
||||||
|
auto apk_assets = ApkAssets::LoadOverlay(temp_file.path);
|
||||||
|
ASSERT_NE(nullptr, apk_assets);
|
||||||
|
ASSERT_TRUE(apk_assets->IsUpToDate());
|
||||||
|
|
||||||
|
unlink(temp_file.path);
|
||||||
|
ASSERT_FALSE(apk_assets->IsUpToDate());
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
base::WriteStringToFile("hello", temp_file.path);
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
ASSERT_FALSE(apk_assets->IsUpToDate());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -63,20 +63,23 @@ class IdmapManager {
|
|||||||
mIdmapDaemon = IdmapDaemon.getInstance();
|
mIdmapDaemon = IdmapDaemon.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the idmap for the target/overlay combination and returns whether the idmap file was
|
||||||
|
* modified.
|
||||||
|
*/
|
||||||
boolean createIdmap(@NonNull final PackageInfo targetPackage,
|
boolean createIdmap(@NonNull final PackageInfo targetPackage,
|
||||||
@NonNull final PackageInfo overlayPackage, int userId) {
|
@NonNull final PackageInfo overlayPackage, int userId) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and "
|
Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and "
|
||||||
+ overlayPackage.packageName);
|
+ overlayPackage.packageName);
|
||||||
}
|
}
|
||||||
final int sharedGid = UserHandle.getSharedAppGid(targetPackage.applicationInfo.uid);
|
|
||||||
final String targetPath = targetPackage.applicationInfo.getBaseCodePath();
|
final String targetPath = targetPackage.applicationInfo.getBaseCodePath();
|
||||||
final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
|
final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
|
||||||
try {
|
try {
|
||||||
int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
|
int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
|
||||||
boolean enforce = enforceOverlayable(overlayPackage);
|
boolean enforce = enforceOverlayable(overlayPackage);
|
||||||
if (mIdmapDaemon.verifyIdmap(targetPath, overlayPath, policies, enforce, userId)) {
|
if (mIdmapDaemon.verifyIdmap(targetPath, overlayPath, policies, enforce, userId)) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
|
return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
|
||||||
enforce, userId) != null;
|
enforce, userId) != null;
|
||||||
|
|||||||
@@ -700,14 +700,15 @@ final class OverlayManagerServiceImpl {
|
|||||||
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName,
|
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName,
|
||||||
userId);
|
userId);
|
||||||
|
|
||||||
// Immutable RROs targeting to "android", ie framework-res.apk, are handled by native layers.
|
// Immutable RROs targeting to "android", ie framework-res.apk, are handled by native
|
||||||
|
// layers.
|
||||||
|
boolean modified = false;
|
||||||
if (targetPackage != null && overlayPackage != null
|
if (targetPackage != null && overlayPackage != null
|
||||||
&& !("android".equals(targetPackageName)
|
&& !("android".equals(targetPackageName)
|
||||||
&& !isPackageConfiguredMutable(overlayPackageName))) {
|
&& !isPackageConfiguredMutable(overlayPackageName))) {
|
||||||
mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
|
modified |= mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean modified = false;
|
|
||||||
if (overlayPackage != null) {
|
if (overlayPackage != null) {
|
||||||
modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
|
modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
|
||||||
overlayPackage.applicationInfo.getBaseCodePath());
|
overlayPackage.applicationInfo.getBaseCodePath());
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
{
|
{
|
||||||
"name": "OverlayHostTests"
|
"name": "OverlayHostTests"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "OverlayRemountedTest"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "CtsAppSecurityHostTestCases",
|
"name": "CtsAppSecurityHostTestCases",
|
||||||
"options": [
|
"options": [
|
||||||
|
|||||||
@@ -377,8 +377,7 @@ class OverlayManagerServiceImplTestsBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final String key = createKey(overlayPackage.packageName, userId);
|
final String key = createKey(overlayPackage.packageName, userId);
|
||||||
mIdmapFiles.add(key);
|
return mIdmapFiles.add(key);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user