diff --git a/core/tests/overlaytests/device/assets/package-name.txt b/core/tests/overlaytests/device/assets/package-name.txt new file mode 100644 index 0000000000000..809443818f06e --- /dev/null +++ b/core/tests/overlaytests/device/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java index 91fcdbbb18ced..f86743a2fdbc8 100644 --- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java @@ -17,9 +17,12 @@ package com.android.overlaytest; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.UiAutomation; +import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -30,6 +33,8 @@ import android.util.Xml; import androidx.test.InstrumentationRegistry; +import com.android.internal.util.ArrayUtils; + import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -291,6 +296,33 @@ public abstract class OverlayBaseTest { assertEquals(getExpected(no, so, mo), actual); } + @Test + public void testAssetsNotPossibleToOverlay() throws Throwable { + final AssetManager am = mResources.getAssets(); + + // AssetManager#list will include assets from all loaded non-overlay + // APKs, including the framework; framework-res.apk contains at least + // assets/{images,webkit}. Rather than checking the list, verify that + // assets only present in overlays are never part of the list. + String[] files = am.list(""); + assertTrue(ArrayUtils.contains(files, "package-name.txt")); + assertFalse(ArrayUtils.contains(files, "foo.txt")); + assertFalse(ArrayUtils.contains(files, "bar.txt")); + + String contents = null; + try (InputStream is = am.open("package-name.txt")) { + final BufferedReader reader = new BufferedReader( + new InputStreamReader(is, StandardCharsets.UTF_8)); + StringBuilder str = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + str.append(line); + } + contents = str.toString(); + } + assertEquals("com.android.overlaytest", contents); + } + /* * testMatrix* tests * diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt new file mode 100644 index 0000000000000..257cc5642cb1a --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt @@ -0,0 +1 @@ +foo diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt new file mode 100644 index 0000000000000..087cb96b767f8 --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest.app_overlay_one diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt new file mode 100644 index 0000000000000..5716ca5987cbf --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt @@ -0,0 +1 @@ +bar diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt new file mode 100644 index 0000000000000..13185654df211 --- /dev/null +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt @@ -0,0 +1 @@ +com.android.overlaytest.app_overlay_two diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index d74f27cca200e..951970464bfe4 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -310,6 +310,9 @@ std::unique_ptr AssetManager2::OpenDir(const std::string& dirname) con // Start from the back. for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) { const ApkAssets* apk_assets = *iter; + if (apk_assets->IsOverlay()) { + continue; + } auto func = [&](const StringPiece& name, FileType type) { AssetDir::FileInfo info; @@ -336,6 +339,13 @@ std::unique_ptr AssetManager2::OpenNonAsset(const std::string& filename, Asset::AccessMode mode, ApkAssetsCookie* out_cookie) const { for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) { + // Prevent RRO from modifying assets and other entries accessed by file + // path. Explicitly asking for a path in a given package (denoted by a + // cookie) is still OK. + if (apk_assets_[i]->IsOverlay()) { + continue; + } + std::unique_ptr asset = apk_assets_[i]->Open(filename, mode); if (asset) { if (out_cookie != nullptr) { diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index db2d0382bcf66..35bbb5804df46 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -80,6 +80,10 @@ class ApkAssets { return loaded_arsc_.get(); } + inline bool IsOverlay() const { + return idmap_asset_.get() != nullptr; + } + private: DISALLOW_COPY_AND_ASSIGN(ApkAssets);