summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/idmap2/Android.bp58
-rw-r--r--cmds/idmap2/idmap2/CommandUtils.cpp17
-rw-r--r--cmds/idmap2/idmap2/Create.cpp25
-rw-r--r--cmds/idmap2/idmap2/CreateMultiple.cpp17
-rw-r--r--cmds/idmap2/idmap2/Lookup.cpp14
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.cpp132
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.h42
-rw-r--r--cmds/idmap2/include/idmap2/FabricatedOverlay.h103
-rw-r--r--cmds/idmap2/include/idmap2/Idmap.h35
-rw-r--r--cmds/idmap2/include/idmap2/PrettyPrintVisitor.h5
-rw-r--r--cmds/idmap2/include/idmap2/RawPrintVisitor.h5
-rw-r--r--cmds/idmap2/include/idmap2/ResourceContainer.h105
-rw-r--r--cmds/idmap2/include/idmap2/ResourceMapping.h114
-rw-r--r--cmds/idmap2/include/idmap2/ResourceUtils.h33
-rw-r--r--cmds/idmap2/include/idmap2/XmlParser.h17
-rw-r--r--cmds/idmap2/include/idmap2/ZipFile.h60
-rw-r--r--cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp4
-rw-r--r--cmds/idmap2/libidmap2/FabricatedOverlay.cpp297
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp103
-rw-r--r--cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp32
-rw-r--r--cmds/idmap2/libidmap2/RawPrintVisitor.cpp46
-rw-r--r--cmds/idmap2/libidmap2/ResourceContainer.cpp440
-rw-r--r--cmds/idmap2/libidmap2/ResourceMapping.cpp401
-rw-r--r--cmds/idmap2/libidmap2/ResourceUtils.cpp78
-rw-r--r--cmds/idmap2/libidmap2/XmlParser.cpp18
-rw-r--r--cmds/idmap2/libidmap2/ZipFile.cpp70
-rw-r--r--cmds/idmap2/libidmap2/proto/fabricated_v1.proto56
-rw-r--r--cmds/idmap2/tests/BinaryStreamVisitorTests.cpp2
-rw-r--r--cmds/idmap2/tests/FabricatedOverlayTests.cpp138
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp176
-rw-r--r--cmds/idmap2/tests/PrettyPrintVisitorTests.cpp26
-rw-r--r--cmds/idmap2/tests/RawPrintVisitorTests.cpp36
-rw-r--r--cmds/idmap2/tests/ResourceMappingTests.cpp95
-rw-r--r--cmds/idmap2/tests/ResourceUtilsTests.cpp33
-rw-r--r--cmds/idmap2/tests/TestHelpers.h55
-rw-r--r--cmds/idmap2/tests/XmlParserTests.cpp22
-rw-r--r--cmds/idmap2/tests/ZipFileTests.cpp66
-rw-r--r--core/jni/android_content_res_ApkAssets.cpp2
-rw-r--r--core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml1
-rwxr-xr-xlibs/androidfw/ApkAssets.cpp10
-rw-r--r--libs/androidfw/AssetManager2.cpp80
-rw-r--r--libs/androidfw/AssetsProvider.cpp12
-rw-r--r--libs/androidfw/Idmap.cpp27
-rw-r--r--libs/androidfw/ResourceTypes.cpp11
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h2
-rw-r--r--libs/androidfw/include/androidfw/AssetsProvider.h2
-rw-r--r--libs/androidfw/include/androidfw/Idmap.h7
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h15
-rw-r--r--libs/androidfw/tests/data/overlay/overlay.idmapbin640 -> 636 bytes
49 files changed, 1888 insertions, 1257 deletions
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 50f400122fe1..34d38d2b1b04 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -51,13 +51,18 @@ cc_library {
static: {
enabled: false,
},
+ static_libs: [
+ "libidmap2_protos",
+ ],
shared_libs: [
"libandroidfw",
"libbase",
"libcutils",
+ "libidmap2_policies",
+ "libprotobuf-cpp-lite",
"libutils",
+ "libz",
"libziparchive",
- "libidmap2_policies",
],
},
host: {
@@ -68,15 +73,30 @@ cc_library {
"libandroidfw",
"libbase",
"libcutils",
+ "libidmap2_policies",
+ "libidmap2_protos",
+ "libprotobuf-cpp-lite",
"libutils",
+ "libz",
"libziparchive",
- "libidmap2_policies",
],
},
},
}
cc_library {
+ name: "libidmap2_protos",
+ srcs: [
+ "libidmap2/proto/*.proto",
+ ],
+ host_supported: true,
+ proto: {
+ type: "lite",
+ export_proto_headers: true,
+ },
+}
+
+cc_library {
name: "libidmap2_policies",
defaults: [
"idmap2_defaults",
@@ -88,9 +108,6 @@ cc_library {
enabled: true,
},
android: {
- static: {
- enabled: false,
- },
shared_libs: [
"libandroidfw",
],
@@ -119,6 +136,7 @@ cc_test {
srcs: [
"tests/BinaryStreamVisitorTests.cpp",
"tests/CommandLineOptionsTests.cpp",
+ "tests/FabricatedOverlayTests.cpp",
"tests/FileUtilsTests.cpp",
"tests/Idmap2BinaryTests.cpp",
"tests/IdmapTests.cpp",
@@ -130,20 +148,27 @@ cc_test {
"tests/ResourceUtilsTests.cpp",
"tests/ResultTests.cpp",
"tests/XmlParserTests.cpp",
- "tests/ZipFileTests.cpp",
],
- static_libs: ["libgmock"],
+ required: [
+ "idmap2",
+ ],
+ static_libs: [
+ "libgmock",
+ "libidmap2_protos",
+ ],
target: {
android: {
shared_libs: [
"libandroidfw",
"libbase",
"libidmap2",
+ "libidmap2_policies",
"liblog",
+ "libprotobuf-cpp-lite",
"libutils",
"libz",
+ "libz",
"libziparchive",
- "libidmap2_policies",
],
},
host: {
@@ -152,10 +177,11 @@ cc_test {
"libbase",
"libcutils",
"libidmap2",
+ "libidmap2_policies",
"liblog",
+ "libprotobuf-cpp-lite",
"libutils",
"libziparchive",
- "libidmap2_policies",
],
shared_libs: [
"libz",
@@ -189,6 +215,9 @@ cc_binary {
"idmap2/Lookup.cpp",
"idmap2/Main.cpp",
],
+ static_libs: [
+ "libidmap2_protos",
+ ],
target: {
android: {
shared_libs: [
@@ -196,9 +225,11 @@ cc_binary {
"libbase",
"libcutils",
"libidmap2",
+ "libidmap2_policies",
+ "libprotobuf-cpp-lite",
"libutils",
+ "libz",
"libziparchive",
- "libidmap2_policies",
],
},
host: {
@@ -207,10 +238,11 @@ cc_binary {
"libbase",
"libcutils",
"libidmap2",
+ "libidmap2_policies",
"liblog",
+ "libprotobuf-cpp-lite",
"libutils",
"libziparchive",
- "libidmap2_policies",
],
shared_libs: [
"libz",
@@ -236,11 +268,13 @@ cc_binary {
"libbinder",
"libcutils",
"libidmap2",
+ "libidmap2_policies",
+ "libprotobuf-cpp-lite",
"libutils",
"libziparchive",
- "libidmap2_policies",
],
static_libs: [
+ "libidmap2_protos",
"libidmap2daidl",
],
init_rc: ["idmap2d/idmap2d.rc"],
diff --git a/cmds/idmap2/idmap2/CommandUtils.cpp b/cmds/idmap2/idmap2/CommandUtils.cpp
index 09867f3a9c20..bf30a76d581a 100644
--- a/cmds/idmap2/idmap2/CommandUtils.cpp
+++ b/cmds/idmap2/idmap2/CommandUtils.cpp
@@ -25,7 +25,9 @@
using android::idmap2::Error;
using android::idmap2::IdmapHeader;
+using android::idmap2::OverlayResourceContainer;
using android::idmap2::Result;
+using android::idmap2::TargetResourceContainer;
using android::idmap2::Unit;
Result<Unit> Verify(const std::string& idmap_path, const std::string& target_path,
@@ -39,11 +41,20 @@ Result<Unit> Verify(const std::string& idmap_path, const std::string& target_pat
return Error("failed to parse idmap header");
}
- const auto header_ok = header->IsUpToDate(target_path, overlay_path, overlay_name,
- fulfilled_policies, enforce_overlayable);
+ auto target = TargetResourceContainer::FromPath(target_path);
+ if (!target) {
+ return Error("failed to load target '%s'", target_path.c_str());
+ }
+
+ auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+ if (!overlay) {
+ return Error("failed to load overlay '%s'", overlay_path.c_str());
+ }
+
+ const auto header_ok = header->IsUpToDate(**target, **overlay, overlay_name, fulfilled_policies,
+ enforce_overlayable);
if (!header_ok) {
return Error(header_ok.GetError(), "idmap not up to date");
}
-
return Unit{};
}
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index c93c717a15d2..977a0bbadafb 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -20,7 +20,6 @@
#include <fstream>
#include <memory>
#include <ostream>
-#include <string>
#include <vector>
#include "androidfw/ResourceTypes.h"
@@ -31,12 +30,13 @@
#include "idmap2/PolicyUtils.h"
#include "idmap2/SysTrace.h"
-using android::ApkAssets;
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::CommandLineOptions;
using android::idmap2::Error;
using android::idmap2::Idmap;
+using android::idmap2::OverlayResourceContainer;
using android::idmap2::Result;
+using android::idmap2::TargetResourceContainer;
using android::idmap2::Unit;
using android::idmap2::utils::kIdmapFilePermissionMask;
using android::idmap2::utils::PoliciesToBitmaskResult;
@@ -93,18 +93,18 @@ Result<Unit> Create(const std::vector<std::string>& args) {
fulfilled_policies |= PolicyFlags::PUBLIC;
}
- const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- if (!target_apk) {
- return Error("failed to load apk %s", target_apk_path.c_str());
+ const auto target = TargetResourceContainer::FromPath(target_apk_path);
+ if (!target) {
+ return Error("failed to load target '%s'", target_apk_path.c_str());
}
- const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- if (!overlay_apk) {
- return Error("failed to load apk %s", overlay_apk_path.c_str());
+ const auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+ if (!overlay) {
+ return Error("failed to load apk overlay '%s'", overlay_apk_path.c_str());
}
- const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, overlay_name,
- fulfilled_policies, !ignore_overlayable);
+ const auto idmap = Idmap::FromContainers(**target, **overlay, overlay_name, fulfilled_policies,
+ !ignore_overlayable);
if (!idmap) {
return Error(idmap.GetError(), "failed to create idmap");
}
@@ -112,13 +112,14 @@ Result<Unit> Create(const std::vector<std::string>& args) {
umask(kIdmapFilePermissionMask);
std::ofstream fout(idmap_path);
if (fout.fail()) {
- return Error("failed to open idmap path %s", idmap_path.c_str());
+ return Error("failed to open idmap path '%s'", idmap_path.c_str());
}
+
BinaryStreamVisitor visitor(fout);
(*idmap)->accept(&visitor);
fout.close();
if (fout.fail()) {
- return Error("failed to write to idmap path %s", idmap_path.c_str());
+ return Error("failed to write to idmap path '%s'", idmap_path.c_str());
}
return Unit{};
diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp
index 5db391caac30..953d99f8dcfb 100644
--- a/cmds/idmap2/idmap2/CreateMultiple.cpp
+++ b/cmds/idmap2/idmap2/CreateMultiple.cpp
@@ -34,13 +34,14 @@
#include "idmap2/PolicyUtils.h"
#include "idmap2/SysTrace.h"
-using android::ApkAssets;
using android::base::StringPrintf;
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::CommandLineOptions;
using android::idmap2::Error;
using android::idmap2::Idmap;
+using android::idmap2::OverlayResourceContainer;
using android::idmap2::Result;
+using android::idmap2::TargetResourceContainer;
using android::idmap2::Unit;
using android::idmap2::utils::kIdmapCacheDir;
using android::idmap2::utils::kIdmapFilePermissionMask;
@@ -91,9 +92,9 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
fulfilled_policies |= PolicyFlags::PUBLIC;
}
- const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- if (!target_apk) {
- return Error("failed to load apk %s", target_apk_path.c_str());
+ const auto target = TargetResourceContainer::FromPath(target_apk_path);
+ if (!target) {
+ return Error("failed to load target '%s'", target_apk_path.c_str());
}
std::vector<std::string> idmap_paths;
@@ -108,14 +109,14 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
// TODO(b/175014391): Support multiple overlay tags in OverlayConfig
if (!Verify(idmap_path, target_apk_path, overlay_apk_path, "", fulfilled_policies,
!ignore_overlayable)) {
- const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- if (!overlay_apk) {
+ const auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+ if (!overlay) {
LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str();
continue;
}
- const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, "", fulfilled_policies,
- !ignore_overlayable);
+ const auto idmap =
+ Idmap::FromContainers(**target, **overlay, "", fulfilled_policies, !ignore_overlayable);
if (!idmap) {
LOG(WARNING) << "failed to create idmap";
continue;
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index 43a1951a5ba9..f41e57cc66d6 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -37,7 +37,6 @@
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
#include "idmap2/XmlParser.h"
-#include "idmap2/ZipFile.h"
#include "utils/String16.h"
#include "utils/String8.h"
@@ -52,10 +51,10 @@ using android::base::StringPrintf;
using android::idmap2::CommandLineOptions;
using android::idmap2::Error;
using android::idmap2::IdmapHeader;
+using android::idmap2::OverlayResourceContainer;
using android::idmap2::ResourceId;
using android::idmap2::Result;
using android::idmap2::Unit;
-using android::idmap2::utils::ExtractOverlayManifestInfo;
namespace {
@@ -195,12 +194,17 @@ Result<Unit> Lookup(const std::vector<std::string>& args) {
}
apk_assets.push_back(std::move(target_apk));
- auto manifest_info = ExtractOverlayManifestInfo(idmap_header->GetOverlayPath(),
- idmap_header->GetOverlayName());
+ auto overlay = OverlayResourceContainer::FromPath(idmap_header->GetOverlayPath());
+ if (!overlay) {
+ return overlay.GetError();
+ }
+
+ auto manifest_info = (*overlay)->FindOverlayInfo(idmap_header->GetOverlayName());
if (!manifest_info) {
return manifest_info.GetError();
}
- target_package_name = manifest_info->target_package;
+
+ target_package_name = (*manifest_info).target_package;
} else if (target_path != idmap_header->GetTargetPath()) {
return Error("different target APKs (expected target APK %s but %s has target APK %s)",
target_path.c_str(), idmap_path.c_str(), idmap_header->GetTargetPath().c_str());
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 93537d32299b..f62630e702d4 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -35,17 +35,16 @@
#include "idmap2/Idmap.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
-#include "idmap2/ZipFile.h"
#include "utils/String8.h"
using android::IPCThreadState;
using android::base::StringPrintf;
using android::binder::Status;
using android::idmap2::BinaryStreamVisitor;
-using android::idmap2::GetPackageCrc;
using android::idmap2::Idmap;
using android::idmap2::IdmapHeader;
-using android::idmap2::ZipFile;
+using android::idmap2::OverlayResourceContainer;
+using android::idmap2::TargetResourceContainer;
using android::idmap2::utils::kIdmapCacheDir;
using android::idmap2::utils::kIdmapFilePermissionMask;
using android::idmap2::utils::UidHasWriteAccessToPath;
@@ -68,40 +67,24 @@ Status error(const std::string& msg) {
PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
return static_cast<PolicyBitmask>(arg);
}
-
-Status GetCrc(const std::string& apk_path, uint32_t* out_crc) {
- const auto zip = ZipFile::Open(apk_path);
- if (!zip) {
- return error(StringPrintf("failed to open apk %s", apk_path.c_str()));
- }
-
- const auto crc = GetPackageCrc(*zip);
- if (!crc) {
- return error(crc.GetErrorMessage());
- }
-
- *out_crc = *crc;
- return ok();
-}
-
} // namespace
namespace android::os {
-Status Idmap2Service::getIdmapPath(const std::string& overlay_apk_path,
+Status Idmap2Service::getIdmapPath(const std::string& overlay_path,
int32_t user_id ATTRIBUTE_UNUSED, std::string* _aidl_return) {
assert(_aidl_return);
- SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_apk_path;
- *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+ SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_path;
+ *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
return ok();
}
-Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
- int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
+Status Idmap2Service::removeIdmap(const std::string& overlay_path, int32_t user_id ATTRIBUTE_UNUSED,
+ bool* _aidl_return) {
assert(_aidl_return);
- SYSTRACE << "Idmap2Service::removeIdmap " << overlay_apk_path;
+ SYSTRACE << "Idmap2Service::removeIdmap " << overlay_path;
const uid_t uid = IPCThreadState::self()->getCallingUid();
- const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+ const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
if (!UidHasWriteAccessToPath(uid, idmap_path)) {
*_aidl_return = false;
return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
@@ -115,85 +98,79 @@ Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
return ok();
}
-Status Idmap2Service::verifyIdmap(const std::string& target_apk_path,
- const std::string& overlay_apk_path, int32_t fulfilled_policies,
- bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
- bool* _aidl_return) {
- SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path;
+Status Idmap2Service::verifyIdmap(const std::string& target_path, const std::string& overlay_path,
+ int32_t fulfilled_policies, bool enforce_overlayable,
+ int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
+ SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_path;
assert(_aidl_return);
- const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+ const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
std::ifstream fin(idmap_path);
const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
fin.close();
if (!header) {
*_aidl_return = false;
- return error("failed to parse idmap header");
+ LOG(WARNING) << "failed to parse idmap header of '" << idmap_path << "'";
+ return ok();
}
- uint32_t target_crc;
- if (target_apk_path == kFrameworkPath && android_crc_) {
- target_crc = *android_crc_;
- } else {
- auto target_crc_status = GetCrc(target_apk_path, &target_crc);
- if (!target_crc_status.isOk()) {
- *_aidl_return = false;
- return target_crc_status;
- }
-
- // Loading the framework zip can take several milliseconds. Cache the crc of the framework
- // resource APK to reduce repeated work during boot.
- if (target_apk_path == kFrameworkPath) {
- android_crc_ = target_crc;
- }
+ const auto target = GetTargetContainer(target_path);
+ if (!target) {
+ *_aidl_return = false;
+ LOG(WARNING) << "failed to load target '" << target_path << "'";
+ return ok();
}
- uint32_t overlay_crc;
- auto overlay_crc_status = GetCrc(overlay_apk_path, &overlay_crc);
- if (!overlay_crc_status.isOk()) {
+ const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+ if (!overlay) {
*_aidl_return = false;
- return overlay_crc_status;
+ LOG(WARNING) << "failed to load overlay '" << overlay_path << "'";
+ return ok();
}
// TODO(162841629): Support passing overlay name to idmap2d verify
auto up_to_date =
- header->IsUpToDate(target_apk_path, overlay_apk_path, "", target_crc, overlay_crc,
+ header->IsUpToDate(*GetPointer(*target), **overlay, "",
ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable);
*_aidl_return = static_cast<bool>(up_to_date);
- return *_aidl_return ? ok() : error(up_to_date.GetErrorMessage());
+ if (!up_to_date) {
+ LOG(WARNING) << "idmap '" << idmap_path
+ << "' not up to date : " << up_to_date.GetErrorMessage();
+ }
+ return ok();
}
-Status Idmap2Service::createIdmap(const std::string& target_apk_path,
- const std::string& overlay_apk_path, int32_t fulfilled_policies,
- bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
+Status Idmap2Service::createIdmap(const std::string& target_path, const std::string& overlay_path,
+ int32_t fulfilled_policies, bool enforce_overlayable,
+ int32_t user_id ATTRIBUTE_UNUSED,
std::optional<std::string>* _aidl_return) {
assert(_aidl_return);
- SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path;
+ SYSTRACE << "Idmap2Service::createIdmap " << target_path << " " << overlay_path;
_aidl_return->reset();
const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
- const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+ const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_path);
const uid_t uid = IPCThreadState::self()->getCallingUid();
if (!UidHasWriteAccessToPath(uid, idmap_path)) {
return error(base::StringPrintf("will not write to %s: calling uid %d lacks write accesss",
idmap_path.c_str(), uid));
}
- const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- if (!target_apk) {
- return error("failed to load apk " + target_apk_path);
+ const auto target = GetTargetContainer(target_path);
+ if (!target) {
+ return error("failed to load target '%s'" + target_path);
}
- const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- if (!overlay_apk) {
- return error("failed to load apk " + overlay_apk_path);
+ const auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+ if (!overlay) {
+ return error("failed to load apk overlay '%s'" + overlay_path);
}
// TODO(162841629): Support passing overlay name to idmap2d create
- const auto idmap =
- Idmap::FromApkAssets(*target_apk, *overlay_apk, "", policy_bitmask, enforce_overlayable);
+ const auto idmap = Idmap::FromContainers(*GetPointer(*target), **overlay, "", policy_bitmask,
+ enforce_overlayable);
if (!idmap) {
return error(idmap.GetErrorMessage());
}
@@ -220,4 +197,25 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path,
return ok();
}
+idmap2::Result<Idmap2Service::TargetResourceContainerPtr> Idmap2Service::GetTargetContainer(
+ const std::string& target_path) {
+ if (target_path == kFrameworkPath) {
+ if (framework_apk_cache_ == nullptr) {
+ // Initialize the framework APK cache.
+ auto target = TargetResourceContainer::FromPath(target_path);
+ if (!target) {
+ return target.GetError();
+ }
+ framework_apk_cache_ = std::move(*target);
+ }
+ return {framework_apk_cache_.get()};
+ }
+
+ auto target = TargetResourceContainer::FromPath(target_path);
+ if (!target) {
+ return target.GetError();
+ }
+ return {std::move(*target)};
+}
+
} // namespace android::os
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index 0127e874b444..869a4d981f42 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -18,12 +18,13 @@
#define IDMAP2_IDMAP2D_IDMAP2SERVICE_H_
#include <android-base/unique_fd.h>
+#include <android/os/BnIdmap2.h>
#include <binder/BinderService.h>
+#include <idmap2/ResourceContainer.h>
+#include <idmap2/Result.h>
#include <string>
-#include "android/os/BnIdmap2.h"
-
namespace android::os {
class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
@@ -32,27 +33,44 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
return "idmap";
}
- binder::Status getIdmapPath(const std::string& overlay_apk_path, int32_t user_id,
+ binder::Status getIdmapPath(const std::string& overlay_path, int32_t user_id,
std::string* _aidl_return) override;
- binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
+ binder::Status removeIdmap(const std::string& overlay_path, int32_t user_id,
bool* _aidl_return) override;
- binder::Status verifyIdmap(const std::string& target_apk_path,
- const std::string& overlay_apk_path, int32_t fulfilled_policies,
- bool enforce_overlayable, int32_t user_id,
+ binder::Status verifyIdmap(const std::string& target_path, const std::string& overlay_path,
+ int32_t fulfilled_policies, bool enforce_overlayable, int32_t user_id,
bool* _aidl_return) override;
- binder::Status createIdmap(const std::string& target_apk_path,
- const std::string& overlay_apk_path, int32_t fulfilled_policies,
- bool enforce_overlayable, int32_t user_id,
+ binder::Status createIdmap(const std::string& target_path, const std::string& overlay_path,
+ int32_t fulfilled_policies, bool enforce_overlayable, int32_t user_id,
std::optional<std::string>* _aidl_return) override;
private:
- // Cache the crc of the android framework package since the crc cannot change without a reboot.
- std::optional<uint32_t> android_crc_;
+ // idmap2d is killed after a period of inactivity, so any information stored on this class should
+ // be able to be recalculated if idmap2 dies and restarts.
+ std::unique_ptr<idmap2::TargetResourceContainer> framework_apk_cache_;
+
+ template <typename T>
+ using MaybeUniquePtr = std::variant<std::unique_ptr<T>, T*>;
+
+ using TargetResourceContainerPtr = MaybeUniquePtr<idmap2::TargetResourceContainer>;
+ idmap2::Result<TargetResourceContainerPtr> GetTargetContainer(const std::string& target_path);
+
+ template <typename T>
+ WARN_UNUSED static const T* GetPointer(const MaybeUniquePtr<T>& ptr);
};
+template <typename T>
+const T* Idmap2Service::GetPointer(const MaybeUniquePtr<T>& ptr) {
+ auto u = std::get_if<T*>(&ptr);
+ if (u != nullptr) {
+ return *u;
+ }
+ return std::get<std::unique_ptr<T>>(ptr).get();
+}
+
} // namespace android::os
#endif // IDMAP2_IDMAP2D_IDMAP2SERVICE_H_
diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
new file mode 100644
index 000000000000..d82315723f71
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_FABRICATEDOVERLAY_H
+#define IDMAP2_INCLUDE_IDMAP2_FABRICATEDOVERLAY_H
+
+#include <libidmap2/proto/fabricated_v1.pb.h>
+
+#include <iostream>
+#include <map>
+#include <memory>
+#include <unordered_map>
+
+#include "idmap2/ResourceContainer.h"
+#include "idmap2/Result.h"
+
+namespace android::idmap2 {
+
+struct FabricatedOverlay {
+ struct Builder {
+ Builder(const std::string& package_name, const std::string& name,
+ const std::string& target_package_name);
+
+ Builder& SetOverlayable(const std::string& name);
+
+ Builder& SetResourceValue(const std::string& resource_name, uint8_t data_type,
+ uint32_t data_value);
+
+ WARN_UNUSED Result<FabricatedOverlay> Build();
+
+ private:
+ struct Entry {
+ std::string resource_name;
+ DataType data_type;
+ DataValue data_value;
+ };
+
+ std::string package_name_;
+ std::string name_;
+ std::string target_package_name_;
+ std::string target_overlayable_;
+ std::vector<Entry> entries_;
+ };
+
+ Result<Unit> ToBinaryStream(std::ostream& stream);
+ static Result<FabricatedOverlay> FromBinaryStream(std::istream& stream);
+
+ private:
+ struct SerializedData {
+ std::unique_ptr<uint8_t[]> data;
+ size_t data_size;
+ uint32_t crc;
+ };
+
+ Result<SerializedData*> InitializeData() const;
+ Result<uint32_t> GetCrc() const;
+
+ FabricatedOverlay(pb::FabricatedOverlay&& overlay, std::optional<uint32_t> crc_from_disk = {});
+
+ pb::FabricatedOverlay overlay_pb_;
+ std::optional<uint32_t> crc_from_disk_;
+ mutable std::optional<SerializedData> data_;
+
+ friend struct FabricatedOverlayContainer;
+};
+
+struct FabricatedOverlayContainer : public OverlayResourceContainer {
+ static Result<std::unique_ptr<FabricatedOverlayContainer>> FromPath(std::string path);
+ static std::unique_ptr<FabricatedOverlayContainer> FromOverlay(FabricatedOverlay&& overlay);
+
+ // inherited from OverlayResourceContainer
+ WARN_UNUSED Result<OverlayManifestInfo> FindOverlayInfo(const std::string& name) const override;
+ WARN_UNUSED Result<OverlayData> GetOverlayData(const OverlayManifestInfo& info) const override;
+
+ // inherited from ResourceContainer
+ WARN_UNUSED Result<uint32_t> GetCrc() const override;
+ WARN_UNUSED const std::string& GetPath() const override;
+ WARN_UNUSED Result<std::string> GetResourceName(ResourceId id) const override;
+
+ ~FabricatedOverlayContainer() override;
+
+ private:
+ FabricatedOverlayContainer(FabricatedOverlay&& overlay, std::string&& path);
+ FabricatedOverlay overlay_;
+ std::string path_;
+};
+
+} // namespace android::idmap2
+
+#endif // IDMAP2_INCLUDE_IDMAP2_FABRICATEDOVERLAY_H
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 1b815c1197ca..58aff42b1e98 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -23,8 +23,8 @@
* debug_info
* data := data_header target_entry* target_inline_entry* overlay_entry*
* string_pool
- * data_header := target_package_id overlay_package_id padding(2) target_entry_count
- * target_inline_entry_count overlay_entry_count string_pool_index
+ * data_header := target_entry_count target_inline_entry_count overlay_entry_count
+ * string_pool_index
* target_entry := target_id overlay_id
* target_inline_entry := target_id Res_value::size padding(1) Res_value::type
* Res_value::value
@@ -68,11 +68,10 @@
#include <vector>
#include "android-base/macros.h"
-#include "androidfw/ApkAssets.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
+#include "idmap2/ResourceContainer.h"
#include "idmap2/ResourceMapping.h"
-#include "idmap2/ZipFile.h"
namespace android::idmap2 {
@@ -85,9 +84,6 @@ static constexpr const uint32_t kIdmapMagic = android::kIdmapMagic;
// current version of the idmap binary format; must be incremented when the format is changed
static constexpr const uint32_t kIdmapCurrentVersion = android::kIdmapCurrentVersion;
-// Retrieves a crc generated using all of the files within the zip that can affect idmap generation.
-Result<uint32_t> GetPackageCrc(const ZipFile& zip_info);
-
class IdmapHeader {
public:
static std::unique_ptr<const IdmapHeader> FromBinaryStream(std::istream& stream);
@@ -135,9 +131,9 @@ class IdmapHeader {
// Invariant: anytime the idmap data encoding is changed, the idmap version
// field *must* be incremented. Because of this, we know that if the idmap
// header is up-to-date the entire file is up-to-date.
- Result<Unit> IsUpToDate(const std::string& target_path, const std::string& overlay_path,
- const std::string& overlay_name, PolicyBitmask fulfilled_policies,
- bool enforce_overlayable) const;
+ Result<Unit> IsUpToDate(const TargetResourceContainer& target,
+ const OverlayResourceContainer& overlay, const std::string& overlay_name,
+ PolicyBitmask fulfilled_policies, bool enforce_overlayable) const;
Result<Unit> IsUpToDate(const std::string& target_path, const std::string& overlay_path,
const std::string& overlay_name, uint32_t target_crc,
@@ -169,14 +165,6 @@ class IdmapData {
public:
static std::unique_ptr<const Header> FromBinaryStream(std::istream& stream);
- inline PackageId GetTargetPackageId() const {
- return target_package_id_;
- }
-
- inline PackageId GetOverlayPackageId() const {
- return overlay_package_id_;
- }
-
inline uint32_t GetTargetEntryCount() const {
return target_entry_count;
}
@@ -196,8 +184,6 @@ class IdmapData {
void accept(Visitor* v) const;
private:
- PackageId target_package_id_;
- PackageId overlay_package_id_;
uint32_t target_entry_count;
uint32_t target_entry_inline_count;
uint32_t overlay_entry_count;
@@ -275,11 +261,10 @@ class Idmap {
// file is used; change this in the next version of idmap to use a named
// package instead; also update FromApkAssets to take additional parameters:
// the target and overlay package names
- static Result<std::unique_ptr<const Idmap>> FromApkAssets(const ApkAssets& target_apk_assets,
- const ApkAssets& overlay_apk_assets,
- const std::string& overlay_name,
- const PolicyBitmask& fulfilled_policies,
- bool enforce_overlayable);
+ static Result<std::unique_ptr<const Idmap>> FromContainers(
+ const TargetResourceContainer& target, const OverlayResourceContainer& overlay,
+ const std::string& overlay_name, const PolicyBitmask& fulfilled_policies,
+ bool enforce_overlayable);
const std::unique_ptr<const IdmapHeader>& GetHeader() const {
return header_;
diff --git a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
index 2b4c76124175..4464201a1f2e 100644
--- a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
@@ -41,9 +41,8 @@ class PrettyPrintVisitor : public Visitor {
private:
std::ostream& stream_;
- AssetManager2 target_am_;
- AssetManager2 overlay_am_;
- std::vector<std::unique_ptr<const ApkAssets>> apk_assets_;
+ std::unique_ptr<TargetResourceContainer> target_;
+ std::unique_ptr<OverlayResourceContainer> overlay_;
};
} // namespace idmap2
diff --git a/cmds/idmap2/include/idmap2/RawPrintVisitor.h b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
index 45835164ef8e..ebd0d1eb2fbc 100644
--- a/cmds/idmap2/include/idmap2/RawPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
@@ -49,10 +49,9 @@ class RawPrintVisitor : public Visitor {
void pad(size_t padding);
std::ostream& stream_;
- std::vector<std::unique_ptr<const ApkAssets>> apk_assets_;
- AssetManager2 target_am_;
- AssetManager2 overlay_am_;
size_t offset_;
+ std::unique_ptr<TargetResourceContainer> target_;
+ std::unique_ptr<OverlayResourceContainer> overlay_;
};
} // namespace idmap2
diff --git a/cmds/idmap2/include/idmap2/ResourceContainer.h b/cmds/idmap2/include/idmap2/ResourceContainer.h
new file mode 100644
index 000000000000..7a22dc668e62
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/ResourceContainer.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_RESOURCECONTAINER_H
+#define IDMAP2_INCLUDE_IDMAP2_RESOURCECONTAINER_H
+
+#include <string>
+#include <variant>
+#include <vector>
+
+#include "idmap2/Policies.h"
+#include "idmap2/ResourceUtils.h"
+
+namespace android::idmap2 {
+
+struct ResourceContainer {
+ WARN_UNUSED virtual Result<uint32_t> GetCrc() const = 0;
+ WARN_UNUSED virtual const std::string& GetPath() const = 0;
+ WARN_UNUSED virtual Result<std::string> GetResourceName(ResourceId id) const = 0;
+
+ virtual ~ResourceContainer() = default;
+};
+
+struct TargetResourceContainer : public ResourceContainer {
+ static Result<std::unique_ptr<TargetResourceContainer>> FromPath(std::string path);
+
+ WARN_UNUSED virtual Result<bool> DefinesOverlayable() const = 0;
+ WARN_UNUSED virtual Result<const android::OverlayableInfo*> GetOverlayableInfo(
+ ResourceId id) const = 0;
+ WARN_UNUSED virtual Result<ResourceId> GetResourceId(const std::string& name) const = 0;
+
+ ~TargetResourceContainer() override = default;
+};
+
+struct OverlayManifestInfo {
+ std::string name; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string target_package; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string target_name; // NOLINT(misc-non-private-member-variables-in-classes)
+ ResourceId resource_mapping; // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
+struct OverlayData {
+ struct ResourceIdValue {
+ // The overlay resource id.
+ ResourceId overlay_id;
+
+ // Whether or not references to the overlay resource id should be rewritten to its corresponding
+ // target id during resource resolution.
+ bool rewrite_id;
+ };
+
+ struct Value {
+ std::string resource_name;
+ std::variant<ResourceIdValue, TargetValue> value;
+ };
+
+ struct InlineStringPoolData {
+ // The binary data of the android::ResStringPool string pool.
+ std::unique_ptr<uint8_t[]> data;
+
+ // The length of the binary data.
+ uint32_t data_length;
+
+ // The offset added to TargetValue#data_value (the index of the string in the inline string
+ // pool) in order to prevent the indices of the overlay resource table string pool from
+ // colliding with the inline string pool indices.
+ uint32_t string_pool_offset;
+ };
+
+ // The overlay's mapping of target resource name to overlaid value. Use a vector to enforce that
+ // the overlay pairs are inserted into the ResourceMapping in the specified ordered.
+ std::vector<Value> pairs;
+
+ // If the overlay maps a target resource to a string literal (not a string resource), then the
+ // this field contains information about the string pool in which the string literal resides so it
+ // can be inlined into an idmap.
+ std::optional<InlineStringPoolData> string_pool_data;
+};
+
+struct OverlayResourceContainer : public ResourceContainer {
+ static Result<std::unique_ptr<OverlayResourceContainer>> FromPath(std::string path);
+
+ WARN_UNUSED virtual Result<OverlayManifestInfo> FindOverlayInfo(
+ const std::string& name) const = 0;
+ WARN_UNUSED virtual Result<OverlayData> GetOverlayData(const OverlayManifestInfo& info) const = 0;
+
+ ~OverlayResourceContainer() override = default;
+};
+
+} // namespace android::idmap2
+
+#endif // IDMAP2_INCLUDE_IDMAP2_RESOURCECONTAINER_H
diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h
index f66916ccb78c..5a0a384f75a3 100644
--- a/cmds/idmap2/include/idmap2/ResourceMapping.h
+++ b/cmds/idmap2/include/idmap2/ResourceMapping.h
@@ -17,30 +17,22 @@
#ifndef IDMAP2_INCLUDE_IDMAP2_RESOURCEMAPPING_H_
#define IDMAP2_INCLUDE_IDMAP2_RESOURCEMAPPING_H_
+#include <androidfw/ApkAssets.h>
+
#include <map>
#include <memory>
#include <utility>
-#include "androidfw/ApkAssets.h"
+#include "idmap2/FabricatedOverlay.h"
#include "idmap2/LogInfo.h"
#include "idmap2/Policies.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/XmlParser.h"
-using android::idmap2::utils::OverlayManifestInfo;
-
using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
namespace android::idmap2 {
-
-struct TargetValue {
- typedef uint8_t DataType;
- typedef uint32_t DataValue;
- DataType data_type;
- DataValue data_value;
-};
-
using TargetResourceMap = std::map<ResourceId, std::variant<ResourceId, TargetValue>>;
using OverlayResourceMap = std::map<ResourceId, ResourceId>;
@@ -49,94 +41,60 @@ class ResourceMapping {
// Creates a ResourceMapping using the target and overlay APKs. Setting enforce_overlayable to
// `false` disables all overlayable and policy enforcement: this is intended for backwards
// compatibility pre-Q and unit tests.
- static Result<ResourceMapping> FromApkAssets(const ApkAssets& target_apk_assets,
- const ApkAssets& overlay_apk_assets,
- const OverlayManifestInfo& overlay_info,
- const PolicyBitmask& fulfilled_policies,
- bool enforce_overlayable, LogInfo& log_info);
+ static Result<ResourceMapping> FromContainers(const TargetResourceContainer& target,
+ const OverlayResourceContainer& overlay,
+ const OverlayManifestInfo& overlay_info,
+ const PolicyBitmask& fulfilled_policies,
+ bool enforce_overlayable, LogInfo& log_info);
// Retrieves the mapping of target resource id to overlay value.
- inline const TargetResourceMap& GetTargetToOverlayMap() const {
- return target_map_;
- }
+ WARN_UNUSED const TargetResourceMap& GetTargetToOverlayMap() const;
// Retrieves the mapping of overlay resource id to target resource id. This allows a reference to
// an overlay resource to appear as a reference to its corresponding target resource at runtime.
- OverlayResourceMap GetOverlayToTargetMap() const;
-
- // Retrieves the build-time package id of the target package.
- inline uint32_t GetTargetPackageId() const {
- return target_package_id_;
- }
-
- // Retrieves the build-time package id of the overlay package.
- inline uint32_t GetOverlayPackageId() const {
- return overlay_package_id_;
- }
+ WARN_UNUSED const OverlayResourceMap& GetOverlayToTargetMap() const;
// Retrieves the offset that was added to the index of inline string overlay values so the indices
// do not collide with the indices of the overlay resource table string pool.
- inline uint32_t GetStringPoolOffset() const {
- return string_pool_offset_;
- }
+ WARN_UNUSED uint32_t GetStringPoolOffset() const;
// Retrieves the raw string pool data from the xml referenced in android:resourcesMap.
- inline const StringPiece GetStringPoolData() const {
- return StringPiece(reinterpret_cast<const char*>(string_pool_data_.get()),
- string_pool_data_length_);
- }
+ WARN_UNUSED StringPiece GetStringPoolData() const;
private:
ResourceMapping() = default;
- // Maps a target resource id to an overlay resource id.
- // If rewrite_overlay_reference is `true` then references to the overlay
- // resource should appear as a reference to its corresponding target resource at runtime.
- Result<Unit> AddMapping(ResourceId target_resource, ResourceId overlay_resource,
- bool rewrite_overlay_reference);
-
- // Maps a target resource id to a data type and value combination.
- // The `data_type` is the runtime format of the data value (see Res_value::dataType).
- Result<Unit> AddMapping(ResourceId target_resource, TargetValue::DataType data_type,
- TargetValue::DataValue data_value);
-
- // Removes the overlay value mapping for the target resource.
- void RemoveMapping(ResourceId target_resource);
-
- // Parses the mapping of target resources to overlay resources to generate a ResourceMapping.
- static Result<ResourceMapping> CreateResourceMapping(const AssetManager2* target_am,
- const LoadedPackage* target_package,
- const LoadedPackage* overlay_package,
- size_t string_pool_offset,
- const XmlParser& overlay_parser,
- LogInfo& log_info);
-
- // Generates a ResourceMapping that maps target resources to overlay resources by name. To overlay
- // a target resource, a resource must exist in the overlay with the same type and entry name as
- // the target resource.
- static Result<ResourceMapping> CreateResourceMappingLegacy(const AssetManager2* target_am,
- const AssetManager2* overlay_am,
- const LoadedPackage* target_package,
- const LoadedPackage* overlay_package,
- LogInfo& log_info);
-
- // Removes resources that do not pass policy or overlayable checks of the target package.
- void FilterOverlayableResources(const AssetManager2* target_am,
- const LoadedPackage* target_package,
- const LoadedPackage* overlay_package,
- const OverlayManifestInfo& overlay_info,
- const PolicyBitmask& fulfilled_policies, LogInfo& log_info);
+ // Maps a target resource id to an overlay resource id or a android::Res_value value.
+ //
+ // If `allow_rewriting_` is true, then the overlay-to-target map will be populated if the target
+ // resource id is mapped to an overlay resource id.
+ Result<Unit> AddMapping(ResourceId target_resource,
+ const std::variant<OverlayData::ResourceIdValue, TargetValue>& value);
TargetResourceMap target_map_;
- std::multimap<ResourceId, ResourceId> overlay_map_;
-
- uint32_t target_package_id_ = 0;
- uint32_t overlay_package_id_ = 0;
+ OverlayResourceMap overlay_map_;
uint32_t string_pool_offset_ = 0;
uint32_t string_pool_data_length_ = 0;
std::unique_ptr<uint8_t[]> string_pool_data_ = nullptr;
};
+inline const TargetResourceMap& ResourceMapping::GetTargetToOverlayMap() const {
+ return target_map_;
+}
+
+inline const OverlayResourceMap& ResourceMapping::GetOverlayToTargetMap() const {
+ return overlay_map_;
+}
+
+inline uint32_t ResourceMapping::GetStringPoolOffset() const {
+ return string_pool_offset_;
+}
+
+inline StringPiece ResourceMapping::GetStringPoolData() const {
+ return StringPiece(reinterpret_cast<const char*>(string_pool_data_.get()),
+ string_pool_data_length_);
+}
+
} // namespace android::idmap2
#endif // IDMAP2_INCLUDE_IDMAP2_RESOURCEMAPPING_H_
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index cd14d3e7254c..a0202dfee473 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -22,19 +22,26 @@
#include "androidfw/AssetManager2.h"
#include "idmap2/Result.h"
-#include "idmap2/ZipFile.h"
namespace android::idmap2 {
-// use typedefs to let the compiler warn us about implicit casts
-typedef uint32_t ResourceId; // 0xpptteeee
-typedef uint8_t PackageId; // pp in 0xpptteeee
-typedef uint8_t TypeId; // tt in 0xpptteeee
-typedef uint16_t EntryId; // eeee in 0xpptteeee
-
#define EXTRACT_TYPE(resid) ((0x00ff0000 & (resid)) >> 16)
#define EXTRACT_ENTRY(resid) (0x0000ffff & (resid))
+// use typedefs to let the compiler warn us about implicit casts
+using ResourceId = uint32_t; // 0xpptteeee
+using PackageId = uint8_t; // pp in 0xpptteeee
+using TypeId = uint8_t; // tt in 0xpptteeee
+using EntryId = uint16_t; // eeee in 0xpptteeee
+
+using DataType = uint8_t; // Res_value::dataType
+using DataValue = uint32_t; // Res_value::data
+
+struct TargetValue {
+ DataType data_type;
+ DataValue data_value;
+};
+
namespace utils {
// Returns whether the Res_value::data_type represents a dynamic or regular resource reference.
@@ -43,20 +50,10 @@ bool IsReference(uint8_t data_type);
// Converts the Res_value::data_type to a human-readable string representation.
StringPiece DataTypeToString(uint8_t data_type);
-struct OverlayManifestInfo {
- std::string name; // NOLINT(misc-non-private-member-variables-in-classes)
- std::string target_package; // NOLINT(misc-non-private-member-variables-in-classes)
- std::string target_name; // NOLINT(misc-non-private-member-variables-in-classes)
- uint32_t resource_mapping; // NOLINT(misc-non-private-member-variables-in-classes)
-};
-
-Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
- const std::string& name);
-
+// Retrieves the type and entry name of the resource in the AssetManager in the form type/entry.
Result<std::string> ResToTypeEntryName(const AssetManager2& am, ResourceId resid);
} // namespace utils
-
} // namespace android::idmap2
#endif // IDMAP2_INCLUDE_IDMAP2_RESOURCEUTILS_H_
diff --git a/cmds/idmap2/include/idmap2/XmlParser.h b/cmds/idmap2/include/idmap2/XmlParser.h
index 1c74ab3bb691..c968a5e6c04f 100644
--- a/cmds/idmap2/include/idmap2/XmlParser.h
+++ b/cmds/idmap2/include/idmap2/XmlParser.h
@@ -30,8 +30,7 @@
namespace android::idmap2 {
-class XmlParser {
- public:
+struct XmlParser {
using Event = ResXMLParser::event_code_t;
class iterator;
@@ -127,23 +126,19 @@ class XmlParser {
};
// Creates a new xml parser beginning at the first tag.
- static Result<std::unique_ptr<const XmlParser>> Create(const void* data, size_t size,
- bool copy_data = false);
- ~XmlParser();
+ static Result<XmlParser> Create(const void* data, size_t size, bool copy_data = false);
inline iterator tree_iterator() const {
- return iterator(tree_);
+ return iterator(*tree_);
}
inline const ResStringPool& get_strings() const {
- return tree_.getStrings();
+ return tree_->getStrings();
}
private:
- XmlParser() = default;
- mutable ResXMLTree tree_;
-
- DISALLOW_COPY_AND_ASSIGN(XmlParser);
+ explicit XmlParser(std::unique_ptr<ResXMLTree> tree);
+ mutable std::unique_ptr<ResXMLTree> tree_;
};
} // namespace android::idmap2
diff --git a/cmds/idmap2/include/idmap2/ZipFile.h b/cmds/idmap2/include/idmap2/ZipFile.h
deleted file mode 100644
index 8f50e36256f6..000000000000
--- a/cmds/idmap2/include/idmap2/ZipFile.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef IDMAP2_INCLUDE_IDMAP2_ZIPFILE_H_
-#define IDMAP2_INCLUDE_IDMAP2_ZIPFILE_H_
-
-#include <memory>
-#include <string>
-
-#include "android-base/macros.h"
-#include "idmap2/Result.h"
-#include "ziparchive/zip_archive.h"
-
-namespace android::idmap2 {
-
-struct MemoryChunk {
- size_t size;
- uint8_t buf[0];
-
- static std::unique_ptr<MemoryChunk> Allocate(size_t size);
-
- private:
- MemoryChunk() {
- }
-};
-
-class ZipFile {
- public:
- static std::unique_ptr<const ZipFile> Open(const std::string& path);
-
- std::unique_ptr<const MemoryChunk> Uncompress(const std::string& entryPath) const;
- Result<uint32_t> Crc(const std::string& entryPath) const;
-
- ~ZipFile();
-
- private:
- explicit ZipFile(const ::ZipArchiveHandle handle) : handle_(handle) {
- }
-
- const ::ZipArchiveHandle handle_;
-
- DISALLOW_COPY_AND_ASSIGN(ZipFile);
-};
-
-} // namespace android::idmap2
-
-#endif // IDMAP2_INCLUDE_IDMAP2_ZIPFILE_H_
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index c16310792d12..3bbe9d91deb6 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -87,10 +87,6 @@ void BinaryStreamVisitor::visit(const IdmapData& data) {
}
void BinaryStreamVisitor::visit(const IdmapData::Header& header) {
- Write8(header.GetTargetPackageId());
- Write8(header.GetOverlayPackageId());
- Write8(0U); // padding
- Write8(0U); // padding
Write32(header.GetTargetEntryCount());
Write32(header.GetTargetInlineEntryCount());
Write32(header.GetOverlayEntryCount());
diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
new file mode 100644
index 000000000000..4a348ac232bc
--- /dev/null
+++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "idmap2/FabricatedOverlay.h"
+
+#include <androidfw/ResourceUtils.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <utils/ByteOrder.h>
+#include <zlib.h>
+
+#include <fstream>
+
+namespace android::idmap2 {
+
+namespace {
+bool Read32(std::istream& stream, uint32_t* out) {
+ uint32_t value;
+ if (stream.read(reinterpret_cast<char*>(&value), sizeof(uint32_t))) {
+ *out = dtohl(value);
+ return true;
+ }
+ return false;
+}
+
+void Write32(std::ostream& stream, uint32_t value) {
+ uint32_t x = htodl(value);
+ stream.write(reinterpret_cast<char*>(&x), sizeof(uint32_t));
+}
+} // namespace
+
+FabricatedOverlay::FabricatedOverlay(pb::FabricatedOverlay&& overlay,
+ std::optional<uint32_t> crc_from_disk)
+ : overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)), crc_from_disk_(crc_from_disk) {
+}
+
+FabricatedOverlay::Builder::Builder(const std::string& package_name, const std::string& name,
+ const std::string& target_package_name) {
+ package_name_ = package_name;
+ name_ = name;
+ target_package_name_ = target_package_name;
+}
+
+FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetOverlayable(const std::string& name) {
+ target_overlayable_ = name;
+ return *this;
+}
+
+FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
+ const std::string& resource_name, uint8_t data_type, uint32_t data_value) {
+ entries_.emplace_back(Entry{resource_name, data_type, data_value});
+ return *this;
+}
+
+Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
+ std::map<std::string, std::map<std::string, std::map<std::string, TargetValue>>> entries;
+ for (const auto& res_entry : entries_) {
+ StringPiece package_substr;
+ StringPiece type_name;
+ StringPiece entry_name;
+ if (!android::ExtractResourceName(StringPiece(res_entry.resource_name), &package_substr,
+ &type_name, &entry_name)) {
+ return Error("failed to parse resource name '%s'", res_entry.resource_name.c_str());
+ }
+
+ std::string package_name =
+ package_substr.empty() ? target_package_name_ : package_substr.to_string();
+ if (type_name.empty()) {
+ return Error("resource name '%s' missing type name", res_entry.resource_name.c_str());
+ }
+
+ if (entry_name.empty()) {
+ return Error("resource name '%s' missing entry name", res_entry.resource_name.c_str());
+ }
+
+ auto package = entries.find(package_name);
+ if (package == entries.end()) {
+ package = entries
+ .insert(std::make_pair<>(
+ package_name, std::map<std::string, std::map<std::string, TargetValue>>()))
+ .first;
+ }
+
+ auto type = package->second.find(type_name.to_string());
+ if (type == package->second.end()) {
+ type =
+ package->second
+ .insert(std::make_pair<>(type_name.to_string(), std::map<std::string, TargetValue>()))
+ .first;
+ }
+
+ auto entry = type->second.find(entry_name.to_string());
+ if (entry == type->second.end()) {
+ entry = type->second.insert(std::make_pair<>(entry_name.to_string(), TargetValue())).first;
+ }
+
+ entry->second = TargetValue{res_entry.data_type, res_entry.data_value};
+ }
+
+ pb::FabricatedOverlay overlay_pb;
+ overlay_pb.set_package_name(package_name_);
+ overlay_pb.set_name(name_);
+ overlay_pb.set_target_package_name(target_package_name_);
+ overlay_pb.set_target_overlayable(target_overlayable_);
+
+ for (const auto& package : entries) {
+ auto package_pb = overlay_pb.add_packages();
+ package_pb->set_name(package.first);
+
+ for (const auto& type : package.second) {
+ auto type_pb = package_pb->add_types();
+ type_pb->set_name(type.first);
+
+ for (const auto& entry : type.second) {
+ auto entry_pb = type_pb->add_entries();
+ entry_pb->set_name(entry.first);
+ pb::ResourceValue* value = entry_pb->mutable_res_value();
+ value->set_data_type(entry.second.data_type);
+ value->set_data_value(entry.second.data_value);
+ }
+ }
+ }
+
+ return FabricatedOverlay(std::move(overlay_pb));
+}
+
+Result<FabricatedOverlay> FabricatedOverlay::FromBinaryStream(std::istream& stream) {
+ uint32_t magic;
+ if (!Read32(stream, &magic)) {
+ return Error("Failed to read fabricated overlay magic.");
+ }
+
+ if (magic != kFabricatedOverlayMagic) {
+ return Error("Not a fabricated overlay file.");
+ }
+
+ uint32_t version;
+ if (!Read32(stream, &version)) {
+ return Error("Failed to read fabricated overlay version.");
+ }
+
+ if (version != 1) {
+ return Error("Invalid fabricated overlay version '%u'.", version);
+ }
+
+ uint32_t crc;
+ if (!Read32(stream, &crc)) {
+ return Error("Failed to read fabricated overlay version.");
+ }
+
+ pb::FabricatedOverlay overlay{};
+ if (!overlay.ParseFromIstream(&stream)) {
+ return Error("Failed read fabricated overlay proto.");
+ }
+
+ // If the proto version is the latest version, then the contents of the proto must be the same
+ // when the proto is re-serialized; otherwise, the crc must be calculated because migrating the
+ // proto to the latest version will likely change the contents of the fabricated overlay.
+ return FabricatedOverlay(std::move(overlay), version == kFabricatedOverlayCurrentVersion
+ ? std::optional<uint32_t>(crc)
+ : std::nullopt);
+}
+
+Result<FabricatedOverlay::SerializedData*> FabricatedOverlay::InitializeData() const {
+ if (!data_.has_value()) {
+ auto size = overlay_pb_.ByteSizeLong();
+ auto data = std::unique_ptr<uint8_t[]>(new uint8_t[size]);
+
+ // Ensure serialization is deterministic
+ google::protobuf::io::ArrayOutputStream array_stream(data.get(), size);
+ google::protobuf::io::CodedOutputStream output_stream(&array_stream);
+ output_stream.SetSerializationDeterministic(true);
+ overlay_pb_.SerializeWithCachedSizes(&output_stream);
+ if (output_stream.HadError() || size != output_stream.ByteCount()) {
+ return Error("Failed to serialize fabricated overlay.");
+ }
+
+ // Calculate the crc using the proto data and the version.
+ uint32_t crc = crc32(0L, Z_NULL, 0);
+ crc = crc32(crc, reinterpret_cast<const uint8_t*>(&kFabricatedOverlayCurrentVersion),
+ sizeof(uint32_t));
+ crc = crc32(crc, data.get(), size);
+ data_ = SerializedData{std::move(data), size, crc};
+ }
+ return &(*data_);
+}
+Result<uint32_t> FabricatedOverlay::GetCrc() const {
+ if (crc_from_disk_.has_value()) {
+ return *crc_from_disk_;
+ }
+ auto data = InitializeData();
+ if (!data) {
+ return data.GetError();
+ }
+ return (*data)->crc;
+}
+
+Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) {
+ auto data = InitializeData();
+ if (!data) {
+ return data.GetError();
+ }
+
+ Write32(stream, kFabricatedOverlayMagic);
+ Write32(stream, kFabricatedOverlayCurrentVersion);
+ Write32(stream, (*data)->crc);
+ stream.write(reinterpret_cast<const char*>((*data)->data.get()), (*data)->data_size);
+ if (stream.bad()) {
+ return Error("Failed to write serialized fabricated overlay.");
+ }
+
+ return Unit{};
+}
+
+using FabContainer = FabricatedOverlayContainer;
+FabContainer::FabricatedOverlayContainer(FabricatedOverlay&& overlay, std::string&& path)
+ : overlay_(std::forward<FabricatedOverlay>(overlay)), path_(std::forward<std::string>(path)) {
+}
+
+FabContainer::~FabricatedOverlayContainer() = default;
+
+Result<std::unique_ptr<FabContainer>> FabContainer::FromPath(std::string path) {
+ std::fstream fin(path);
+ auto overlay = FabricatedOverlay::FromBinaryStream(fin);
+ if (!overlay) {
+ return overlay.GetError();
+ }
+ return std::unique_ptr<FabContainer>(
+ new FabricatedOverlayContainer(std::move(*overlay), std::move(path)));
+}
+
+std::unique_ptr<FabricatedOverlayContainer> FabContainer::FromOverlay(FabricatedOverlay&& overlay) {
+ return std::unique_ptr<FabContainer>(
+ new FabricatedOverlayContainer(std::move(overlay), {} /* path */));
+}
+
+Result<OverlayManifestInfo> FabContainer::FindOverlayInfo(const std::string& name) const {
+ const pb::FabricatedOverlay& overlay_pb = overlay_.overlay_pb_;
+ if (name != overlay_pb.name()) {
+ return Error("Failed to find name '%s' in fabricated overlay", name.c_str());
+ }
+
+ return OverlayManifestInfo{
+ .name = overlay_pb.name(),
+ .target_package = overlay_pb.target_package_name(),
+ .target_name = overlay_pb.target_overlayable(),
+ };
+}
+
+Result<OverlayData> FabContainer::GetOverlayData(const OverlayManifestInfo& info) const {
+ const pb::FabricatedOverlay& overlay_pb = overlay_.overlay_pb_;
+ if (info.name != overlay_pb.name()) {
+ return Error("Failed to find name '%s' in fabricated overlay", info.name.c_str());
+ }
+
+ OverlayData result{};
+ for (const auto& package : overlay_pb.packages()) {
+ for (const auto& type : package.types()) {
+ for (const auto& entry : type.entries()) {
+ auto name = base::StringPrintf("%s:%s/%s", package.name().c_str(), type.name().c_str(),
+ entry.name().c_str());
+ const auto& res_value = entry.res_value();
+ result.pairs.emplace_back(OverlayData::Value{
+ name, TargetValue{.data_type = static_cast<uint8_t>(res_value.data_type()),
+ .data_value = res_value.data_value()}});
+ }
+ }
+ }
+ return result;
+}
+
+Result<uint32_t> FabContainer::GetCrc() const {
+ return overlay_.GetCrc();
+}
+
+const std::string& FabContainer::GetPath() const {
+ return path_;
+}
+
+Result<std::string> FabContainer::GetResourceName(ResourceId /* id */) const {
+ return Error("Fabricated overlay does not contain resources.");
+}
+
+} // namespace android::idmap2 \ No newline at end of file
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index a0cc407fc948..6515d5516d83 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -20,23 +20,16 @@
#include <iostream>
#include <iterator>
#include <limits>
-#include <map>
#include <memory>
-#include <set>
#include <string>
#include <utility>
-#include <vector>
#include "android-base/macros.h"
-#include "android-base/stringprintf.h"
#include "androidfw/AssetManager2.h"
#include "idmap2/ResourceMapping.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
-#include "idmap2/ZipFile.h"
-#include "utils/String16.h"
-#include "utils/String8.h"
namespace android::idmap2 {
@@ -93,22 +86,13 @@ bool WARN_UNUSED ReadString(std::istream& stream, std::string* out) {
} // namespace
-Result<uint32_t> GetPackageCrc(const ZipFile& zip) {
- const Result<uint32_t> a = zip.Crc("resources.arsc");
- const Result<uint32_t> b = zip.Crc("AndroidManifest.xml");
- return a && b
- ? Result<uint32_t>(*a ^ *b)
- : Error("failed to get CRC for \"%s\"", a ? "AndroidManifest.xml" : "resources.arsc");
-}
-
std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) {
std::unique_ptr<IdmapHeader> idmap_header(new IdmapHeader());
if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_)) {
return nullptr;
}
- if (idmap_header->magic_ != kIdmapMagic ||
- idmap_header->version_ != kIdmapCurrentVersion) {
+ if (idmap_header->magic_ != kIdmapMagic || idmap_header->version_ != kIdmapCurrentVersion) {
// Do not continue parsing if the file is not a current version idmap.
return nullptr;
}
@@ -127,32 +111,22 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s
return std::move(idmap_header);
}
-Result<Unit> IdmapHeader::IsUpToDate(const std::string& target_path,
- const std::string& overlay_path,
+Result<Unit> IdmapHeader::IsUpToDate(const TargetResourceContainer& target,
+ const OverlayResourceContainer& overlay,
const std::string& overlay_name,
PolicyBitmask fulfilled_policies,
bool enforce_overlayable) const {
- const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path);
- if (!target_zip) {
- return Error("failed to open target %s", target_path.c_str());
- }
-
- const Result<uint32_t> target_crc = GetPackageCrc(*target_zip);
+ const Result<uint32_t> target_crc = target.GetCrc();
if (!target_crc) {
return Error("failed to get target crc");
}
- const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path);
- if (!overlay_zip) {
- return Error("failed to overlay target %s", overlay_path.c_str());
- }
-
- const Result<uint32_t> overlay_crc = GetPackageCrc(*overlay_zip);
+ const Result<uint32_t> overlay_crc = overlay.GetCrc();
if (!overlay_crc) {
return Error("failed to get overlay crc");
}
- return IsUpToDate(target_path, overlay_path, overlay_name, *target_crc, *overlay_crc,
+ return IsUpToDate(target.GetPath(), overlay.GetPath(), overlay_name, *target_crc, *overlay_crc,
fulfilled_policies, enforce_overlayable);
}
@@ -209,11 +183,7 @@ Result<Unit> IdmapHeader::IsUpToDate(const std::string& target_path,
std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std::istream& stream) {
std::unique_ptr<IdmapData::Header> idmap_data_header(new IdmapData::Header());
-
- uint8_t padding;
- if (!Read8(stream, &idmap_data_header->target_package_id_) ||
- !Read8(stream, &idmap_data_header->overlay_package_id_) || !Read8(stream, &padding) ||
- !Read8(stream, &padding) || !Read32(stream, &idmap_data_header->target_entry_count) ||
+ if (!Read32(stream, &idmap_data_header->target_entry_count) ||
!Read32(stream, &idmap_data_header->target_entry_inline_count) ||
!Read32(stream, &idmap_data_header->overlay_entry_count) ||
!Read32(stream, &idmap_data_header->string_pool_index_offset)) {
@@ -321,8 +291,6 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
}
std::unique_ptr<IdmapData::Header> data_header(new IdmapData::Header());
- data_header->target_package_id_ = resource_mapping.GetTargetPackageId();
- data_header->overlay_package_id_ = resource_mapping.GetOverlayPackageId();
data_header->target_entry_count = static_cast<uint32_t>(data->target_entries_.size());
data_header->target_entry_inline_count =
static_cast<uint32_t>(data->target_inline_entries_.size());
@@ -332,57 +300,46 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
return {std::move(data)};
}
-Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const ApkAssets& target_apk_assets,
- const ApkAssets& overlay_apk_assets,
- const std::string& overlay_name,
- const PolicyBitmask& fulfilled_policies,
- bool enforce_overlayable) {
+Result<std::unique_ptr<const Idmap>> Idmap::FromContainers(const TargetResourceContainer& target,
+ const OverlayResourceContainer& overlay,
+ const std::string& overlay_name,
+ const PolicyBitmask& fulfilled_policies,
+ bool enforce_overlayable) {
SYSTRACE << "Idmap::FromApkAssets";
- const std::string& target_apk_path = target_apk_assets.GetPath();
- const std::string& overlay_apk_path = overlay_apk_assets.GetPath();
-
- const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_apk_path);
- if (!target_zip) {
- return Error("failed to open target as zip");
- }
-
- const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_apk_path);
- if (!overlay_zip) {
- return Error("failed to open overlay as zip");
- }
-
std::unique_ptr<IdmapHeader> header(new IdmapHeader());
header->magic_ = kIdmapMagic;
header->version_ = kIdmapCurrentVersion;
- Result<uint32_t> crc = GetPackageCrc(*target_zip);
- if (!crc) {
- return Error(crc.GetError(), "failed to get zip CRC for target");
+ const auto target_crc = target.GetCrc();
+ if (!target_crc) {
+ return Error(target_crc.GetError(), "failed to get zip CRC for '%s'", target.GetPath().data());
}
- header->target_crc_ = *crc;
+ header->target_crc_ = *target_crc;
- crc = GetPackageCrc(*overlay_zip);
- if (!crc) {
- return Error(crc.GetError(), "failed to get zip CRC for overlay");
+ const auto overlay_crc = overlay.GetCrc();
+ if (!overlay_crc) {
+ return Error(overlay_crc.GetError(), "failed to get zip CRC for '%s'",
+ overlay.GetPath().data());
}
- header->overlay_crc_ = *crc;
+ header->overlay_crc_ = *overlay_crc;
+
header->fulfilled_policies_ = fulfilled_policies;
header->enforce_overlayable_ = enforce_overlayable;
- header->target_path_ = target_apk_path;
- header->overlay_path_ = overlay_apk_path;
+ header->target_path_ = target.GetPath();
+ header->overlay_path_ = overlay.GetPath();
header->overlay_name_ = overlay_name;
- auto info = utils::ExtractOverlayManifestInfo(overlay_apk_path, overlay_name);
+ auto info = overlay.FindOverlayInfo(overlay_name);
if (!info) {
- return info.GetError();
+ return Error(info.GetError(), "failed to get overlay info for '%s'", overlay.GetPath().data());
}
LogInfo log_info;
- auto resource_mapping =
- ResourceMapping::FromApkAssets(target_apk_assets, overlay_apk_assets, *info,
- fulfilled_policies, enforce_overlayable, log_info);
+ auto resource_mapping = ResourceMapping::FromContainers(
+ target, overlay, *info, fulfilled_policies, enforce_overlayable, log_info);
if (!resource_mapping) {
- return resource_mapping.GetError();
+ return Error(resource_mapping.GetError(), "failed to generate resource map for '%s'",
+ overlay.GetPath().data());
}
auto idmap_data = IdmapData::FromResourceMapping(*resource_mapping);
diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
index 7e090a983f95..721612cc567b 100644
--- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
@@ -27,8 +27,6 @@
namespace android::idmap2 {
-#define RESID(pkg, type, entry) (((pkg) << 24) | ((type) << 16) | (entry))
-
#define TAB " "
void PrettyPrintVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) {
@@ -36,8 +34,8 @@ void PrettyPrintVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) {
void PrettyPrintVisitor::visit(const IdmapHeader& header) {
stream_ << "Paths:" << std::endl
- << TAB "target apk path : " << header.GetTargetPath() << std::endl
- << TAB "overlay apk path : " << header.GetOverlayPath() << std::endl;
+ << TAB "target path : " << header.GetTargetPath() << std::endl
+ << TAB "overlay path : " << header.GetOverlayPath() << std::endl;
if (!header.GetOverlayName().empty()) {
stream_ << "Overlay name: " << header.GetOverlayName() << std::endl;
@@ -53,14 +51,11 @@ void PrettyPrintVisitor::visit(const IdmapHeader& header) {
}
}
- if (auto target_apk_ = ApkAssets::Load(header.GetTargetPath())) {
- target_am_.SetApkAssets({target_apk_.get()});
- apk_assets_.push_back(std::move(target_apk_));
+ if (auto target = TargetResourceContainer::FromPath(header.GetTargetPath())) {
+ target_ = std::move(*target);
}
-
- if (auto overlay_apk = ApkAssets::Load(header.GetOverlayPath())) {
- overlay_am_.SetApkAssets({overlay_apk.get()});
- apk_assets_.push_back(std::move(overlay_apk));
+ if (auto overlay = OverlayResourceContainer::FromPath(header.GetOverlayPath())) {
+ overlay_ = std::move(*overlay);
}
stream_ << "Mapping:" << std::endl;
@@ -72,23 +67,20 @@ void PrettyPrintVisitor::visit(const IdmapData::Header& header ATTRIBUTE_UNUSED)
void PrettyPrintVisitor::visit(const IdmapData& data) {
static constexpr const char* kUnknownResourceName = "???";
- const bool target_package_loaded = !target_am_.GetApkAssets().empty();
- const bool overlay_package_loaded = !overlay_am_.GetApkAssets().empty();
-
const ResStringPool string_pool(data.GetStringPoolData().data(), data.GetStringPoolData().size());
const size_t string_pool_offset = data.GetHeader()->GetStringPoolIndexOffset();
for (const auto& target_entry : data.GetTargetEntries()) {
std::string target_name = kUnknownResourceName;
- if (target_package_loaded) {
- if (auto name = utils::ResToTypeEntryName(target_am_, target_entry.target_id)) {
+ if (target_ != nullptr) {
+ if (auto name = target_->GetResourceName(target_entry.target_id)) {
target_name = *name;
}
}
std::string overlay_name = kUnknownResourceName;
- if (overlay_package_loaded) {
- if (auto name = utils::ResToTypeEntryName(overlay_am_, target_entry.overlay_id)) {
+ if (overlay_ != nullptr) {
+ if (auto name = overlay_->GetResourceName(target_entry.overlay_id)) {
overlay_name = *name;
}
}
@@ -112,8 +104,8 @@ void PrettyPrintVisitor::visit(const IdmapData& data) {
}
std::string target_name = kUnknownResourceName;
- if (target_package_loaded) {
- if (auto name = utils::ResToTypeEntryName(target_am_, target_entry.target_id)) {
+ if (target_ != nullptr) {
+ if (auto name = target_->GetResourceName(target_entry.target_id)) {
target_name = *name;
}
}
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index b517aa3a0c01..a016a36a2e3d 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -18,16 +18,13 @@
#include <algorithm>
#include <cstdarg>
-#include <string>
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
-#include "androidfw/ApkAssets.h"
#include "idmap2/PolicyUtils.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
-using android::ApkAssets;
using android::idmap2::policy::PoliciesToDebugString;
namespace android::idmap2 {
@@ -48,27 +45,19 @@ void RawPrintVisitor::visit(const IdmapHeader& header) {
print(header.GetOverlayName(), true /* print_value */, "overlay name");
print(header.GetDebugInfo(), false /* print_value */, "debug info");
- auto target_apk_ = ApkAssets::Load(header.GetTargetPath());
- if (target_apk_) {
- target_am_.SetApkAssets({target_apk_.get()});
- apk_assets_.push_back(std::move(target_apk_));
+ if (auto target = TargetResourceContainer::FromPath(header.GetTargetPath())) {
+ target_ = std::move(*target);
}
-
- auto overlay_apk_ = ApkAssets::Load(header.GetOverlayPath());
- if (overlay_apk_) {
- overlay_am_.SetApkAssets({overlay_apk_.get()});
- apk_assets_.push_back(std::move(overlay_apk_));
+ if (auto overlay = OverlayResourceContainer::FromPath(header.GetOverlayPath())) {
+ overlay_ = std::move(*overlay);
}
}
void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
- const bool target_package_loaded = !target_am_.GetApkAssets().empty();
- const bool overlay_package_loaded = !overlay_am_.GetApkAssets().empty();
-
for (auto& target_entry : data.GetTargetEntries()) {
Result<std::string> target_name(Error(""));
- if (target_package_loaded) {
- target_name = utils::ResToTypeEntryName(target_am_, target_entry.target_id);
+ if (target_ != nullptr) {
+ target_name = target_->GetResourceName(target_entry.target_id);
}
if (target_name) {
print(target_entry.target_id, "target id: %s", target_name->c_str());
@@ -77,8 +66,8 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
}
Result<std::string> overlay_name(Error(""));
- if (overlay_package_loaded) {
- overlay_name = utils::ResToTypeEntryName(overlay_am_, target_entry.overlay_id);
+ if (overlay_ != nullptr) {
+ overlay_name = overlay_->GetResourceName(target_entry.overlay_id);
}
if (overlay_name) {
print(target_entry.overlay_id, "overlay id: %s", overlay_name->c_str());
@@ -89,8 +78,8 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
for (auto& target_entry : data.GetTargetInlineEntries()) {
Result<std::string> target_name(Error(""));
- if (target_package_loaded) {
- target_name = utils::ResToTypeEntryName(target_am_, target_entry.target_id);
+ if (target_ != nullptr) {
+ target_name = target_->GetResourceName(target_entry.target_id);
}
if (target_name) {
print(target_entry.target_id, "target id: %s", target_name->c_str());
@@ -104,10 +93,10 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
utils::DataTypeToString(target_entry.value.data_type).data());
Result<std::string> overlay_name(Error(""));
- if (overlay_package_loaded &&
+ if (overlay_ != nullptr &&
(target_entry.value.data_value == Res_value::TYPE_REFERENCE ||
target_entry.value.data_value == Res_value::TYPE_DYNAMIC_REFERENCE)) {
- overlay_name = utils::ResToTypeEntryName(overlay_am_, target_entry.value.data_value);
+ overlay_name = overlay_->GetResourceName(target_entry.value.data_value);
}
if (overlay_name) {
@@ -119,8 +108,8 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
for (auto& overlay_entry : data.GetOverlayEntries()) {
Result<std::string> overlay_name(Error(""));
- if (overlay_package_loaded) {
- overlay_name = utils::ResToTypeEntryName(overlay_am_, overlay_entry.overlay_id);
+ if (overlay_ != nullptr) {
+ overlay_name = overlay_->GetResourceName(overlay_entry.overlay_id);
}
if (overlay_name) {
@@ -130,8 +119,8 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
}
Result<std::string> target_name(Error(""));
- if (target_package_loaded) {
- target_name = utils::ResToTypeEntryName(target_am_, overlay_entry.target_id);
+ if (target_ != nullptr) {
+ target_name = target_->GetResourceName(overlay_entry.target_id);
}
if (target_name) {
@@ -145,9 +134,6 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
}
void RawPrintVisitor::visit(const IdmapData::Header& header) {
- print(header.GetTargetPackageId(), "target package id");
- print(header.GetOverlayPackageId(), "overlay package id");
- align();
print(header.GetTargetEntryCount(), "target entry count");
print(header.GetTargetInlineEntryCount(), "target inline entry count");
print(header.GetOverlayEntryCount(), "overlay entry count");
diff --git a/cmds/idmap2/libidmap2/ResourceContainer.cpp b/cmds/idmap2/libidmap2/ResourceContainer.cpp
new file mode 100644
index 000000000000..91cb43c216ef
--- /dev/null
+++ b/cmds/idmap2/libidmap2/ResourceContainer.cpp
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "idmap2/ResourceContainer.h"
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/Util.h"
+#include "idmap2/FabricatedOverlay.h"
+#include "idmap2/XmlParser.h"
+
+namespace android::idmap2 {
+namespace {
+#define REWRITE_PACKAGE(resid, package_id) \
+ (((resid)&0x00ffffffU) | (((uint32_t)(package_id)) << 24U))
+
+#define EXTRACT_PACKAGE(resid) ((0xff000000 & (resid)) >> 24)
+
+constexpr ResourceId kAttrName = 0x01010003;
+constexpr ResourceId kAttrResourcesMap = 0x01010609;
+constexpr ResourceId kAttrTargetName = 0x0101044d;
+constexpr ResourceId kAttrTargetPackage = 0x01010021;
+
+// idmap version 0x01 naively assumes that the package to use is always the first ResTable_package
+// in the resources.arsc blob. In most cases, there is only a single ResTable_package anyway, so
+// this assumption tends to work out. That said, the correct thing to do is to scan
+// resources.arsc for a package with a given name as read from the package manifest instead of
+// relying on a hard-coded index. This however requires storing the package name in the idmap
+// header, which in turn requires incrementing the idmap version. Because the initial version of
+// idmap2 is compatible with idmap, this will have to wait for now.
+const LoadedPackage* GetPackageAtIndex0(const LoadedArsc* loaded_arsc) {
+ const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+ if (packages.empty()) {
+ return nullptr;
+ }
+ return loaded_arsc->GetPackageById(packages[0]->GetPackageId());
+}
+
+Result<uint32_t> CalculateCrc(const ZipAssetsProvider* zip_assets) {
+ constexpr const char* kResourcesArsc = "resources.arsc";
+ std::optional<uint32_t> res_crc = zip_assets->GetCrc(kResourcesArsc);
+ if (!res_crc) {
+ return Error("failed to get CRC for '%s'", kResourcesArsc);
+ }
+
+ constexpr const char* kManifest = "AndroidManifest.xml";
+ std::optional<uint32_t> man_crc = zip_assets->GetCrc(kManifest);
+ if (!man_crc) {
+ return Error("failed to get CRC for '%s'", kManifest);
+ }
+
+ return *res_crc ^ *man_crc;
+}
+
+Result<XmlParser> OpenXmlParser(const std::string& entry_path, const ZipAssetsProvider* zip) {
+ auto manifest = zip->Open(entry_path);
+ if (manifest == nullptr) {
+ return Error("failed to find %s ", entry_path.c_str());
+ }
+
+ auto size = manifest->getLength();
+ auto buffer = manifest->getIncFsBuffer(true /* aligned */).convert<uint8_t>();
+ if (!buffer.verify(size)) {
+ return Error("failed to read entire %s", entry_path.c_str());
+ }
+
+ return XmlParser::Create(buffer.unsafe_ptr(), size, true /* copyData */);
+}
+
+Result<XmlParser> OpenXmlParser(ResourceId id, const ZipAssetsProvider* zip,
+ const AssetManager2* am) {
+ const auto ref_table = am->GetDynamicRefTableForCookie(0);
+ if (ref_table == nullptr) {
+ return Error("failed to find dynamic ref table for cookie 0");
+ }
+
+ ref_table->lookupResourceId(&id);
+ auto value = am->GetResource(id);
+ if (!value.has_value()) {
+ return Error("failed to find resource for id 0x%08x", id);
+ }
+
+ if (value->type != Res_value::TYPE_STRING) {
+ return Error("resource for is 0x%08x is not a file", id);
+ }
+
+ auto string_pool = am->GetStringPoolForCookie(value->cookie);
+ auto file = string_pool->string8ObjectAt(value->data);
+ if (!file.has_value()) {
+ return Error("failed to find string for index %d", value->data);
+ }
+
+ return OpenXmlParser(file->c_str(), zip);
+}
+
+Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const ZipAssetsProvider* zip,
+ const std::string& name) {
+ Result<XmlParser> xml = OpenXmlParser("AndroidManifest.xml", zip);
+ if (!xml) {
+ return xml.GetError();
+ }
+
+ auto manifest_it = xml->tree_iterator();
+ if (manifest_it->event() != XmlParser::Event::START_TAG || manifest_it->name() != "manifest") {
+ return Error("root element tag is not <manifest> in AndroidManifest.xml");
+ }
+
+ for (auto&& it : manifest_it) {
+ if (it.event() != XmlParser::Event::START_TAG || it.name() != "overlay") {
+ continue;
+ }
+
+ OverlayManifestInfo info{};
+ if (auto result_str = it.GetAttributeStringValue(kAttrName, "android:name")) {
+ if (*result_str != name) {
+ // A value for android:name was found, but either the name does not match the requested
+ // name, or an <overlay> tag with no name was requested.
+ continue;
+ }
+ info.name = *result_str;
+ } else if (!name.empty()) {
+ // This tag does not have a value for android:name, but an <overlay> tag with a specific name
+ // has been requested.
+ continue;
+ }
+
+ if (auto result_str = it.GetAttributeStringValue(kAttrTargetPackage, "android:targetPackage")) {
+ info.target_package = *result_str;
+ } else {
+ return Error("android:targetPackage missing from <overlay> in AndroidManifest.xml");
+ }
+
+ if (auto result_str = it.GetAttributeStringValue(kAttrTargetName, "android:targetName")) {
+ info.target_name = *result_str;
+ }
+
+ if (auto result_value = it.GetAttributeValue(kAttrResourcesMap, "android:resourcesMap")) {
+ if (utils::IsReference((*result_value).dataType)) {
+ info.resource_mapping = (*result_value).data;
+ } else {
+ return Error("android:resourcesMap is not a reference in AndroidManifest.xml");
+ }
+ }
+ return info;
+ }
+
+ return Error("<overlay> with android:name \"%s\" missing from AndroidManifest.xml", name.c_str());
+}
+
+Result<OverlayData> CreateResourceMapping(ResourceId id, const ZipAssetsProvider* zip,
+ const AssetManager2* overlay_am,
+ const LoadedArsc* overlay_arsc,
+ const LoadedPackage* overlay_package) {
+ auto parser = OpenXmlParser(id, zip, overlay_am);
+ if (!parser) {
+ return parser.GetError();
+ }
+
+ OverlayData overlay_data{};
+ const uint32_t string_pool_offset = overlay_arsc->GetStringPool()->size();
+ const uint8_t package_id = overlay_package->GetPackageId();
+ auto root_it = parser->tree_iterator();
+ if (root_it->event() != XmlParser::Event::START_TAG || root_it->name() != "overlay") {
+ return Error("root element is not <overlay> tag");
+ }
+
+ auto overlay_it_end = root_it.end();
+ for (auto overlay_it = root_it.begin(); overlay_it != overlay_it_end; ++overlay_it) {
+ if (overlay_it->event() == XmlParser::Event::BAD_DOCUMENT) {
+ return Error("failed to parse overlay xml document");
+ }
+
+ if (overlay_it->event() != XmlParser::Event::START_TAG) {
+ continue;
+ }
+
+ if (overlay_it->name() != "item") {
+ return Error("unexpected tag <%s> in <overlay>", overlay_it->name().c_str());
+ }
+
+ Result<std::string> target_resource = overlay_it->GetAttributeStringValue("target");
+ if (!target_resource) {
+ return Error(R"(<item> tag missing expected attribute "target")");
+ }
+
+ Result<android::Res_value> overlay_resource = overlay_it->GetAttributeValue("value");
+ if (!overlay_resource) {
+ return Error(R"(<item> tag missing expected attribute "value")");
+ }
+
+ if (overlay_resource->dataType == Res_value::TYPE_STRING) {
+ overlay_resource->data += string_pool_offset;
+ }
+
+ if (utils::IsReference(overlay_resource->dataType)) {
+ // Only rewrite resources defined within the overlay package to their corresponding target
+ // resource ids at runtime.
+ bool rewrite_id = package_id == EXTRACT_PACKAGE(overlay_resource->data);
+ overlay_data.pairs.emplace_back(OverlayData::Value{
+ *target_resource, OverlayData::ResourceIdValue{overlay_resource->data, rewrite_id}});
+ } else {
+ overlay_data.pairs.emplace_back(
+ OverlayData::Value{*target_resource, TargetValue{.data_type = overlay_resource->dataType,
+ .data_value = overlay_resource->data}});
+ }
+ }
+
+ const auto& string_pool = parser->get_strings();
+ const uint32_t string_pool_data_length = string_pool.bytes();
+ overlay_data.string_pool_data = OverlayData::InlineStringPoolData{
+ .data = std::unique_ptr<uint8_t[]>(new uint8_t[string_pool_data_length]),
+ .data_length = string_pool_data_length,
+ .string_pool_offset = string_pool_offset,
+ };
+
+ // Overlays should not be incrementally installed, so calling unsafe_ptr is fine here.
+ memcpy(overlay_data.string_pool_data->data.get(), string_pool.data().unsafe_ptr(),
+ string_pool_data_length);
+ return overlay_data;
+}
+
+OverlayData CreateResourceMappingLegacy(const AssetManager2* overlay_am,
+ const LoadedPackage* overlay_package) {
+ OverlayData overlay_data{};
+ for (const ResourceId overlay_resid : *overlay_package) {
+ if (auto name = utils::ResToTypeEntryName(*overlay_am, overlay_resid)) {
+ // Disable rewriting. Overlays did not support internal references before
+ // android:resourcesMap. Do not introduce new behavior.
+ overlay_data.pairs.emplace_back(OverlayData::Value{
+ *name, OverlayData::ResourceIdValue{overlay_resid, false /* rewrite_id */}});
+ }
+ }
+ return overlay_data;
+}
+
+struct ResState {
+ std::unique_ptr<ApkAssets> apk_assets;
+ const LoadedArsc* arsc;
+ const LoadedPackage* package;
+ std::unique_ptr<AssetManager2> am;
+ ZipAssetsProvider* zip_assets;
+
+ static Result<ResState> Initialize(std::unique_ptr<ZipAssetsProvider> zip) {
+ ResState state;
+ state.zip_assets = zip.get();
+ if ((state.apk_assets = ApkAssets::Load(std::move(zip))) == nullptr) {
+ return Error("failed to load apk asset");
+ }
+
+ if ((state.arsc = state.apk_assets->GetLoadedArsc()) == nullptr) {
+ return Error("failed to retrieve loaded arsc");
+ }
+
+ if ((state.package = GetPackageAtIndex0(state.arsc)) == nullptr) {
+ return Error("failed to retrieve loaded package at index 0");
+ }
+
+ state.am = std::make_unique<AssetManager2>();
+ if (!state.am->SetApkAssets({state.apk_assets.get()})) {
+ return Error("failed to create asset manager");
+ }
+
+ return state;
+ }
+};
+
+} // namespace
+
+struct ApkResourceContainer : public TargetResourceContainer, public OverlayResourceContainer {
+ static Result<std::unique_ptr<ApkResourceContainer>> FromPath(const std::string& path);
+
+ // inherited from TargetResourceContainer
+ Result<bool> DefinesOverlayable() const override;
+ Result<const android::OverlayableInfo*> GetOverlayableInfo(ResourceId id) const override;
+ Result<ResourceId> GetResourceId(const std::string& name) const override;
+
+ // inherited from OverlayResourceContainer
+ Result<OverlayData> GetOverlayData(const OverlayManifestInfo& info) const override;
+ Result<OverlayManifestInfo> FindOverlayInfo(const std::string& name) const override;
+
+ // inherited from ResourceContainer
+ Result<uint32_t> GetCrc() const override;
+ Result<std::string> GetResourceName(ResourceId id) const override;
+ const std::string& GetPath() const override;
+
+ ~ApkResourceContainer() override = default;
+
+ private:
+ ApkResourceContainer(std::unique_ptr<ZipAssetsProvider> zip_assets, std::string path);
+
+ Result<const ResState*> GetState() const;
+ ZipAssetsProvider* GetZipAssets() const;
+
+ mutable std::variant<std::unique_ptr<ZipAssetsProvider>, ResState> state_;
+ std::string path_;
+};
+
+ApkResourceContainer::ApkResourceContainer(std::unique_ptr<ZipAssetsProvider> zip_assets,
+ std::string path)
+ : state_(std::move(zip_assets)), path_(std::move(path)) {
+}
+
+Result<std::unique_ptr<ApkResourceContainer>> ApkResourceContainer::FromPath(
+ const std::string& path) {
+ auto zip_assets = ZipAssetsProvider::Create(path);
+ if (zip_assets == nullptr) {
+ return Error("failed to load zip assets");
+ }
+ return std::unique_ptr<ApkResourceContainer>(
+ new ApkResourceContainer(std::move(zip_assets), path));
+}
+
+Result<const ResState*> ApkResourceContainer::GetState() const {
+ if (auto state = std::get_if<ResState>(&state_); state != nullptr) {
+ return state;
+ }
+
+ auto state =
+ ResState::Initialize(std::move(std::get<std::unique_ptr<ZipAssetsProvider>>(state_)));
+ if (!state) {
+ return state.GetError();
+ }
+
+ state_ = std::move(*state);
+ return &std::get<ResState>(state_);
+}
+
+ZipAssetsProvider* ApkResourceContainer::GetZipAssets() const {
+ if (auto zip = std::get_if<std::unique_ptr<ZipAssetsProvider>>(&state_); zip != nullptr) {
+ return zip->get();
+ }
+ return std::get<ResState>(state_).zip_assets;
+}
+
+Result<bool> ApkResourceContainer::DefinesOverlayable() const {
+ auto state = GetState();
+ if (!state) {
+ return state.GetError();
+ }
+ return (*state)->package->DefinesOverlayable();
+}
+
+Result<const android::OverlayableInfo*> ApkResourceContainer::GetOverlayableInfo(
+ ResourceId id) const {
+ auto state = GetState();
+ if (!state) {
+ return state.GetError();
+ }
+ return (*state)->package->GetOverlayableInfo(id);
+}
+
+Result<OverlayManifestInfo> ApkResourceContainer::FindOverlayInfo(const std::string& name) const {
+ return ExtractOverlayManifestInfo(GetZipAssets(), name);
+}
+
+Result<OverlayData> ApkResourceContainer::GetOverlayData(const OverlayManifestInfo& info) const {
+ const auto state = GetState();
+ if (!state) {
+ return state.GetError();
+ }
+
+ if (info.resource_mapping != 0) {
+ return CreateResourceMapping(info.resource_mapping, GetZipAssets(), (*state)->am.get(),
+ (*state)->arsc, (*state)->package);
+ }
+ return CreateResourceMappingLegacy((*state)->am.get(), (*state)->package);
+}
+
+Result<uint32_t> ApkResourceContainer::GetCrc() const {
+ return CalculateCrc(GetZipAssets());
+}
+
+const std::string& ApkResourceContainer::GetPath() const {
+ return path_;
+}
+
+Result<ResourceId> ApkResourceContainer::GetResourceId(const std::string& name) const {
+ auto state = GetState();
+ if (!state) {
+ return state.GetError();
+ }
+ auto id = (*state)->am->GetResourceId(name, "", (*state)->package->GetPackageName());
+ if (!id.has_value()) {
+ return Error("failed to find resource '%s'", name.c_str());
+ }
+
+ // Retrieve the compile-time resource id of the target resource.
+ return REWRITE_PACKAGE(*id, (*state)->package->GetPackageId());
+}
+
+Result<std::string> ApkResourceContainer::GetResourceName(ResourceId id) const {
+ auto state = GetState();
+ if (!state) {
+ return state.GetError();
+ }
+ return utils::ResToTypeEntryName(*(*state)->am, id);
+}
+
+Result<std::unique_ptr<TargetResourceContainer>> TargetResourceContainer::FromPath(
+ std::string path) {
+ auto result = ApkResourceContainer::FromPath(path);
+ if (!result) {
+ return result.GetError();
+ }
+ return std::unique_ptr<TargetResourceContainer>(result->release());
+}
+
+Result<std::unique_ptr<OverlayResourceContainer>> OverlayResourceContainer::FromPath(
+ std::string path) {
+ // Load the path as a fabricated overlay if the file magic indicates this is a fabricated overlay.
+ if (android::IsFabricatedOverlay(path)) {
+ auto result = FabricatedOverlayContainer::FromPath(path);
+ if (!result) {
+ return result.GetError();
+ }
+ return std::unique_ptr<OverlayResourceContainer>(result->release());
+ }
+
+ // Fallback to loading the container as an APK.
+ auto result = ApkResourceContainer::FromPath(path);
+ if (!result) {
+ return result.GetError();
+ }
+ return std::unique_ptr<OverlayResourceContainer>(result->release());
+}
+
+} // namespace android::idmap2 \ No newline at end of file
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 46eeb8e6ac80..3bbbf248c87d 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -30,19 +30,12 @@
using android::base::StringPrintf;
using android::idmap2::utils::BitmaskToPolicies;
-using android::idmap2::utils::IsReference;
-using android::idmap2::utils::ResToTypeEntryName;
using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
namespace android::idmap2 {
namespace {
-
-#define REWRITE_PACKAGE(resid, package_id) \
- (((resid)&0x00ffffffU) | (((uint32_t)(package_id)) << 24U))
-#define EXTRACT_PACKAGE(resid) ((0xff000000 & (resid)) >> 24)
-
std::string ConcatPolicies(const std::vector<std::string>& policies) {
std::string message;
for (const std::string& policy : policies) {
@@ -55,11 +48,11 @@ std::string ConcatPolicies(const std::vector<std::string>& policies) {
return message;
}
-Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
+Result<Unit> CheckOverlayable(const TargetResourceContainer& target,
const OverlayManifestInfo& overlay_info,
const PolicyBitmask& fulfilled_policies,
const ResourceId& target_resource) {
- static constexpr const PolicyBitmask sDefaultPolicies =
+ constexpr const PolicyBitmask kDefaultPolicies =
PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION |
PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE |
PolicyFlags::CONFIG_SIGNATURE;
@@ -68,8 +61,13 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
// the overlay is preinstalled, signed with the same signature as the target or signed with the
// same signature as reference package defined in SystemConfig under 'overlay-config-signature'
// tag.
- if (!target_package.DefinesOverlayable()) {
- return (sDefaultPolicies & fulfilled_policies) != 0
+ const Result<bool> defines_overlayable = target.DefinesOverlayable();
+ if (!defines_overlayable) {
+ return Error(defines_overlayable.GetError(), "unable to retrieve overlayable info");
+ }
+
+ if (!*defines_overlayable) {
+ return (kDefaultPolicies & fulfilled_policies) != 0
? Result<Unit>({})
: Error(
"overlay must be preinstalled, signed with the same signature as the target,"
@@ -77,317 +75,92 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
" <overlay-config-signature>.");
}
- const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(target_resource);
- if (overlayable_info == nullptr) {
+ const auto overlayable_info = target.GetOverlayableInfo(target_resource);
+ if (!overlayable_info) {
+ return overlayable_info.GetError();
+ }
+
+ if (*overlayable_info == nullptr) {
// Do not allow non-overlayable resources to be overlaid.
return Error("target resource has no overlayable declaration");
}
- if (overlay_info.target_name != overlayable_info->name) {
+ if (overlay_info.target_name != (*overlayable_info)->name) {
// If the overlay supplies a target overlayable name, the resource must belong to the
// overlayable defined with the specified name to be overlaid.
return Error(R"(<overlay> android:targetName "%s" does not match overlayable name "%s")",
- overlay_info.target_name.c_str(), overlayable_info->name.c_str());
+ overlay_info.target_name.c_str(), (*overlayable_info)->name.c_str());
}
// Enforce policy restrictions if the resource is declared as overlayable.
- if ((overlayable_info->policy_flags & fulfilled_policies) == 0) {
+ if (((*overlayable_info)->policy_flags & fulfilled_policies) == 0) {
return Error(R"(overlay with policies "%s" does not fulfill any overlayable policies "%s")",
ConcatPolicies(BitmaskToPolicies(fulfilled_policies)).c_str(),
- ConcatPolicies(BitmaskToPolicies(overlayable_info->policy_flags)).c_str());
+ ConcatPolicies(BitmaskToPolicies((*overlayable_info)->policy_flags)).c_str());
}
return Result<Unit>({});
}
-// TODO(martenkongstad): scan for package name instead of assuming package at index 0
-//
-// idmap version 0x01 naively assumes that the package to use is always the first ResTable_package
-// in the resources.arsc blob. In most cases, there is only a single ResTable_package anyway, so
-// this assumption tends to work out. That said, the correct thing to do is to scan
-// resources.arsc for a package with a given name as read from the package manifest instead of
-// relying on a hard-coded index. This however requires storing the package name in the idmap
-// header, which in turn requires incrementing the idmap version. Because the initial version of
-// idmap2 is compatible with idmap, this will have to wait for now.
-const LoadedPackage* GetPackageAtIndex0(const LoadedArsc& loaded_arsc) {
- const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc.GetPackages();
- if (packages.empty()) {
- return nullptr;
- }
- int id = packages[0]->GetPackageId();
- return loaded_arsc.GetPackageById(id);
-}
-
-Result<std::unique_ptr<Asset>> OpenNonAssetFromResource(const ResourceId& resource_id,
- const AssetManager2& asset_manager) {
- auto value = asset_manager.GetResource(resource_id);
- if (!value.has_value()) {
- return Error("failed to find resource for id 0x%08x", resource_id);
- }
-
- if (value->type != Res_value::TYPE_STRING) {
- return Error("resource for is 0x%08x is not a file", resource_id);
- }
-
- auto string_pool = asset_manager.GetStringPoolForCookie(value->cookie);
- auto file = string_pool->string8ObjectAt(value->data);
- if (!file.has_value()) {
- return Error("failed to find string for index %d", value->data);
+std::string GetDebugResourceName(const ResourceContainer& container, ResourceId resid) {
+ auto name = container.GetResourceName(resid);
+ if (name) {
+ return *name;
}
-
- // Load the overlay resource mappings from the file specified using android:resourcesMap.
- auto asset = asset_manager.OpenNonAsset(file->c_str(), Asset::AccessMode::ACCESS_BUFFER);
- if (asset == nullptr) {
- return Error("file \"%s\" not found", file->c_str());
- }
-
- return asset;
+ return StringPrintf("0x%08x", resid);
}
-
} // namespace
-Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManager2* target_am,
- const LoadedPackage* target_package,
- const LoadedPackage* overlay_package,
- size_t string_pool_offset,
- const XmlParser& overlay_parser,
- LogInfo& log_info) {
- ResourceMapping resource_mapping;
- auto root_it = overlay_parser.tree_iterator();
- if (root_it->event() != XmlParser::Event::START_TAG || root_it->name() != "overlay") {
- return Error("root element is not <overlay> tag");
- }
-
- const uint8_t target_package_id = target_package->GetPackageId();
- const uint8_t overlay_package_id = overlay_package->GetPackageId();
- auto overlay_it_end = root_it.end();
- for (auto overlay_it = root_it.begin(); overlay_it != overlay_it_end; ++overlay_it) {
- if (overlay_it->event() == XmlParser::Event::BAD_DOCUMENT) {
- return Error("failed to parse overlay xml document");
- }
-
- if (overlay_it->event() != XmlParser::Event::START_TAG) {
- continue;
- }
-
- if (overlay_it->name() != "item") {
- return Error("unexpected tag <%s> in <overlay>", overlay_it->name().c_str());
- }
-
- Result<std::string> target_resource = overlay_it->GetAttributeStringValue("target");
- if (!target_resource) {
- return Error(R"(<item> tag missing expected attribute "target")");
- }
-
- Result<android::Res_value> overlay_resource = overlay_it->GetAttributeValue("value");
- if (!overlay_resource) {
- return Error(R"(<item> tag missing expected attribute "value")");
- }
-
- auto target_id_result =
- target_am->GetResourceId(*target_resource, "", target_package->GetPackageName());
- if (!target_id_result.has_value()) {
- log_info.Warning(LogMessage() << "failed to find resource \"" << *target_resource
- << "\" in target resources");
+Result<ResourceMapping> ResourceMapping::FromContainers(const TargetResourceContainer& target,
+ const OverlayResourceContainer& overlay,
+ const OverlayManifestInfo& overlay_info,
+ const PolicyBitmask& fulfilled_policies,
+ bool enforce_overlayable,
+ LogInfo& log_info) {
+ auto overlay_data = overlay.GetOverlayData(overlay_info);
+ if (!overlay_data) {
+ return overlay_data.GetError();
+ }
+
+ ResourceMapping mapping;
+ for (const auto& overlay_pair : overlay_data->pairs) {
+ const auto target_resid = target.GetResourceId(overlay_pair.resource_name);
+ if (!target_resid) {
+ log_info.Warning(LogMessage() << target_resid.GetErrorMessage());
continue;
}
- // Retrieve the compile-time resource id of the target resource.
- uint32_t target_id = REWRITE_PACKAGE(*target_id_result, target_package_id);
-
- if (overlay_resource->dataType == Res_value::TYPE_STRING) {
- overlay_resource->data += string_pool_offset;
- }
-
- if (IsReference(overlay_resource->dataType)) {
- // Only rewrite resources defined within the overlay package to their corresponding target
- // resource ids at runtime.
- bool rewrite_reference = overlay_package_id == EXTRACT_PACKAGE(overlay_resource->data);
- resource_mapping.AddMapping(target_id, overlay_resource->data, rewrite_reference);
- } else {
- resource_mapping.AddMapping(target_id, overlay_resource->dataType, overlay_resource->data);
- }
- }
-
- return resource_mapping;
-}
-
-Result<ResourceMapping> ResourceMapping::CreateResourceMappingLegacy(
- const AssetManager2* target_am, const AssetManager2* overlay_am,
- const LoadedPackage* target_package, const LoadedPackage* overlay_package, LogInfo& log_info) {
- ResourceMapping resource_mapping;
- const uint8_t target_package_id = target_package->GetPackageId();
- const auto end = overlay_package->end();
- for (auto iter = overlay_package->begin(); iter != end; ++iter) {
- const ResourceId overlay_resid = *iter;
- Result<std::string> name = utils::ResToTypeEntryName(*overlay_am, overlay_resid);
- if (!name) {
- continue;
+ if (enforce_overlayable) {
+ // Filter out resources the overlay is not allowed to override.
+ auto overlayable = CheckOverlayable(target, overlay_info, fulfilled_policies, *target_resid);
+ if (!overlayable) {
+ log_info.Warning(LogMessage() << "overlay '" << overlay.GetPath()
+ << "' is not allowed to overlay resource '"
+ << GetDebugResourceName(target, *target_resid)
+ << "' in target: " << overlayable.GetErrorMessage());
+ continue;
+ }
}
- // Find the resource with the same type and entry name within the target package.
- const std::string full_name =
- base::StringPrintf("%s:%s", target_package->GetPackageName().c_str(), name->c_str());
- auto target_resource_result = target_am->GetResourceId(full_name);
- if (!target_resource_result.has_value()) {
- log_info.Warning(LogMessage()
- << "failed to find resource \"" << full_name << "\" in target resources");
- continue;
+ if (auto result = mapping.AddMapping(*target_resid, overlay_pair.value); !result) {
+ return Error(result.GetError(), "failed to add mapping for '%s'",
+ GetDebugResourceName(target, *target_resid).c_str());
}
-
- // Retrieve the compile-time resource id of the target resource.
- ResourceId target_resource = REWRITE_PACKAGE(*target_resource_result, target_package_id);
- resource_mapping.AddMapping(target_resource, overlay_resid,
- false /* rewrite_overlay_reference */);
}
- return resource_mapping;
-}
-
-void ResourceMapping::FilterOverlayableResources(const AssetManager2* target_am,
- const LoadedPackage* target_package,
- const LoadedPackage* overlay_package,
- const OverlayManifestInfo& overlay_info,
- const PolicyBitmask& fulfilled_policies,
- LogInfo& log_info) {
- std::set<ResourceId> remove_ids;
- for (const auto& target_map : target_map_) {
- const ResourceId target_resid = target_map.first;
- Result<Unit> success =
- CheckOverlayable(*target_package, overlay_info, fulfilled_policies, target_resid);
- if (success) {
- continue;
- }
-
- // Attempting to overlay a resource that is not allowed to be overlaid is treated as a
- // warning.
- Result<std::string> name = utils::ResToTypeEntryName(*target_am, target_resid);
- if (!name) {
- name = StringPrintf("0x%08x", target_resid);
- }
-
- log_info.Warning(LogMessage() << "overlay \"" << overlay_package->GetPackageName()
- << "\" is not allowed to overlay resource \"" << *name
- << "\" in target: " << success.GetErrorMessage());
-
- remove_ids.insert(target_resid);
+ auto& string_pool_data = overlay_data->string_pool_data;
+ if (string_pool_data.has_value()) {
+ mapping.string_pool_offset_ = string_pool_data->string_pool_offset;
+ mapping.string_pool_data_ = std::move(string_pool_data->data);
+ mapping.string_pool_data_length_ = string_pool_data->data_length;
}
- for (const ResourceId target_resid : remove_ids) {
- RemoveMapping(target_resid);
- }
+ return std::move(mapping);
}
-Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_apk_assets,
- const ApkAssets& overlay_apk_assets,
- const OverlayManifestInfo& overlay_info,
- const PolicyBitmask& fulfilled_policies,
- bool enforce_overlayable,
- LogInfo& log_info) {
- AssetManager2 target_asset_manager;
- if (!target_asset_manager.SetApkAssets({&target_apk_assets})) {
- return Error("failed to create target asset manager");
- }
-
- AssetManager2 overlay_asset_manager;
- if (!overlay_asset_manager.SetApkAssets({&overlay_apk_assets})) {
- return Error("failed to create overlay asset manager");
- }
-
- const LoadedArsc* target_arsc = target_apk_assets.GetLoadedArsc();
- if (target_arsc == nullptr) {
- return Error("failed to load target resources.arsc");
- }
-
- const LoadedArsc* overlay_arsc = overlay_apk_assets.GetLoadedArsc();
- if (overlay_arsc == nullptr) {
- return Error("failed to load overlay resources.arsc");
- }
-
- const LoadedPackage* target_pkg = GetPackageAtIndex0(*target_arsc);
- if (target_pkg == nullptr) {
- return Error("failed to load target package from resources.arsc");
- }
-
- const LoadedPackage* overlay_pkg = GetPackageAtIndex0(*overlay_arsc);
- if (overlay_pkg == nullptr) {
- return Error("failed to load overlay package from resources.arsc");
- }
-
- size_t string_pool_data_length = 0U;
- size_t string_pool_offset = 0U;
- std::unique_ptr<uint8_t[]> string_pool_data;
- Result<ResourceMapping> resource_mapping = {{}};
- if (overlay_info.resource_mapping != 0U) {
- // Use the dynamic reference table to find the assigned resource id of the map xml.
- const auto& ref_table = overlay_asset_manager.GetDynamicRefTableForCookie(0);
- uint32_t resource_mapping_id = overlay_info.resource_mapping;
- ref_table->lookupResourceId(&resource_mapping_id);
-
- // Load the overlay resource mappings from the file specified using android:resourcesMap.
- auto asset = OpenNonAssetFromResource(resource_mapping_id, overlay_asset_manager);
- if (!asset) {
- return Error("failed opening xml for android:resourcesMap: %s",
- asset.GetErrorMessage().c_str());
- }
-
- auto parser =
- XmlParser::Create((*asset)->getBuffer(true /* wordAligned*/), (*asset)->getLength());
- if (!parser) {
- return Error("failed opening ResXMLTree");
- }
-
- // Copy the xml string pool data before the parse goes out of scope.
- auto& string_pool = (*parser)->get_strings();
- string_pool_data_length = string_pool.bytes();
- string_pool_data.reset(new uint8_t[string_pool_data_length]);
-
- // Overlays should not be incrementally installed, so calling unsafe_ptr is fine here.
- memcpy(string_pool_data.get(), string_pool.data().unsafe_ptr(), string_pool_data_length);
-
- // Offset string indices by the size of the overlay resource table string pool.
- string_pool_offset = overlay_arsc->GetStringPool()->size();
-
- resource_mapping = CreateResourceMapping(&target_asset_manager, target_pkg, overlay_pkg,
- string_pool_offset, *(*parser), log_info);
- } else {
- // If no file is specified using android:resourcesMap, it is assumed that the overlay only
- // defines resources intended to override target resources of the same type and name.
- resource_mapping = CreateResourceMappingLegacy(&target_asset_manager, &overlay_asset_manager,
- target_pkg, overlay_pkg, log_info);
- }
-
- if (!resource_mapping) {
- return resource_mapping.GetError();
- }
-
- if (enforce_overlayable) {
- // Filter out resources the overlay is not allowed to override.
- (*resource_mapping)
- .FilterOverlayableResources(&target_asset_manager, target_pkg, overlay_pkg, overlay_info,
- fulfilled_policies, log_info);
- }
-
- resource_mapping->target_package_id_ = target_pkg->GetPackageId();
- resource_mapping->overlay_package_id_ = overlay_pkg->GetPackageId();
- resource_mapping->string_pool_offset_ = string_pool_offset;
- resource_mapping->string_pool_data_ = std::move(string_pool_data);
- resource_mapping->string_pool_data_length_ = string_pool_data_length;
- return std::move(*resource_mapping);
-}
-
-OverlayResourceMap ResourceMapping::GetOverlayToTargetMap() const {
- // An overlay resource can override multiple target resources at once. Rewrite the overlay
- // resource as the first target resource it overrides.
- OverlayResourceMap map;
- for (const auto& mappings : overlay_map_) {
- map.insert(std::make_pair(mappings.first, mappings.second));
- }
- return map;
-}
-
-Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource, ResourceId overlay_resource,
- bool rewrite_overlay_reference) {
+Result<Unit> ResourceMapping::AddMapping(
+ ResourceId target_resource,
+ const std::variant<OverlayData::ResourceIdValue, TargetValue>& value) {
if (target_map_.find(target_resource) != target_map_.end()) {
return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
}
@@ -395,49 +168,19 @@ Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource, ResourceId
// TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
// runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
- target_map_.insert(std::make_pair(target_resource, overlay_resource));
-
- if (rewrite_overlay_reference) {
- overlay_map_.insert(std::make_pair(overlay_resource, target_resource));
- }
- return Unit{};
-}
-
-Result<Unit> ResourceMapping::AddMapping(ResourceId target_resource,
- TargetValue::DataType data_type,
- TargetValue::DataValue data_value) {
- if (target_map_.find(target_resource) != target_map_.end()) {
- return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
+ if (auto overlay_resource = std::get_if<OverlayData::ResourceIdValue>(&value)) {
+ target_map_.insert(std::make_pair(target_resource, overlay_resource->overlay_id));
+ if (overlay_resource->rewrite_id) {
+ // An overlay resource can override multiple target resources at once. Rewrite the overlay
+ // resource as the first target resource it overrides.
+ overlay_map_.insert(std::make_pair(overlay_resource->overlay_id, target_resource));
+ }
+ } else {
+ auto overlay_value = std::get<TargetValue>(value);
+ target_map_.insert(std::make_pair(target_resource, overlay_value));
}
- // TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
- // runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
-
- target_map_.insert(std::make_pair(target_resource, TargetValue{data_type, data_value}));
return Unit{};
}
-void ResourceMapping::RemoveMapping(ResourceId target_resource) {
- auto target_iter = target_map_.find(target_resource);
- if (target_iter == target_map_.end()) {
- return;
- }
-
- const auto value = target_iter->second;
- target_map_.erase(target_iter);
-
- const ResourceId* overlay_resource = std::get_if<ResourceId>(&value);
- if (overlay_resource == nullptr) {
- return;
- }
-
- auto overlay_iter = overlay_map_.equal_range(*overlay_resource);
- for (auto i = overlay_iter.first; i != overlay_iter.second; ++i) {
- if (i->second == target_resource) {
- overlay_map_.erase(i);
- return;
- }
- }
-}
-
} // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index 4e85e5751300..e809bf1f4b02 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -17,27 +17,16 @@
#include "idmap2/ResourceUtils.h"
#include <memory>
-#include <string>
#include "androidfw/StringPiece.h"
#include "androidfw/Util.h"
#include "idmap2/Result.h"
-#include "idmap2/XmlParser.h"
-#include "idmap2/ZipFile.h"
using android::StringPiece16;
using android::idmap2::Result;
-using android::idmap2::XmlParser;
-using android::idmap2::ZipFile;
using android::util::Utf16ToUtf8;
namespace android::idmap2::utils {
-namespace {
-constexpr ResourceId kAttrName = 0x01010003;
-constexpr ResourceId kAttrResourcesMap = 0x01010609;
-constexpr ResourceId kAttrTargetName = 0x0101044d;
-constexpr ResourceId kAttrTargetPackage = 0x01010021;
-} // namespace
bool IsReference(uint8_t data_type) {
return data_type == Res_value::TYPE_REFERENCE || data_type == Res_value::TYPE_DYNAMIC_REFERENCE;
@@ -97,71 +86,4 @@ Result<std::string> ResToTypeEntryName(const AssetManager2& am, uint32_t resid)
return out;
}
-Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
- const std::string& name) {
- std::unique_ptr<const ZipFile> zip = ZipFile::Open(path);
- if (!zip) {
- return Error("failed to open %s as a zip file", path.c_str());
- }
-
- std::unique_ptr<const MemoryChunk> entry = zip->Uncompress("AndroidManifest.xml");
- if (!entry) {
- return Error("failed to uncompress AndroidManifest.xml from %s", path.c_str());
- }
-
- Result<std::unique_ptr<const XmlParser>> xml = XmlParser::Create(entry->buf, entry->size);
- if (!xml) {
- return Error("failed to parse AndroidManifest.xml from %s", path.c_str());
- }
-
- auto manifest_it = (*xml)->tree_iterator();
- if (manifest_it->event() != XmlParser::Event::START_TAG || manifest_it->name() != "manifest") {
- return Error("root element tag is not <manifest> in AndroidManifest.xml of %s", path.c_str());
- }
-
- for (auto&& it : manifest_it) {
- if (it.event() != XmlParser::Event::START_TAG || it.name() != "overlay") {
- continue;
- }
-
- OverlayManifestInfo info{};
- if (auto result_str = it.GetAttributeStringValue(kAttrName, "android:name")) {
- if (*result_str != name) {
- // A value for android:name was found, but either a the name does not match the requested
- // name, or an <overlay> tag with no name was requested.
- continue;
- }
- info.name = *result_str;
- } else if (!name.empty()) {
- // This tag does not have a value for android:name, but an <overlay> tag with a specific name
- // has been requested.
- continue;
- }
-
- if (auto result_str = it.GetAttributeStringValue(kAttrTargetPackage, "android:targetPackage")) {
- info.target_package = *result_str;
- } else {
- return Error("android:targetPackage missing from <overlay> of %s: %s", path.c_str(),
- result_str.GetErrorMessage().c_str());
- }
-
- if (auto result_str = it.GetAttributeStringValue(kAttrTargetName, "android:targetName")) {
- info.target_name = *result_str;
- }
-
- if (auto result_value = it.GetAttributeValue(kAttrResourcesMap, "android:resourcesMap")) {
- if (IsReference((*result_value).dataType)) {
- info.resource_mapping = (*result_value).data;
- } else {
- return Error("android:resourcesMap is not a reference in AndroidManifest.xml of %s",
- path.c_str());
- }
- }
- return info;
- }
-
- return Error("<overlay> with android:name \"%s\" missing from AndroidManifest.xml of %s",
- name.c_str(), path.c_str());
-}
-
} // namespace android::idmap2::utils
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 00baea46f909..70822c890288 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -151,16 +151,18 @@ Result<std::string> XmlParser::Node::GetAttributeStringValue(const std::string&
return value ? GetStringValue(parser_, *value, name) : value.GetError();
}
-Result<std::unique_ptr<const XmlParser>> XmlParser::Create(const void* data, size_t size,
- bool copy_data) {
- auto parser = std::unique_ptr<const XmlParser>(new XmlParser());
- if (parser->tree_.setTo(data, size, copy_data) != NO_ERROR) {
+XmlParser::XmlParser(std::unique_ptr<ResXMLTree> tree) : tree_(std::move(tree)) {
+}
+
+Result<XmlParser> XmlParser::Create(const void* data, size_t size, bool copy_data) {
+ auto tree = std::make_unique<ResXMLTree>();
+ if (tree->setTo(data, size, copy_data) != NO_ERROR) {
return Error("Malformed xml block");
}
// Find the beginning of the first tag.
XmlParser::Event event;
- while ((event = parser->tree_.next()) != XmlParser::Event::BAD_DOCUMENT &&
+ while ((event = tree->next()) != XmlParser::Event::BAD_DOCUMENT &&
event != XmlParser::Event::END_DOCUMENT && event != XmlParser::Event::START_TAG) {
}
@@ -172,11 +174,7 @@ Result<std::unique_ptr<const XmlParser>> XmlParser::Create(const void* data, siz
return Error("Bad xml document");
}
- return parser;
-}
-
-XmlParser::~XmlParser() {
- tree_.uninit();
+ return XmlParser{std::move(tree)};
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/ZipFile.cpp b/cmds/idmap2/libidmap2/ZipFile.cpp
deleted file mode 100644
index 1e1a218163f0..000000000000
--- a/cmds/idmap2/libidmap2/ZipFile.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "idmap2/ZipFile.h"
-
-#include <memory>
-#include <string>
-
-#include "idmap2/Result.h"
-
-namespace android::idmap2 {
-
-std::unique_ptr<MemoryChunk> MemoryChunk::Allocate(size_t size) {
- void* ptr = ::operator new(sizeof(MemoryChunk) + size);
- std::unique_ptr<MemoryChunk> chunk(reinterpret_cast<MemoryChunk*>(ptr));
- chunk->size = size;
- return chunk;
-}
-
-std::unique_ptr<const ZipFile> ZipFile::Open(const std::string& path) {
- ::ZipArchiveHandle handle;
- int32_t status = ::OpenArchive(path.c_str(), &handle);
- if (status != 0) {
- ::CloseArchive(handle);
- return nullptr;
- }
- return std::unique_ptr<ZipFile>(new ZipFile(handle));
-}
-
-ZipFile::~ZipFile() {
- ::CloseArchive(handle_);
-}
-
-std::unique_ptr<const MemoryChunk> ZipFile::Uncompress(const std::string& entryPath) const {
- ::ZipEntry entry;
- int32_t status = ::FindEntry(handle_, entryPath, &entry);
- if (status != 0) {
- return nullptr;
- }
- std::unique_ptr<MemoryChunk> chunk = MemoryChunk::Allocate(entry.uncompressed_length);
- status = ::ExtractToMemory(handle_, &entry, chunk->buf, chunk->size);
- if (status != 0) {
- return nullptr;
- }
- return chunk;
-}
-
-Result<uint32_t> ZipFile::Crc(const std::string& entryPath) const {
- ::ZipEntry entry;
- int32_t status = ::FindEntry(handle_, entryPath, &entry);
- if (status != 0) {
- return Error("failed to find zip entry %s", entryPath.c_str());
- }
- return entry.crc32;
-}
-
-} // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/proto/fabricated_v1.proto b/cmds/idmap2/libidmap2/proto/fabricated_v1.proto
new file mode 100644
index 000000000000..a392b2b6d856
--- /dev/null
+++ b/cmds/idmap2/libidmap2/proto/fabricated_v1.proto
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+syntax = "proto3";
+
+package android.idmap2.pb;
+
+option optimize_for = LITE_RUNTIME;
+
+// All changes to the proto messages in this file MUST be backwards compatible. Backwards
+// incompatible changes will cause previously fabricated overlays to be considered corrupt by the
+// new proto message specification.
+message FabricatedOverlay {
+ repeated ResourcePackage packages = 1;
+ string name = 2;
+ string package_name = 3;
+ string target_package_name = 4;
+ string target_overlayable = 5;
+}
+
+message ResourcePackage {
+ string name = 1;
+ repeated ResourceType types = 2;
+}
+
+message ResourceType {
+ string name = 1;
+ repeated ResourceEntry entries = 2;
+}
+
+message ResourceEntry {
+ string name = 1;
+ oneof value {
+ ResourceValue res_value = 2;
+ }
+}
+
+message ResourceValue {
+ // Corresponds with android::Res_value::dataType
+ uint32 data_type = 1;
+ // Corresponds with android::Res_value::data
+ uint32 data_value = 2;
+} \ No newline at end of file
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 524aabcec652..bf6332742787 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -33,7 +33,7 @@ using ::testing::NotNull;
namespace android::idmap2 {
TEST(BinaryStreamVisitorTests, CreateBinaryStreamViaBinaryStreamVisitor) {
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
std::istringstream raw_stream(raw);
auto result1 = Idmap::FromBinaryStream(raw_stream);
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
new file mode 100644
index 000000000000..79ab2438af74
--- /dev/null
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+#include <idmap2/FabricatedOverlay.h>
+
+#include <fstream>
+
+namespace android::idmap2 {
+
+TEST(FabricatedOverlayTests, OverlayInfo) {
+ auto overlay =
+ FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+ .SetOverlayable("TestResources")
+ .Build();
+
+ ASSERT_TRUE(overlay);
+ auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay));
+ auto info = container->FindOverlayInfo("SandTheme");
+ ASSERT_TRUE(info);
+ EXPECT_EQ("SandTheme", (*info).name);
+ EXPECT_EQ("TestResources", (*info).target_name);
+
+ info = container->FindOverlayInfo("OceanTheme");
+ ASSERT_FALSE(info);
+}
+
+TEST(FabricatedOverlayTests, SetResourceValue) {
+ auto overlay =
+ FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+ .SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U)
+ .SetResourceValue("com.example.target.split:integer/int2", Res_value::TYPE_INT_DEC, 2U)
+ .SetResourceValue("string/int3", Res_value::TYPE_REFERENCE, 0x7f010000)
+ .Build();
+ ASSERT_TRUE(overlay);
+ auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay));
+ auto info = container->FindOverlayInfo("SandTheme");
+ ASSERT_TRUE(info);
+ ASSERT_TRUE((*info).target_name.empty());
+
+ auto crc = (*container).GetCrc();
+ ASSERT_TRUE(crc) << crc.GetErrorMessage();
+ EXPECT_NE(0U, *crc);
+
+ auto pairs = container->GetOverlayData(*info);
+ ASSERT_TRUE(pairs);
+ EXPECT_FALSE(pairs->string_pool_data.has_value());
+ ASSERT_EQ(3U, pairs->pairs.size());
+
+ auto& it = pairs->pairs[0];
+ ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
+ auto entry = std::get_if<TargetValue>(&it.value);
+ ASSERT_NE(nullptr, entry);
+ ASSERT_EQ(1U, entry->data_value);
+ ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+
+ it = pairs->pairs[1];
+ ASSERT_EQ("com.example.target:string/int3", it.resource_name);
+ entry = std::get_if<TargetValue>(&it.value);
+ ASSERT_NE(nullptr, entry);
+ ASSERT_EQ(0x7f010000, entry->data_value);
+ ASSERT_EQ(Res_value::TYPE_REFERENCE, entry->data_type);
+
+ it = pairs->pairs[2];
+ ASSERT_EQ("com.example.target.split:integer/int2", it.resource_name);
+ entry = std::get_if<TargetValue>(&it.value);
+ ASSERT_NE(nullptr, entry);
+ ASSERT_EQ(2U, entry->data_value);
+ ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+}
+
+TEST(FabricatedOverlayTests, SetResourceValueBadArgs) {
+ {
+ auto builder =
+ FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+ .SetResourceValue("int1", Res_value::TYPE_INT_DEC, 1U);
+ ASSERT_FALSE(builder.Build());
+ }
+ {
+ auto builder =
+ FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+ .SetResourceValue("com.example.target:int2", Res_value::TYPE_INT_DEC, 1U);
+ ASSERT_FALSE(builder.Build());
+ }
+}
+
+TEST(FabricatedOverlayTests, SerializeAndDeserialize) {
+ auto overlay =
+ FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
+ .SetOverlayable("TestResources")
+ .SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U)
+ .Build();
+ ASSERT_TRUE(overlay);
+ TemporaryFile tf;
+ std::ofstream out(tf.path);
+ ASSERT_TRUE((*overlay).ToBinaryStream(out));
+ out.close();
+
+ auto container = OverlayResourceContainer::FromPath(tf.path);
+ ASSERT_TRUE(container) << container.GetErrorMessage();
+ EXPECT_EQ(tf.path, (*container)->GetPath());
+
+ auto crc = (*container)->GetCrc();
+ ASSERT_TRUE(crc) << crc.GetErrorMessage();
+ EXPECT_NE(0U, *crc);
+
+ auto info = (*container)->FindOverlayInfo("SandTheme");
+ ASSERT_TRUE(info) << info.GetErrorMessage();
+ EXPECT_EQ("SandTheme", (*info).name);
+ EXPECT_EQ("TestResources", (*info).target_name);
+
+ auto pairs = (*container)->GetOverlayData(*info);
+ ASSERT_TRUE(pairs) << pairs.GetErrorMessage();
+ EXPECT_EQ(1U, pairs->pairs.size());
+
+ auto& it = pairs->pairs[0];
+ ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
+ auto entry = std::get_if<TargetValue>(&it.value);
+ ASSERT_NE(nullptr, entry);
+ EXPECT_EQ(1U, entry->data_value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+}
+
+} // namespace android::idmap2 \ No newline at end of file
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 16b68f01e8f5..9516ff83d718 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <android-base/file.h>
+
#include <cstdio> // fclose
#include <fstream>
#include <memory>
@@ -61,12 +63,12 @@ TEST(IdmapTests, TestCanonicalIdmapPathFor) {
}
TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) {
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
std::istringstream stream(raw);
std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
ASSERT_THAT(header, NotNull());
ASSERT_EQ(header->GetMagic(), 0x504d4449U);
- ASSERT_EQ(header->GetVersion(), 0x07U);
+ ASSERT_EQ(header->GetVersion(), 0x08U);
ASSERT_EQ(header->GetTargetCrc(), 0x1234U);
ASSERT_EQ(header->GetOverlayCrc(), 0x5678U);
ASSERT_EQ(header->GetFulfilledPolicies(), 0x11);
@@ -81,7 +83,7 @@ TEST(IdmapTests, IdmapFailParsingDifferentVersion) {
std::stringstream stream;
stream << android::kIdmapMagic;
stream << 0xffffffffU;
- stream << std::string(kJunkSize, (char) 0xffU);
+ stream << std::string(kJunkSize, (char)0xffU);
ASSERT_FALSE(Idmap::FromBinaryStream(stream));
}
@@ -90,14 +92,13 @@ TEST(IdmapTests, IdmapFailParsingDifferentMagic) {
std::stringstream stream;
stream << 0xffffffffU;
stream << android::kIdmapCurrentVersion;
- stream << std::string(kJunkSize, (char) 0xffU);
+ stream << std::string(kJunkSize, (char)0xffU);
ASSERT_FALSE(Idmap::FromBinaryStream(stream));
}
TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
const size_t offset = kIdmapRawDataOffset;
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
- kIdmapRawDataLen - offset);
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData + offset), kIdmapRawDataLen - offset);
std::istringstream stream(raw);
std::unique_ptr<const IdmapData::Header> header = IdmapData::Header::FromBinaryStream(stream);
@@ -108,8 +109,7 @@ TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
TEST(IdmapTests, CreateIdmapDataFromBinaryStream) {
const size_t offset = kIdmapRawDataOffset;
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
- kIdmapRawDataLen - offset);
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData + offset), kIdmapRawDataLen - offset);
std::istringstream stream(raw);
std::unique_ptr<const IdmapData> data = IdmapData::FromBinaryStream(stream);
@@ -134,7 +134,7 @@ TEST(IdmapTests, CreateIdmapDataFromBinaryStream) {
}
TEST(IdmapTests, CreateIdmapFromBinaryStream) {
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
std::istringstream stream(raw);
auto result = Idmap::FromBinaryStream(stream);
@@ -143,7 +143,7 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x07U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x08U);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U);
ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), kIdmapRawDataPolicies);
@@ -177,7 +177,7 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
}
TEST(IdmapTests, GracefullyFailToCreateIdmapFromCorruptBinaryStream) {
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data),
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData),
10); // data too small
std::istringstream stream(raw);
@@ -189,14 +189,14 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) {
std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk";
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
+ auto target = TargetResourceContainer::FromPath(target_apk_path);
+ ASSERT_TRUE(target);
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
+ auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+ ASSERT_TRUE(overlay);
- auto idmap_result = Idmap::FromApkAssets(
- *target_apk, *overlay_apk, TestConstants::OVERLAY_NAME_ALL_POLICIES, PolicyFlags::PUBLIC,
+ auto idmap_result = Idmap::FromContainers(
+ **target, **overlay, TestConstants::OVERLAY_NAME_ALL_POLICIES, PolicyFlags::PUBLIC,
/* enforce_overlayable */ true);
ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
auto& idmap = *idmap_result;
@@ -204,7 +204,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) {
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x07U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x08U);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC);
@@ -218,15 +218,15 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssets) {
std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk";
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
+ auto target = TargetResourceContainer::FromPath(target_apk_path);
+ ASSERT_TRUE(target);
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
+ auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+ ASSERT_TRUE(overlay);
- auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk,
- TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
- /* enforce_overlayable */ true);
+ auto idmap_result = Idmap::FromContainers(
+ **target, **overlay, TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
+ /* enforce_overlayable */ true);
ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
auto& idmap = *idmap_result;
ASSERT_THAT(idmap, NotNull());
@@ -255,25 +255,66 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssets) {
ASSERT_OVERLAY_ENTRY(overlay_entries[3], R::overlay::string::str4, R::target::string::str4);
}
+TEST(IdmapTests, FabricatedOverlay) {
+ std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+ auto target = TargetResourceContainer::FromPath(target_apk_path);
+ ASSERT_TRUE(target);
+
+ auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
+ .SetOverlayable("TestResources")
+ .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U)
+ .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000)
+ .Build();
+
+ ASSERT_TRUE(frro);
+ TemporaryFile tf;
+ std::ofstream out(tf.path);
+ ASSERT_TRUE((*frro).ToBinaryStream(out));
+ out.close();
+
+ auto overlay = OverlayResourceContainer::FromPath(tf.path);
+ ASSERT_TRUE(overlay);
+
+ auto idmap_result = Idmap::FromContainers(**target, **overlay, "SandTheme", PolicyFlags::PUBLIC,
+ /* enforce_overlayable */ true);
+ ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
+ auto& idmap = *idmap_result;
+ ASSERT_THAT(idmap, NotNull());
+
+ const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+ ASSERT_EQ(dataBlocks.size(), 1U);
+
+ const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+ ASSERT_THAT(data, NotNull());
+ ASSERT_EQ(data->GetTargetEntries().size(), 0U);
+ ASSERT_EQ(data->GetOverlayEntries().size(), 0U);
+
+ const auto& target_inline_entries = data->GetTargetInlineEntries();
+ ASSERT_EQ(target_inline_entries.size(), 2U);
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1,
+ Res_value::TYPE_INT_DEC, 2U);
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1,
+ Res_value::TYPE_REFERENCE, 0x7f010000);
+}
+
TEST(IdmapTests, FailCreateIdmapInvalidName) {
std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk";
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
+ auto target = TargetResourceContainer::FromPath(target_apk_path);
+ ASSERT_TRUE(target);
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
+ auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+ ASSERT_TRUE(overlay);
{
- auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, "", PolicyFlags::PUBLIC,
- /* enforce_overlayable */ true);
+ auto idmap_result = Idmap::FromContainers(**target, **overlay, "", PolicyFlags::PUBLIC,
+ /* enforce_overlayable */ true);
ASSERT_FALSE(idmap_result);
}
{
- auto idmap_result =
- Idmap::FromApkAssets(*target_apk, *overlay_apk, "unknown", PolicyFlags::PUBLIC,
- /* enforce_overlayable */ true);
+ auto idmap_result = Idmap::FromContainers(**target, **overlay, "unknown", PolicyFlags::PUBLIC,
+ /* enforce_overlayable */ true);
ASSERT_FALSE(idmap_result);
}
}
@@ -282,15 +323,15 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) {
std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay-shared.apk";
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
+ auto target = TargetResourceContainer::FromPath(target_apk_path);
+ ASSERT_TRUE(target);
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
+ auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+ ASSERT_TRUE(overlay);
- auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk,
- TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
- /* enforce_overlayable */ true);
+ auto idmap_result = Idmap::FromContainers(
+ **target, **overlay, TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
+ /* enforce_overlayable */ true);
ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage();
auto& idmap = *idmap_result;
ASSERT_THAT(idmap, NotNull());
@@ -328,30 +369,29 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) {
}
Result<std::unique_ptr<const IdmapData>> TestIdmapDataFromApkAssets(
- const std::string& local_target_apk_path, const std::string& local_overlay_apk_path,
+ const std::string& local_target_path, const std::string& local_overlay_path,
const std::string& overlay_name, const PolicyBitmask& fulfilled_policies,
bool enforce_overlayable) {
- auto overlay_info =
- utils::ExtractOverlayManifestInfo(GetTestDataPath() + local_overlay_apk_path, overlay_name);
- if (!overlay_info) {
- return overlay_info.GetError();
+ const std::string target_path(GetTestDataPath() + local_target_path);
+ auto target = TargetResourceContainer::FromPath(target_path);
+ if (!target) {
+ return Error(R"(Failed to load target "%s")", target_path.c_str());
}
- const std::string target_apk_path(GetTestDataPath() + local_target_apk_path);
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- if (!target_apk) {
- return Error(R"(Failed to load target apk "%s")", target_apk_path.data());
+ const std::string overlay_path(GetTestDataPath() + local_overlay_path);
+ auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+ if (!overlay) {
+ return Error(R"(Failed to load overlay "%s")", overlay_path.c_str());
}
- const std::string overlay_apk_path(GetTestDataPath() + local_overlay_apk_path);
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- if (!overlay_apk) {
- return Error(R"(Failed to load overlay apk "%s")", overlay_apk_path.data());
+ auto overlay_info = (*overlay)->FindOverlayInfo(overlay_name);
+ if (!overlay_info) {
+ return Error(R"(Failed to find overlay name "%s")", overlay_name.c_str());
}
LogInfo log_info;
- auto mapping = ResourceMapping::FromApkAssets(*target_apk, *overlay_apk, *overlay_info,
- fulfilled_policies, enforce_overlayable, log_info);
+ auto mapping = ResourceMapping::FromContainers(**target, **overlay, *overlay_info,
+ fulfilled_policies, enforce_overlayable, log_info);
if (!mapping) {
return mapping.GetError();
}
@@ -360,11 +400,9 @@ Result<std::unique_ptr<const IdmapData>> TestIdmapDataFromApkAssets(
}
TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) {
- auto idmap_data =
- TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk", "DifferentPackages",
-
- PolicyFlags::PUBLIC,
- /* enforce_overlayable */ false);
+ auto idmap_data = TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk",
+ "DifferentPackages", PolicyFlags::PUBLIC,
+ /* enforce_overlayable */ false);
ASSERT_TRUE(idmap_data) << idmap_data.GetErrorMessage();
auto& data = *idmap_data;
@@ -417,7 +455,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
const uint32_t target_crc = kIdmapRawDataTargetCrc;
const uint32_t overlay_crc = kIdmapRawOverlayCrc;
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
std::istringstream raw_stream(raw);
auto result = Idmap::FromBinaryStream(raw_stream);
@@ -468,8 +506,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
ASSERT_THAT(bad_target_crc_header, NotNull());
ASSERT_NE(header->GetTargetCrc(), bad_target_crc_header->GetTargetCrc());
ASSERT_FALSE(bad_target_crc_header->IsUpToDate(target_apk_path, overlay_apk_path, overlay_name,
- target_crc, overlay_crc, policies,
- /* enforce_overlayable */ true));
+ target_crc, overlay_crc, policies,
+ /* enforce_overlayable */ true));
// overlay crc: bytes (0xc, 0xf)
std::string bad_overlay_crc_string(stream.str());
@@ -483,8 +521,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
ASSERT_THAT(bad_overlay_crc_header, NotNull());
ASSERT_NE(header->GetOverlayCrc(), bad_overlay_crc_header->GetOverlayCrc());
ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate(target_apk_path, overlay_apk_path, overlay_name,
- target_crc, overlay_crc, policies,
- /* enforce_overlayable */ true));
+ target_crc, overlay_crc, policies,
+ /* enforce_overlayable */ true));
// fulfilled policy: bytes (0x10, 0x13)
std::string bad_policy_string(stream.str());
@@ -522,8 +560,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
ASSERT_THAT(bad_target_path_header, NotNull());
ASSERT_NE(header->GetTargetPath(), bad_target_path_header->GetTargetPath());
ASSERT_FALSE(bad_target_path_header->IsUpToDate(target_apk_path, overlay_apk_path, overlay_name,
- target_crc, overlay_crc, policies,
- /* enforce_overlayable */ true));
+ target_crc, overlay_crc, policies,
+ /* enforce_overlayable */ true));
// overlay path: bytes (0x2c, 0x37)
std::string bad_overlay_path_string(stream.str());
@@ -576,7 +614,7 @@ class TestVisitor : public Visitor {
};
TEST(IdmapTests, TestVisitor) {
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
std::istringstream stream(raw);
const auto idmap = Idmap::FromBinaryStream(stream);
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index 87ce0f13d19e..3d3d82a8c7dd 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -27,35 +27,31 @@
#include "idmap2/Idmap.h"
#include "idmap2/PrettyPrintVisitor.h"
-using android::ApkAssets;
using android::base::StringPrintf;
-using ::testing::NotNull;
-using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
namespace android::idmap2 {
TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) {
const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
+ auto target = TargetResourceContainer::FromPath(target_apk_path);
+ ASSERT_TRUE(target);
const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
+ auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+ ASSERT_TRUE(overlay);
- const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk,
- TestConstants::OVERLAY_NAME_DEFAULT, PolicyFlags::PUBLIC,
- /* enforce_overlayable */ true);
+ const auto idmap = Idmap::FromContainers(**target, **overlay, TestConstants::OVERLAY_NAME_DEFAULT,
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true);
ASSERT_TRUE(idmap);
std::stringstream stream;
PrettyPrintVisitor visitor(stream);
(*idmap)->accept(&visitor);
- ASSERT_NE(stream.str().find("target apk path : "), std::string::npos);
- ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos);
+ ASSERT_NE(stream.str().find("target path : "), std::string::npos);
+ ASSERT_NE(stream.str().find("overlay path : "), std::string::npos);
ASSERT_NE(stream.str().find(StringPrintf("0x%08x -> 0x%08x (integer/int1 -> integer/int1)\n",
R::target::integer::int1, R::overlay::integer::int1)),
std::string::npos);
@@ -64,7 +60,7 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) {
TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitorWithoutAccessToApks) {
fclose(stderr); // silence expected warnings from libandroidfw
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
std::istringstream raw_stream(raw);
const auto idmap = Idmap::FromBinaryStream(raw_stream);
@@ -74,8 +70,8 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitorWithoutAccessToApks) {
PrettyPrintVisitor visitor(stream);
(*idmap)->accept(&visitor);
- ASSERT_NE(stream.str().find("target apk path : "), std::string::npos);
- ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos);
+ ASSERT_NE(stream.str().find("target path : "), std::string::npos);
+ ASSERT_NE(stream.str().find("overlay path : "), std::string::npos);
ASSERT_NE(stream.str().find("0x7f020000 -> 0x7f020000 (\?\?\? -> \?\?\?)\n"), std::string::npos);
}
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 88f85efb0f84..a6371cb74f2e 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -30,17 +30,16 @@
#include "idmap2/RawPrintVisitor.h"
using android::base::StringPrintf;
-using ::testing::NotNull;
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
namespace android::idmap2 {
-#define ASSERT_CONTAINS_REGEX(pattern, str) \
- do { \
- ASSERT_TRUE(std::regex_search(str, std::regex(pattern))) \
- << "pattern '" << pattern << "' not found in\n--------\n" \
- << str << "--------"; \
+#define ASSERT_CONTAINS_REGEX(pattern, str) \
+ do { \
+ ASSERT_TRUE(std::regex_search(str, std::regex(pattern))) \
+ << "pattern '" << (pattern) << "' not found in\n--------\n" \
+ << (str) << "--------"; \
} while (0)
#define ADDRESS "[0-9a-f]{8}: "
@@ -49,16 +48,15 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
fclose(stderr); // silence expected warnings
const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
+ auto target = TargetResourceContainer::FromPath(target_apk_path);
+ ASSERT_TRUE(target);
const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
+ auto overlay = OverlayResourceContainer::FromPath(overlay_apk_path);
+ ASSERT_TRUE(overlay);
- const auto idmap =
- Idmap::FromApkAssets(*target_apk, *overlay_apk, TestConstants::OVERLAY_NAME_DEFAULT,
- PolicyFlags::PUBLIC, /* enforce_overlayable */ true);
+ const auto idmap = Idmap::FromContainers(**target, **overlay, TestConstants::OVERLAY_NAME_DEFAULT,
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true);
ASSERT_TRUE(idmap);
std::stringstream stream;
@@ -66,7 +64,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
(*idmap)->accept(&visitor);
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "00000007 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000008 version\n", stream.str());
ASSERT_CONTAINS_REGEX(
StringPrintf(ADDRESS "%s target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
stream.str());
@@ -75,8 +73,6 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000001 fulfilled policies: public\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000001 enforce overlayable\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 target entry count", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000000 target inline entry count", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 overlay entry count", stream.str());
@@ -104,7 +100,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
fclose(stderr); // silence expected warnings from libandroidfw
- std::string raw(reinterpret_cast<const char*>(idmap_raw_data), kIdmapRawDataLen);
+ std::string raw(reinterpret_cast<const char*>(kIdmapRawData), kIdmapRawDataLen);
std::istringstream raw_stream(raw);
const auto idmap = Idmap::FromBinaryStream(raw_stream);
@@ -115,7 +111,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
(*idmap)->accept(&visitor);
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "00000007 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000008 version\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00001234 target crc\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00005678 overlay crc\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000011 fulfilled policies: public|signature\n", stream.str());
@@ -126,8 +122,6 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
ASSERT_CONTAINS_REGEX(ADDRESS "........ overlay path: overlayX.apk\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "0000000b overlay name size\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "........ overlay name: OverlayName\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000003 target entry count\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000001 target inline entry count\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000003 overlay entry count\n", stream.str());
@@ -140,7 +134,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 overlay id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f030002 target id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 string pool size\n", stream.str());
- ASSERT_CONTAINS_REGEX("000000a8: ........ string pool\n", stream.str());
+ ASSERT_CONTAINS_REGEX("000000a4: ........ string pool\n", stream.str());
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 0362529c4f3b..5a1d808af06f 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#include <android-base/file.h>
+#include <androidfw/ResourceTypes.h>
+#include <gtest/gtest.h>
+
#include <cstdio> // fclose
#include <fstream>
#include <memory>
@@ -22,14 +26,10 @@
#include "R.h"
#include "TestConstants.h"
#include "TestHelpers.h"
-#include "androidfw/ResourceTypes.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
#include "idmap2/LogInfo.h"
#include "idmap2/ResourceMapping.h"
using android::Res_value;
-using android::idmap2::utils::ExtractOverlayManifestInfo;
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
@@ -41,32 +41,36 @@ namespace android::idmap2 {
ASSERT_TRUE(result) << result.GetErrorMessage(); \
} while (0)
-Result<ResourceMapping> TestGetResourceMapping(const std::string& local_target_apk_path,
- const std::string& local_overlay_apk_path,
+Result<ResourceMapping> TestGetResourceMapping(const std::string& local_target_path,
+ const std::string& local_overlay_path,
const std::string& overlay_name,
const PolicyBitmask& fulfilled_policies,
bool enforce_overlayable) {
- auto overlay_info =
- ExtractOverlayManifestInfo(GetTestDataPath() + local_overlay_apk_path, overlay_name);
- if (!overlay_info) {
- return overlay_info.GetError();
+ const std::string target_path = (local_target_path[0] == '/')
+ ? local_target_path
+ : (GetTestDataPath() + "/" + local_target_path);
+ auto target = TargetResourceContainer::FromPath(target_path);
+ if (!target) {
+ return Error(target.GetError(), R"(Failed to load target "%s")", target_path.c_str());
}
- const std::string target_apk_path(GetTestDataPath() + local_target_apk_path);
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- if (!target_apk) {
- return Error(R"(Failed to load target apk "%s")", target_apk_path.data());
+ const std::string overlay_path = (local_overlay_path[0] == '/')
+ ? local_overlay_path
+ : (GetTestDataPath() + "/" + local_overlay_path);
+ auto overlay = OverlayResourceContainer::FromPath(overlay_path);
+ if (!overlay) {
+ return Error(overlay.GetError(), R"(Failed to load overlay "%s")", overlay_path.c_str());
}
- const std::string overlay_apk_path(GetTestDataPath() + local_overlay_apk_path);
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- if (!overlay_apk) {
- return Error(R"(Failed to load overlay apk "%s")", overlay_apk_path.data());
+ auto overlay_info = (*overlay)->FindOverlayInfo(overlay_name);
+ if (!overlay_info) {
+ return Error(overlay_info.GetError(), R"(Failed to find overlay name "%s")",
+ overlay_name.c_str());
}
LogInfo log_info;
- return ResourceMapping::FromApkAssets(*target_apk, *overlay_apk, *overlay_info,
- fulfilled_policies, enforce_overlayable, log_info);
+ return ResourceMapping::FromContainers(**target, **overlay, *overlay_info, fulfilled_policies,
+ enforce_overlayable, log_info);
}
Result<Unit> MappingExists(const ResourceMapping& mapping, ResourceId target_resource,
@@ -128,7 +132,7 @@ Result<Unit> MappingExists(const ResourceMapping& mapping, const ResourceId& tar
}
TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) {
- auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay-legacy.apk", "",
+ auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay-legacy.apk", "",
PolicyFlags::PUBLIC, /* enforce_overlayable */ false);
ASSERT_TRUE(resources) << resources.GetErrorMessage();
@@ -145,7 +149,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) {
}
TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
- auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", "SwapNames",
+ auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk", "SwapNames",
PolicyFlags::PUBLIC,
/* enforce_overlayable */ false);
@@ -161,7 +165,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) {
}
TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) {
- auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk",
+ auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
"DifferentPackages", PolicyFlags::PUBLIC,
/* enforce_overlayable */ false);
@@ -176,7 +180,7 @@ TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) {
}
TEST(ResourceMappingTests, InlineResources) {
- auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", "Inline",
+ auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk", "Inline",
PolicyFlags::PUBLIC, /* enforce_overlayable */ false);
constexpr size_t overlay_string_pool_size = 10U;
@@ -189,8 +193,32 @@ TEST(ResourceMappingTests, InlineResources) {
ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 73U));
}
+TEST(ResourceMappingTests, FabricatedOverlay) {
+ auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
+ .SetOverlayable("TestResources")
+ .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U)
+ .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000)
+ .Build();
+
+ ASSERT_TRUE(frro);
+ TemporaryFile tf;
+ std::ofstream out(tf.path);
+ ASSERT_TRUE((*frro).ToBinaryStream(out));
+ out.close();
+
+ auto resources = TestGetResourceMapping("target/target.apk", tf.path, "SandTheme",
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ false);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
+ ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
+ ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, 0x7f010000));
+ ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 2U));
+}
+
TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
- auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk",
+ auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
TestConstants::OVERLAY_NAME_ALL_POLICIES,
PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
/* enforce_overlayable */ true);
@@ -209,7 +237,7 @@ TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
// Resources that are not declared as overlayable and resources that a protected by policies the
// overlay does not fulfill must not map to overlay resources.
TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
- auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk",
+ auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
TestConstants::OVERLAY_NAME_ALL_POLICIES,
PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
/* enforce_overlayable */ true);
@@ -229,7 +257,7 @@ TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
// overlay does not fulfilled can map to overlay resources when overlayable enforcement is turned
// off.
TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
- auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk",
+ auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay.apk",
TestConstants::OVERLAY_NAME_ALL_POLICIES,
PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC,
/* enforce_overlayable */ false);
@@ -264,7 +292,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore
// Overlays that do not target an <overlayable> tag can overlay any resource if overlayable
// enforcement is disabled.
TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTargetName) {
- auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay-legacy.apk", "",
+ auto resources = TestGetResourceMapping("target/target.apk", "overlay/overlay-legacy.apk", "",
PolicyFlags::PUBLIC,
/* enforce_overlayable */ false);
@@ -284,10 +312,9 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTarget
// Overlays that are neither pre-installed nor signed with the same signature as the target cannot
// overlay packages that have not defined overlayable resources.
TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
- auto resources =
- TestGetResourceMapping("/target/target-no-overlayable.apk", "/overlay/overlay.apk",
- "NoTargetName", PolicyFlags::PUBLIC,
- /* enforce_overlayable */ true);
+ auto resources = TestGetResourceMapping("target/target-no-overlayable.apk", "overlay/overlay.apk",
+ "NoTargetName", PolicyFlags::PUBLIC,
+ /* enforce_overlayable */ true);
ASSERT_TRUE(resources) << resources.GetErrorMessage();
ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
@@ -297,9 +324,9 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
// signed with the same signature as the reference package can overlay packages that have not
// defined overlayable resources.
TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
- auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
+ auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) {
auto resources =
- TestGetResourceMapping("/target/target-no-overlayable.apk", "/overlay/overlay.apk",
+ TestGetResourceMapping("target/target-no-overlayable.apk", "overlay/overlay.apk",
TestConstants::OVERLAY_NAME_ALL_POLICIES, fulfilled_policies,
/* enforce_overlayable */ true);
diff --git a/cmds/idmap2/tests/ResourceUtilsTests.cpp b/cmds/idmap2/tests/ResourceUtilsTests.cpp
index 1f6bf49f5f0e..69142086765c 100644
--- a/cmds/idmap2/tests/ResourceUtilsTests.cpp
+++ b/cmds/idmap2/tests/ResourceUtilsTests.cpp
@@ -17,10 +17,12 @@
#include <memory>
#include <string>
+#include "R.h"
#include "TestHelpers.h"
#include "androidfw/ApkAssets.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "idmap2/ResourceContainer.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
@@ -49,8 +51,8 @@ class ResourceUtilsTests : public Idmap2Tests {
};
TEST_F(ResourceUtilsTests, ResToTypeEntryName) {
- Result<std::string> name = utils::ResToTypeEntryName(GetAssetManager(), 0x7f010000U);
- ASSERT_TRUE(name);
+ Result<std::string> name = utils::ResToTypeEntryName(GetAssetManager(), R::target::integer::int1);
+ ASSERT_TRUE(name) << name.GetErrorMessage();
ASSERT_EQ(*name, "integer/int1");
}
@@ -60,25 +62,34 @@ TEST_F(ResourceUtilsTests, ResToTypeEntryNameNoSuchResourceId) {
}
TEST_F(ResourceUtilsTests, InvalidValidOverlayNameInvalidAttributes) {
- auto info = utils::ExtractOverlayManifestInfo(GetTestDataPath() + "/overlay/overlay-invalid.apk",
- "InvalidName");
+ auto overlay =
+ OverlayResourceContainer::FromPath(GetTestDataPath() + "/overlay/overlay-invalid.apk");
+ ASSERT_TRUE(overlay);
+
+ auto info = (*overlay)->FindOverlayInfo("InvalidName");
ASSERT_FALSE(info);
}
TEST_F(ResourceUtilsTests, ValidOverlayNameInvalidAttributes) {
- auto info = utils::ExtractOverlayManifestInfo(GetTestDataPath() + "/overlay/overlay-invalid.apk",
- "ValidName");
+ auto overlay =
+ OverlayResourceContainer::FromPath(GetTestDataPath() + "/overlay/overlay-invalid.apk");
+ ASSERT_TRUE(overlay);
+
+ auto info = (*overlay)->FindOverlayInfo("ValidName");
ASSERT_FALSE(info);
}
TEST_F(ResourceUtilsTests, ValidOverlayNameAndTargetPackageInvalidAttributes) {
- auto info = utils::ExtractOverlayManifestInfo(GetTestDataPath() + "/overlay/overlay-invalid.apk",
- "ValidNameAndTargetPackage");
+ auto overlay =
+ OverlayResourceContainer::FromPath(GetTestDataPath() + "/overlay/overlay-invalid.apk");
+ ASSERT_TRUE(overlay);
+
+ auto info = (*overlay)->FindOverlayInfo("ValidNameAndTargetPackage");
ASSERT_TRUE(info);
ASSERT_EQ("ValidNameAndTargetPackage", info->name);
ASSERT_EQ("Valid", info->target_package);
- ASSERT_EQ("", info->target_name); // Attribute resource id could not be found
- ASSERT_EQ(0, info->resource_mapping); // Attribute resource id could not be found
+ ASSERT_EQ("", info->target_name); // Attribute resource id could not be found
+ ASSERT_EQ(0, info->resource_mapping); // Attribute resource id could not be found
}
-}// namespace android::idmap2
+} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index 842af3dd7b3c..6b5f3a8a98eb 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -24,13 +24,13 @@
namespace android::idmap2 {
-const unsigned char idmap_raw_data[] = {
+const unsigned char kIdmapRawData[] = {
// IDMAP HEADER
// 0x0: magic
0x49, 0x44, 0x4d, 0x50,
// 0x4: version
- 0x07, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
// 0x8: target crc
0x34, 0x12, 0x00, 0x00,
@@ -70,81 +70,72 @@ const unsigned char idmap_raw_data[] = {
0x64, 0x65, 0x62, 0x75, 0x67, 0x00, 0x00, 0x00,
// DATA HEADER
- // 0x54: target_package_id
- 0x7f,
-
- // 0x55: overlay_package_id
- 0x7f,
-
- // 0x56: padding
- 0x00, 0x00,
-
- // 0x58: target_entry_count
+ // 0x54: target_entry_count
0x03, 0x00, 0x00, 0x00,
- // 0x5c: target_inline_entry_count
+ // 0x58: target_inline_entry_count
0x01, 0x00, 0x00, 0x00,
- // 0x60: overlay_entry_count
+ // 0x5c: overlay_entry_count
0x03, 0x00, 0x00, 0x00,
- // 0x64: string_pool_offset
+ // 0x60: string_pool_offset
0x00, 0x00, 0x00, 0x00,
// TARGET ENTRIES
- // 0x68: target id (0x7f020000)
+ // 0x64: target id (0x7f020000)
0x00, 0x00, 0x02, 0x7f,
- // 0x6c: overlay_id (0x7f020000)
+ // 0x68: overlay_id (0x7f020000)
0x00, 0x00, 0x02, 0x7f,
- // 0x70: target id (0x7f030000)
+ // 0x6c: target id (0x7f030000)
0x00, 0x00, 0x03, 0x7f,
- // 0x74: overlay_id (0x7f030000)
+ // 0x70: overlay_id (0x7f030000)
0x00, 0x00, 0x03, 0x7f,
- // 0x78: target id (0x7f030002)
+ // 0x74: target id (0x7f030002)
0x02, 0x00, 0x03, 0x7f,
- // 0x7c: overlay_id (0x7f030001)
+ // 0x78: overlay_id (0x7f030001)
0x01, 0x00, 0x03, 0x7f,
// INLINE TARGET ENTRIES
- // 0x80: target_id
+ // 0x7c: target_id
0x00, 0x00, 0x04, 0x7f,
- // 0x84: Res_value::size (value ignored by idmap)
+ // 0x80: Res_value::size (value ignored by idmap)
0x08, 0x00,
- // 0x87: Res_value::res0 (value ignored by idmap)
+ // 0x82: Res_value::res0 (value ignored by idmap)
0x00,
- // 0x88: Res_value::dataType (TYPE_INT_HEX)
+ // 0x83: Res_value::dataType (TYPE_INT_HEX)
0x11,
- // 0x8c: Res_value::data
+ // 0x84: Res_value::data
0x78, 0x56, 0x34, 0x12,
// OVERLAY ENTRIES
- // 0x90: 0x7f020000 -> 0x7f020000
+ // 0x88: 0x7f020000 -> 0x7f020000
0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f,
- // 0x98: 0x7f030000 -> 0x7f030000
+ // 0x90: 0x7f030000 -> 0x7f030000
0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f,
- // 0xa0: 0x7f030001 -> 0x7f030002
+ // 0x98: 0x7f030001 -> 0x7f030002
0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f,
- // 0xa4: string pool
+ // 0xa0: string pool
// string length,
0x04, 0x00, 0x00, 0x00,
- // 0xa8 string contents "test"
+ // 0xa4 string contents "test"
0x74, 0x65, 0x73, 0x74};
-const unsigned int kIdmapRawDataLen = 0xac;
+const unsigned int kIdmapRawDataLen = 0xa8;
const unsigned int kIdmapRawDataOffset = 0x54;
const unsigned int kIdmapRawDataTargetCrc = 0x1234;
const unsigned int kIdmapRawOverlayCrc = 0x5678;
diff --git a/cmds/idmap2/tests/XmlParserTests.cpp b/cmds/idmap2/tests/XmlParserTests.cpp
index 1a7eaca4d67b..eaf10a7d9282 100644
--- a/cmds/idmap2/tests/XmlParserTests.cpp
+++ b/cmds/idmap2/tests/XmlParserTests.cpp
@@ -19,25 +19,25 @@
#include <string>
#include "TestHelpers.h"
-#include "gmock/gmock.h"
+#include "androidfw/AssetsProvider.h"
#include "gtest/gtest.h"
#include "idmap2/XmlParser.h"
-#include "idmap2/ZipFile.h"
namespace android::idmap2 {
-Result<std::unique_ptr<const XmlParser>> CreateTestParser(const std::string& test_file) {
- auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
+Result<XmlParser> CreateTestParser(const std::string& test_file) {
+ auto zip = ZipAssetsProvider::Create(GetTestDataPath() + "/target/target.apk");
if (zip == nullptr) {
return Error("Failed to open zip file");
}
- auto data = zip->Uncompress(test_file);
+ auto data = zip->Open(test_file);
if (data == nullptr) {
return Error("Failed to open xml file");
}
- return XmlParser::Create(data->buf, data->size, /* copy_data */ true);
+ return XmlParser::Create(data->getBuffer(true /* aligned*/), data->getLength(),
+ /* copy_data */ true);
}
TEST(XmlParserTests, Create) {
@@ -54,7 +54,7 @@ TEST(XmlParserTests, NextChild) {
auto xml = CreateTestParser("res/xml/test.xml");
ASSERT_TRUE(xml) << xml.GetErrorMessage();
- auto root_iter = (*xml)->tree_iterator();
+ auto root_iter = xml->tree_iterator();
ASSERT_EQ(root_iter->event(), XmlParser::Event::START_TAG);
ASSERT_EQ(root_iter->name(), "a");
@@ -85,7 +85,7 @@ TEST(XmlParserTests, AttributeValues) {
ASSERT_TRUE(xml) << xml.GetErrorMessage();
// Start at the <a> tag.
- auto root_iter = (*xml)->tree_iterator();
+ auto root_iter = xml->tree_iterator();
// Start at the <b> tag.
auto a_iter = root_iter.begin();
@@ -111,8 +111,8 @@ TEST(XmlParserTests, IteratorEquality) {
ASSERT_TRUE(xml) << xml.GetErrorMessage();
// Start at the <a> tag.
- auto root_iter_1 = (*xml)->tree_iterator();
- auto root_iter_2 = (*xml)->tree_iterator();
+ auto root_iter_1 = xml->tree_iterator();
+ auto root_iter_2 = xml->tree_iterator();
ASSERT_EQ(root_iter_1, root_iter_2);
ASSERT_EQ(*root_iter_1, *root_iter_2);
@@ -146,7 +146,7 @@ TEST(XmlParserTests, Backtracking) {
ASSERT_TRUE(xml) << xml.GetErrorMessage();
// Start at the <a> tag.
- auto root_iter_1 = (*xml)->tree_iterator();
+ auto root_iter_1 = xml->tree_iterator();
// Start at the <b> tag.
auto a_iter_1 = root_iter_1.begin();
diff --git a/cmds/idmap2/tests/ZipFileTests.cpp b/cmds/idmap2/tests/ZipFileTests.cpp
deleted file mode 100644
index 3fca43621945..000000000000
--- a/cmds/idmap2/tests/ZipFileTests.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cstdio> // fclose
-#include <string>
-
-#include "TestHelpers.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "idmap2/Result.h"
-#include "idmap2/ZipFile.h"
-
-using ::testing::IsNull;
-using ::testing::NotNull;
-
-namespace android::idmap2 {
-
-TEST(ZipFileTests, BasicOpen) {
- auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
- ASSERT_THAT(zip, NotNull());
-
- fclose(stderr); // silence expected warnings from libziparchive
- auto fail = ZipFile::Open(GetTestDataPath() + "/does-not-exist");
- ASSERT_THAT(fail, IsNull());
-}
-
-TEST(ZipFileTests, Crc) {
- auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
- ASSERT_THAT(zip, NotNull());
-
- Result<uint32_t> crc = zip->Crc("AndroidManifest.xml");
- ASSERT_TRUE(crc);
- ASSERT_EQ(*crc, 0x762f3d24);
-
- Result<uint32_t> crc2 = zip->Crc("does-not-exist");
- ASSERT_FALSE(crc2);
-}
-
-TEST(ZipFileTests, Uncompress) {
- auto zip = ZipFile::Open(GetTestDataPath() + "/target/target.apk");
- ASSERT_THAT(zip, NotNull());
-
- auto data = zip->Uncompress("assets/lorem-ipsum.txt");
- ASSERT_THAT(data, NotNull());
- const std::string lorem_ipsum("Lorem ipsum dolor sit amet.\n");
- ASSERT_THAT(data->size, lorem_ipsum.size());
- ASSERT_THAT(std::string(reinterpret_cast<const char*>(data->buf), data->size), lorem_ipsum);
-
- auto fail = zip->Uncompress("does-not-exist");
- ASSERT_THAT(fail, IsNull());
-}
-
-} // namespace android::idmap2
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index f1998a583a21..af06e2e80cec 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -188,7 +188,7 @@ static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t forma
ATRACE_NAME(base::StringPrintf("LoadApkAssets(%s)", path.c_str()).c_str());
auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
- std::unique_ptr<const ApkAssets> apk_assets;
+ std::unique_ptr<ApkAssets> apk_assets;
switch (format) {
case FORMAT_APK: {
auto assets = MultiAssetsProvider::Create(std::move(loader_assets),
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml
index 38e5fa18300c..926b1864d97c 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/overlays.xml
@@ -25,7 +25,6 @@
<item target="integer/matrix_100100" value="@integer/matrix_100100"/>
<item target="integer/matrix_100101" value="@integer/matrix_100101"/>
<item target="integer/matrix_100110" value="@integer/matrix_100110"/>
- <item target="integer/matrix_100110" value="@integer/matrix_100110"/>
<item target="integer/matrix_100111" value="@integer/matrix_100111"/>
<item target="integer/matrix_101000" value="@integer/matrix_101000"/>
<item target="integer/matrix_101001" value="@integer/matrix_101001"/>
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index ca5981c0dd5c..9c743cea592a 100755
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -83,8 +83,16 @@ std::unique_ptr<ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
return {};
}
+ std::unique_ptr<AssetsProvider> overlay_assets;
const std::string overlay_path(loaded_idmap->OverlayApkPath());
- auto overlay_assets = ZipAssetsProvider::Create(overlay_path);
+ if (IsFabricatedOverlay(overlay_path)) {
+ // Fabricated overlays do not contain resource definitions. All of the overlay resource values
+ // are defined inline in the idmap.
+ overlay_assets = EmptyAssetsProvider::Create();
+ } else {
+ // The overlay should be an APK.
+ overlay_assets = ZipAssetsProvider::Create(overlay_path);
+ }
if (overlay_assets == nullptr) {
return {};
}
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 03ab62f48870..36bde5ccf267 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -102,9 +102,8 @@ AssetManager2::AssetManager2() {
memset(&configuration_, 0, sizeof(configuration_));
}
-bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
- bool invalidate_caches) {
- apk_assets_ = apk_assets;
+bool AssetManager2::SetApkAssets(std::vector<const ApkAssets*> apk_assets, bool invalidate_caches) {
+ apk_assets_ = std::move(apk_assets);
BuildDynamicRefTable();
RebuildFilterList();
if (invalidate_caches) {
@@ -137,6 +136,36 @@ void AssetManager2::BuildDynamicRefTable() {
// 0x01 is reserved for the android package.
int next_package_id = 0x02;
for (const ApkAssets* apk_assets : sorted_apk_assets) {
+ std::shared_ptr<OverlayDynamicRefTable> overlay_ref_table;
+ if (auto loaded_idmap = apk_assets->GetLoadedIdmap(); loaded_idmap != nullptr) {
+ // The target package must precede the overlay package in the apk assets paths in order
+ // to take effect.
+ auto iter = apk_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath()));
+ if (iter == apk_assets_package_ids.end()) {
+ LOG(INFO) << "failed to find target package for overlay "
+ << loaded_idmap->OverlayApkPath();
+ } else {
+ uint8_t target_package_id = iter->second;
+
+ // Create a special dynamic reference table for the overlay to rewrite references to
+ // overlay resources as references to the target resources they overlay.
+ overlay_ref_table = std::make_shared<OverlayDynamicRefTable>(
+ loaded_idmap->GetOverlayDynamicRefTable(target_package_id));
+
+ // Add the overlay resource map to the target package's set of overlays.
+ const uint8_t target_idx = package_ids_[target_package_id];
+ CHECK(target_idx != 0xff) << "overlay target '" << loaded_idmap->TargetApkPath()
+ << "'added to apk_assets_package_ids but does not have an"
+ << " assigned package group";
+
+ PackageGroup& target_package_group = package_groups_[target_idx];
+ target_package_group.overlays_.push_back(
+ ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id,
+ overlay_ref_table.get()),
+ apk_assets_cookies[apk_assets]});
+ }
+ }
+
const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc();
for (const std::unique_ptr<const LoadedPackage>& package : loaded_arsc->GetPackages()) {
// Get the package ID or assign one if a shared library.
@@ -147,50 +176,25 @@ void AssetManager2::BuildDynamicRefTable() {
package_id = package->GetPackageId();
}
- // Add the mapping for package ID to index if not present.
uint8_t idx = package_ids_[package_id];
if (idx == 0xff) {
+ // Add the mapping for package ID to index if not present.
package_ids_[package_id] = idx = static_cast<uint8_t>(package_groups_.size());
- package_groups_.push_back({});
-
- if (apk_assets->IsOverlay()) {
- // The target package must precede the overlay package in the apk assets paths in order
- // to take effect.
- const auto& loaded_idmap = apk_assets->GetLoadedIdmap();
- auto target_package_iter = apk_assets_package_ids.find(
- std::string(loaded_idmap->TargetApkPath()));
- if (target_package_iter == apk_assets_package_ids.end()) {
- LOG(INFO) << "failed to find target package for overlay "
- << loaded_idmap->OverlayApkPath();
- } else {
- const uint8_t target_package_id = target_package_iter->second;
- const uint8_t target_idx = package_ids_[target_package_id];
- CHECK(target_idx != 0xff) << "overlay added to apk_assets_package_ids but does not"
- << " have an assigned package group";
-
- PackageGroup& target_package_group = package_groups_[target_idx];
-
- // Create a special dynamic reference table for the overlay to rewrite references to
- // overlay resources as references to the target resources they overlay.
- auto overlay_table = std::make_shared<OverlayDynamicRefTable>(
- loaded_idmap->GetOverlayDynamicRefTable(target_package_id));
- package_groups_.back().dynamic_ref_table = overlay_table;
-
- // Add the overlay resource map to the target package's set of overlays.
- target_package_group.overlays_.push_back(
- ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id,
- overlay_table.get()),
- apk_assets_cookies[apk_assets]});
- }
+ PackageGroup& new_group = package_groups_.emplace_back();
+
+ if (overlay_ref_table != nullptr) {
+ // If this package is from an overlay, use a dynamic reference table that can rewrite
+ // overlay resource ids to their corresponding target resource ids.
+ new_group.dynamic_ref_table = overlay_ref_table;
}
- DynamicRefTable* ref_table = package_groups_.back().dynamic_ref_table.get();
+ DynamicRefTable* ref_table = new_group.dynamic_ref_table.get();
ref_table->mAssignedPackageId = package_id;
ref_table->mAppAsLib = package->IsDynamic() && package->GetPackageId() == 0x7f;
}
- PackageGroup* package_group = &package_groups_[idx];
// Add the package and to the set of packages with the same ID.
+ PackageGroup* package_group = &package_groups_[idx];
package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
package_group->cookies_.push_back(apk_assets_cookies[apk_assets]);
@@ -578,7 +582,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
const PackageGroup& package_group = package_groups_[package_idx];
auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
- stop_at_first_match, ignore_configuration);
+ stop_at_first_match, ignore_configuration);
if (UNLIKELY(!result.has_value())) {
return base::unexpected(result.error());
}
diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp
index 23cacf88a6db..f3c48f7f9fc8 100644
--- a/libs/androidfw/AssetsProvider.cpp
+++ b/libs/androidfw/AssetsProvider.cpp
@@ -84,7 +84,7 @@ const std::string& ZipAssetsProvider::PathOrDebugName::GetDebugName() const {
return value_;
}
-ZipAssetsProvider::ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path,
+ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path,
time_t last_mod_time)
: zip_handle_(handle, ::CloseArchive),
name_(std::forward<PathOrDebugName>(path)),
@@ -93,7 +93,7 @@ ZipAssetsProvider::ZipAssetsProvider(ZipArchive* handle, PathOrDebugName&& path,
std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path) {
ZipArchiveHandle handle;
if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) {
- LOG(ERROR) << "Failed to open APK '" << path << "' " << ::ErrorCodeString(result);
+ LOG(ERROR) << "Failed to open APK '" << path << "': " << ::ErrorCodeString(result);
CloseArchive(handle);
return {};
}
@@ -253,6 +253,14 @@ bool ZipAssetsProvider::ForEachFile(const std::string& root_path,
return result == -1;
}
+std::optional<uint32_t> ZipAssetsProvider::GetCrc(std::string_view path) const {
+ ::ZipEntry entry;
+ if (FindEntry(zip_handle_.get(), path, &entry) != 0) {
+ return {};
+ }
+ return entry.crc32;
+}
+
const std::string& ZipAssetsProvider::GetDebugName() const {
return name_.GetDebugName();
}
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index f216f55771c2..efd1f6a25786 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -54,12 +54,6 @@ struct Idmap_header {
};
struct Idmap_data_header {
- uint8_t target_package_id;
- uint8_t overlay_package_id;
-
- // Padding to ensure 4 byte alignment for target_entry_count
- uint16_t p0;
-
uint32_t target_entry_count;
uint32_t target_inline_entry_count;
uint32_t overlay_entry_count;
@@ -158,19 +152,19 @@ IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const {
return {};
}
- // The resource ids encoded within the idmap are build-time resource ids.
- target_res_id = (0x00FFFFFFU & target_res_id)
- | (((uint32_t) data_header_->target_package_id) << 24U);
+ // The resource ids encoded within the idmap are build-time resource ids so do not consider the
+ // package id when determining if the resource in the target package is overlaid.
+ target_res_id &= 0x00FFFFFFU;
// Check if the target resource is mapped to an overlay resource.
auto first_entry = entries_;
auto end_entry = entries_ + dtohl(data_header_->target_entry_count);
auto entry = std::lower_bound(first_entry, end_entry, target_res_id,
- [](const Idmap_target_entry &e, const uint32_t target_id) {
- return dtohl(e.target_id) < target_id;
+ [](const Idmap_target_entry& e, const uint32_t target_id) {
+ return (0x00FFFFFFU & dtohl(e.target_id)) < target_id;
});
- if (entry != end_entry && dtohl(entry->target_id) == target_res_id) {
+ if (entry != end_entry && (0x00FFFFFFU & dtohl(entry->target_id)) == target_res_id) {
uint32_t overlay_resource_id = dtohl(entry->overlay_id);
// Lookup the resource without rewriting the overlay resource id back to the target resource id
// being looked up.
@@ -182,12 +176,13 @@ IdmapResMap::Result IdmapResMap::Lookup(uint32_t target_res_id) const {
auto first_inline_entry = inline_entries_;
auto end_inline_entry = inline_entries_ + dtohl(data_header_->target_inline_entry_count);
auto inline_entry = std::lower_bound(first_inline_entry, end_inline_entry, target_res_id,
- [](const Idmap_target_entry_inline &e,
+ [](const Idmap_target_entry_inline& e,
const uint32_t target_id) {
- return dtohl(e.target_id) < target_id;
+ return (0x00FFFFFFU & dtohl(e.target_id)) < target_id;
});
- if (inline_entry != end_inline_entry && dtohl(inline_entry->target_id) == target_res_id) {
+ if (inline_entry != end_inline_entry &&
+ (0x00FFFFFFU & dtohl(inline_entry->target_id)) == target_res_id) {
return Result(inline_entry->value);
}
return {};
@@ -235,7 +230,7 @@ std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size
}
return std::string_view(data, *len);
}
-}
+} // namespace
LoadedIdmap::LoadedIdmap(std::string&& idmap_path,
const Idmap_header* header,
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 223382731bc0..30500abc39c0 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -25,6 +25,7 @@
#include <string.h>
#include <algorithm>
+#include <fstream>
#include <limits>
#include <map>
#include <memory>
@@ -44,6 +45,7 @@
#ifdef __ANDROID__
#include <binder/TextOutput.h>
+
#endif
#ifndef INT32_MAX
@@ -233,6 +235,15 @@ void Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs
fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData));
}
+bool IsFabricatedOverlay(const std::string& path) {
+ std::ifstream fin(path);
+ uint32_t magic;
+ if (fin.read(reinterpret_cast<char*>(&magic), sizeof(uint32_t))) {
+ return magic == kFabricatedOverlayMagic;
+ }
+ return false;
+}
+
static bool assertIdmapHeader(const void* idmap, size_t size) {
if (reinterpret_cast<uintptr_t>(idmap) & 0x03) {
ALOGE("idmap: header is not word aligned");
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 6fbd6aa0df7b..2255973f1039 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -101,7 +101,7 @@ class AssetManager2 {
// Only pass invalidate_caches=false when it is known that the structure
// change in ApkAssets is due to a safe addition of resources with completely
// new resource IDs.
- bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
+ bool SetApkAssets(std::vector<const ApkAssets*> apk_assets, bool invalidate_caches = true);
inline const std::vector<const ApkAssets*> GetApkAssets() const {
return apk_assets_;
diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h
index 7b06947f45aa..6f16ff453905 100644
--- a/libs/androidfw/include/androidfw/AssetsProvider.h
+++ b/libs/androidfw/include/androidfw/AssetsProvider.h
@@ -88,6 +88,8 @@ struct ZipAssetsProvider : public AssetsProvider {
WARN_UNUSED const std::string& GetDebugName() const override;
WARN_UNUSED bool IsUpToDate() const override;
+ WARN_UNUSED std::optional<uint32_t> GetCrc(std::string_view path) const;
+
~ZipAssetsProvider() override = default;
protected:
std::unique_ptr<Asset> OpenInternal(const std::string& path, Asset::AccessMode mode,
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index 0ded79309bc1..6804472b3d17 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -168,15 +168,14 @@ class LoadedIdmap {
}
// Returns a mapping from target resource ids to overlay values.
- const IdmapResMap GetTargetResourcesMap(
- uint8_t target_assigned_package_id, const OverlayDynamicRefTable* overlay_ref_table) const {
+ const IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id,
+ const OverlayDynamicRefTable* overlay_ref_table) const {
return IdmapResMap(data_header_, target_entries_, target_inline_entries_,
target_assigned_package_id, overlay_ref_table);
}
// Returns a dynamic reference table for a loaded overlay package.
- const OverlayDynamicRefTable GetOverlayDynamicRefTable(
- uint8_t target_assigned_package_id) const {
+ const OverlayDynamicRefTable GetOverlayDynamicRefTable(uint8_t target_assigned_package_id) const {
return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id);
}
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index bfd564c258ee..168a863df2bc 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -43,8 +43,19 @@
namespace android {
-constexpr const static uint32_t kIdmapMagic = 0x504D4449u;
-constexpr const static uint32_t kIdmapCurrentVersion = 0x00000007u;
+constexpr const uint32_t kIdmapMagic = 0x504D4449u;
+constexpr const uint32_t kIdmapCurrentVersion = 0x00000008u;
+
+// This must never change.
+constexpr const uint32_t kFabricatedOverlayMagic = 0x4f525246; // FRRO (big endian)
+
+// The version should only be changed when a backwards-incompatible change must be made to the
+// fabricated overlay file format. Old fabricated overlays must be migrated to the new file format
+// to prevent losing fabricated overlay data.
+constexpr const uint32_t kFabricatedOverlayCurrentVersion = 1;
+
+// Returns whether or not the path represents a fabricated overlay.
+bool IsFabricatedOverlay(const std::string& path);
/**
* In C++11, char16_t is defined as *at least* 16 bits. We do a lot of
diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap
index 723413c3cea8..88eadccb38cf 100644
--- a/libs/androidfw/tests/data/overlay/overlay.idmap
+++ b/libs/androidfw/tests/data/overlay/overlay.idmap
Binary files differ