Merge changes from topic "invalidate_idmap" into rvc-dev am: 6cb79cdfb7

Change-Id: I8e4b6280fcfc2623f982f9ea3bb3f0349d05482c
This commit is contained in:
Ryan Mitchell
2020-04-10 15:51:26 +00:00
committed by Automerger Merge Worker
38 changed files with 429 additions and 119 deletions

View File

@@ -3,5 +3,10 @@
{
"name" : "idmap2_tests"
}
],
"imports": [
{
"path": "frameworks/base/services/core/java/com/android/server/om"
}
]
}

View File

@@ -149,15 +149,21 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path,
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);
std::ofstream fout(idmap_path);
if (fout.fail()) {
return error("failed to open idmap path " + idmap_path);
}
BinaryStreamVisitor visitor(fout);
(*idmap)->accept(&visitor);
fout.close();
if (fout.fail()) {
unlink(idmap_path.c_str());
return error("failed to write to idmap path " + idmap_path);
}

View File

@@ -344,7 +344,7 @@ public class ResourcesManager {
ApkAssets apkAssets = null;
if (mLoadedApkAssets != null) {
apkAssets = mLoadedApkAssets.get(newKey);
if (apkAssets != null) {
if (apkAssets != null && apkAssets.isUpToDate()) {
return apkAssets;
}
}
@@ -353,7 +353,7 @@ public class ResourcesManager {
final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey);
if (apkAssetsRef != null) {
apkAssets = apkAssetsRef.get();
if (apkAssets != null) {
if (apkAssets != null && apkAssets.isUpToDate()) {
if (mLoadedApkAssets != null) {
mLoadedApkAssets.put(newKey, apkAssets);
}

View File

@@ -16,7 +16,7 @@ java_test_host {
name: "OverlayHostTests",
srcs: ["src/**/*.java"],
libs: ["tradefed"],
test_suites: ["general-tests"],
test_suites: ["device-tests"],
target_required: [
"OverlayHostTests_NonPlatformSignatureOverlay",
"OverlayHostTests_PlatformSignatureStaticOverlay",

View File

@@ -78,14 +78,9 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
}
@Test
public void failToInstallPlatformSignedStaticOverlay() throws Exception {
try {
installPackage("OverlayHostTests_PlatformSignatureStaticOverlay.apk");
fail("installed a static overlay");
} catch (Exception e) {
// Expected.
}
assertFalse(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME));
public void installedIsStaticOverlayIsMutable() throws Exception {
installPackage("OverlayHostTests_PlatformSignatureStaticOverlay.apk");
assertTrue(isOverlayMutable(SIG_OVERLAY_PACKAGE_NAME));
}
@Test
@@ -229,6 +224,10 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
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 {
return getDevice().executeShellCommand(cmd);
}

View File

@@ -20,7 +20,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_NonPlatformSignatureOverlay
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad
include $(BUILD_PACKAGE)
@@ -28,7 +28,8 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureStaticOverlay
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
LOCAL_MANIFEST_FILE := static/AndroidManifest.xml
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_static
include $(BUILD_PACKAGE)
@@ -37,7 +38,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureOverlay
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1

View File

@@ -19,7 +19,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
LOCAL_USE_AAPT2 := true
LOCAL_AAPT_FLAGS := --no-resource-removal
@@ -31,7 +31,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV1
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
@@ -43,7 +43,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV2
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
@@ -57,7 +57,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1
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 += --version-code 1 --version-name v1
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res
@@ -68,7 +68,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2
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 += --version-code 2 --version-name v2
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res

View File

@@ -24,5 +24,7 @@ java_test_host {
":OverlayRemountedTest_SharedLibrary",
":OverlayRemountedTest_SharedLibraryOverlay",
":OverlayRemountedTest_Target",
":OverlayRemountedTest_TargetUpgrade",
":OverlayRemountedTest_Overlay",
],
}

View File

@@ -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));
}
}

View File

@@ -16,42 +16,13 @@
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.junit4.BaseHostJUnit4Test;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
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();
}
public class OverlaySharedLibraryTest extends OverlayRemountedTestBase {
@Test
public void testSharedLibrary() throws Exception {
@@ -60,7 +31,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
"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)
.reboot()
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, false)
@@ -71,7 +42,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
assertResource(libraryResource, "false");
// Overlay the shared library resource.
preparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true);
mPreparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true);
assertResource(targetResource, "true");
assertResource(libraryResource, "true");
}
@@ -83,7 +54,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
"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)
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true)
.reboot()
@@ -92,18 +63,4 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
assertResource(targetResource, "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"));
}
}

View File

@@ -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");
}
}

View File

@@ -18,8 +18,6 @@ package com.android.overlaytest.remounted;
import static org.junit.Assert.assertTrue;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -32,10 +30,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
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 {
private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
@@ -58,7 +52,7 @@ class SystemPreparer extends ExternalResource {
SystemPreparer pushResourceFile(String resourcePath,
String outputPath) throws DeviceNotAvailableException, IOException {
final ITestDevice device = mDeviceProvider.getDevice();
device.executeAdbCommand("remount");
remount();
assertTrue(device.pushFile(copyResourceToTemp(resourcePath), outputPath));
mPushedFiles.add(outputPath);
return this;
@@ -69,7 +63,7 @@ class SystemPreparer extends ExternalResource {
throws DeviceNotAvailableException, IOException {
final ITestDevice device = mDeviceProvider.getDevice();
final File tmpFile = copyResourceToTemp(resourcePath);
final String result = device.installPackage(tmpFile, true);
final String result = device.installPackage(tmpFile, true /* reinstall */);
Assert.assertNull(result);
mInstalledPackages.add(packageName);
return this;
@@ -77,34 +71,29 @@ class SystemPreparer extends ExternalResource {
/** Sets the enable state of an overlay pacakage. */
SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
throws ExecutionException, DeviceNotAvailableException {
throws DeviceNotAvailableException {
final ITestDevice device = mDeviceProvider.getDevice();
final String enable = enabled ? "enable" : "disable";
// Wait for the overlay to change its enabled state.
final FutureTask<Boolean> enabledListener = new FutureTask<>(() -> {
while (true) {
device.executeShellCommand(String.format("cmd overlay %s %s",
enabled ? "enable" : "disable", packageName));
final String result = device.executeShellCommand("cmd overlay dump " + packageName);
final int startIndex = result.indexOf("mIsEnabled");
final int endIndex = result.indexOf('\n', startIndex);
if (result.substring(startIndex, endIndex).contains((enabled) ? "true" : "false")) {
return true;
}
final long endMillis = System.currentTimeMillis() + OVERLAY_ENABLE_TIMEOUT_MS;
String result;
while (System.currentTimeMillis() <= endMillis) {
device.executeShellCommand(String.format("cmd overlay %s %s", enable, packageName));
result = device.executeShellCommand("cmd overlay dump isenabled "
+ packageName);
if (((enabled) ? "true\n" : "false\n").equals(result)) {
return this;
}
});
final Executor executor = (cmd) -> new Thread(cmd).start();
executor.execute(enabledListener);
try {
enabledListener.get(OVERLAY_ENABLE_TIMEOUT_MS, MILLISECONDS);
} catch (InterruptedException ignored) {
} catch (TimeoutException e) {
throw new IllegalStateException(device.executeShellCommand("cmd overlay list"));
try {
Thread.sleep(200);
} catch (InterruptedException ignore) {
}
}
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. */
@@ -114,6 +103,11 @@ class SystemPreparer extends ExternalResource {
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. */
private File copyResourceToTemp(String resourcePath) throws IOException {
final File tempFile = mHostTempFolder.newFile(resourcePath);
@@ -138,7 +132,7 @@ class SystemPreparer extends ExternalResource {
protected void after() {
final ITestDevice device = mDeviceProvider.getDevice();
try {
device.executeAdbCommand("remount");
remount();
for (final String file : mPushedFiles) {
device.deleteFile(file);
}

View 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",
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,12 @@
android_test_helper_app {
name: "OverlayRemountedTest_Target",
srcs: ["src/**/*.java"],
sdk_version: "test_current",
libs: ["OverlayRemountedTest_SharedLibrary"],
}
android_test_helper_app {
name: "OverlayRemountedTest_TargetUpgrade",
resource_dirs: ["res_upgrade"],
sdk_version: "test_current",
}

View File

@@ -19,8 +19,7 @@
package="com.android.overlaytest.remounted.target">
<application>
<uses-library android:name="android.test.runner" />
<uses-library android:name="com.android.overlaytest.remounted.shared_library"
android:required="true" />
android:required="false" />
</application>
</manifest>

View File

@@ -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>

View File

@@ -17,4 +17,10 @@
<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>
<!-- 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -385,7 +385,7 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap
const StringPiece idmap_data(
reinterpret_cast<const char*>(idmap_asset->getBuffer(true /*wordAligned*/)),
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) {
LOG(ERROR) << "failed to load IDMAP " << idmap_path;
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.
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

View File

@@ -20,6 +20,7 @@
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "androidfw/misc.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/Util.h"
#include "utils/ByteOrder.h"
@@ -192,7 +193,9 @@ static bool IsValidIdmapHeader(const StringPiece& data) {
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_target_entry* target_entries,
const Idmap_overlay_entry* overlay_entries,
@@ -201,7 +204,9 @@ LoadedIdmap::LoadedIdmap(const Idmap_header* header,
data_header_(data_header),
target_entries_(target_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),
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);
}
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();
if (!IsValidIdmapHeader(idmap_data)) {
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.
std::unique_ptr<LoadedIdmap> loaded_idmap = std::unique_ptr<LoadedIdmap>(
new LoadedIdmap(header, data_header, target_entries, overlay_entries,
idmap_string_pool.release()));
new LoadedIdmap(idmap_path.to_string(), getFileModDate(idmap_path.data()), header,
data_header, target_entries, overlay_entries, idmap_string_pool.release()));
return std::move(loaded_idmap);
}
bool LoadedIdmap::IsUpToDate() const {
return idmap_last_mod_time_ == getFileModDate(idmap_path_.c_str());
}
} // namespace android

View File

@@ -142,7 +142,13 @@ class IdmapResMap {
class LoadedIdmap {
public:
// 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.
inline const std::string& OverlayApkPath() const {
@@ -167,6 +173,10 @@ class LoadedIdmap {
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:
// Exposed as protected so that tests can subclass and mock this class out.
LoadedIdmap() = default;
@@ -177,13 +187,17 @@ class LoadedIdmap {
const Idmap_overlay_entry* overlay_entries_;
const std::unique_ptr<ResStringPool> string_pool_;
const std::string idmap_path_;
std::string overlay_apk_path_;
std::string target_apk_path_;
const time_t idmap_last_mod_time_;
private:
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_target_entry* target_entries,
const Idmap_overlay_entry* overlay_entries,

View File

@@ -38,7 +38,7 @@ class IdmapTest : public ::testing::Test {
protected:
void SetUp() override {
// 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());
system_assets_ = ApkAssets::Load("system/system.apk");
@@ -49,10 +49,14 @@ class IdmapTest : public ::testing::Test {
overlayable_assets_ = ApkAssets::Load("overlayable/overlayable.apk");
ASSERT_NE(nullptr, overlayable_assets_);
}
void TearDown() override {
chdir(original_path.c_str());
}
protected:
std::string original_path;
std::unique_ptr<const ApkAssets> system_assets_;
std::unique_ptr<const ApkAssets> overlay_assets_;
std::unique_ptr<const ApkAssets> overlayable_assets_;
@@ -221,8 +225,7 @@ TEST_F(IdmapTest, OverlaidResourceHasSameName) {
TEST_F(IdmapTest, OverlayLoaderInterop) {
std::string contents;
auto loader_assets = ApkAssets::LoadTable(GetTestDataPath() + "/loader/resources.arsc",
PROPERTY_LOADER);
auto loader_assets = ApkAssets::LoadTable("loader/resources.arsc", PROPERTY_LOADER);
AssetManager2 asset_manager;
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");
}
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

View File

@@ -63,20 +63,23 @@ class IdmapManager {
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,
@NonNull final PackageInfo overlayPackage, int userId) {
if (DEBUG) {
Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and "
+ overlayPackage.packageName);
}
final int sharedGid = UserHandle.getSharedAppGid(targetPackage.applicationInfo.uid);
final String targetPath = targetPackage.applicationInfo.getBaseCodePath();
final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
try {
int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
boolean enforce = enforceOverlayable(overlayPackage);
if (mIdmapDaemon.verifyIdmap(targetPath, overlayPath, policies, enforce, userId)) {
return true;
return false;
}
return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
enforce, userId) != null;

View File

@@ -700,14 +700,15 @@ final class OverlayManagerServiceImpl {
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName,
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
&& !("android".equals(targetPackageName)
&& !isPackageConfiguredMutable(overlayPackageName))) {
mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
modified |= mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
}
boolean modified = false;
if (overlayPackage != null) {
modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
overlayPackage.applicationInfo.getBaseCodePath());

View File

@@ -14,6 +14,9 @@
{
"name": "OverlayHostTests"
},
{
"name": "OverlayRemountedTest"
},
{
"name": "CtsAppSecurityHostTestCases",
"options": [

View File

@@ -377,8 +377,7 @@ class OverlayManagerServiceImplTestsBase {
return false;
}
final String key = createKey(overlayPackage.packageName, userId);
mIdmapFiles.add(key);
return true;
return mIdmapFiles.add(key);
}
@Override