From a761f3325ecada28ba5c7a6697d9183fc4b30f92 Mon Sep 17 00:00:00 2001 From: Jeremy Meyer Date: Fri, 21 Oct 2022 17:42:14 +0000 Subject: [PATCH] implement drawable frros Test: unit tests Bug: 251283316 Change-Id: Iead53711c54596c3787eeba6dcf9ced129f94426 --- cmds/idmap2/Android.bp | 1 + cmds/idmap2/idmap2d/Idmap2Service.cpp | 5 ++ .../os/FabricatedOverlayInternalEntry.aidl | 1 + .../idmap2/include/idmap2/FabricatedOverlay.h | 16 ++++ cmds/idmap2/include/idmap2/ResourceUtils.h | 2 + cmds/idmap2/libidmap2/FabricatedOverlay.cpp | 78 ++++++++++++++---- cmds/idmap2/tests/FabricatedOverlayTests.cpp | 26 ++++-- cmds/idmap2/tests/IdmapTests.cpp | 19 ++++- cmds/idmap2/tests/R.h | 35 ++++---- cmds/idmap2/tests/RawPrintVisitorTests.cpp | 16 ++-- cmds/idmap2/tests/ResourceMappingTests.cpp | 27 +++++- cmds/idmap2/tests/TestConstants.h | 4 +- .../data/overlay/res/drawable/android.png | Bin 0 -> 8341 bytes cmds/idmap2/tests/data/target/build | 6 +- .../tests/data/target/res/drawable/dr1.png | Bin 0 -> 546 bytes .../data/target/res/values/overlayable.xml | 1 + .../data/target/target-no-overlayable.apk | Bin 2391 -> 2761 bytes cmds/idmap2/tests/data/target/target.apk | Bin 5201 -> 5571 bytes .../android/content/om/FabricatedOverlay.java | 19 +++++ .../android/content/res/ResourcesImpl.java | 31 ++++++- .../include/androidfw/ResourceTypes.h | 2 +- .../server/om/OverlayManagerShellCommand.java | 24 ++++-- 22 files changed, 248 insertions(+), 65 deletions(-) create mode 100644 cmds/idmap2/tests/data/overlay/res/drawable/android.png create mode 100644 cmds/idmap2/tests/data/target/res/drawable/dr1.png diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index 4f8faca59e4ce..7a08cbdcddd4a 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -222,6 +222,7 @@ cc_test { }, data: [ "tests/data/**/*.apk", + "tests/data/**/*.png", ], compile_multilib: "first", test_options: { diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index 44311648da80e..10947dc90a76e 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -39,6 +39,7 @@ #include "idmap2/PrettyPrintVisitor.h" #include "idmap2/Result.h" #include "idmap2/SysTrace.h" +#include using android::base::StringPrintf; using android::binder::Status; @@ -238,6 +239,9 @@ Status Idmap2Service::createFabricatedOverlay( if (res.dataType == Res_value::TYPE_STRING) { builder.SetResourceValue(res.resourceName, res.dataType, res.stringData.value(), res.configuration.value_or(std::string())); + } else if (res.binaryData.has_value()) { + builder.SetResourceValue(res.resourceName, res.binaryData->get(), + res.configuration.value_or(std::string())); } else { builder.SetResourceValue(res.resourceName, res.dataType, res.data, res.configuration.value_or(std::string())); @@ -264,6 +268,7 @@ Status Idmap2Service::createFabricatedOverlay( file_name.c_str(), kMaxFileNameLength)); } } while (std::filesystem::exists(path)); + builder.setFrroPath(path); const uid_t uid = IPCThreadState::self()->getCallingUid(); if (!UidHasWriteAccessToPath(uid, path)) { diff --git a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl index c773e112997de..3ad6d58e82530 100644 --- a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl +++ b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl @@ -24,5 +24,6 @@ parcelable FabricatedOverlayInternalEntry { int dataType; int data; @nullable @utf8InCpp String stringData; + @nullable ParcelFileDescriptor binaryData; @nullable @utf8InCpp String configuration; } \ No newline at end of file diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h index 05b0618131c90..9f57710edb0b0 100644 --- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h +++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h @@ -28,6 +28,7 @@ #include "idmap2/ResourceContainer.h" #include "idmap2/Result.h" +#include namespace android::idmap2 { @@ -45,6 +46,15 @@ struct FabricatedOverlay { const std::string& data_string_value, const std::string& configuration); + Builder& SetResourceValue(const std::string& resource_name, + std::optional&& binary_value, + const std::string& configuration); + + inline Builder& setFrroPath(std::string frro_path) { + frro_path_ = std::move(frro_path); + return *this; + } + WARN_UNUSED Result Build(); private: @@ -53,6 +63,7 @@ struct FabricatedOverlay { DataType data_type; DataValue data_value; std::string data_string_value; + std::optional data_binary_value; std::string configuration; }; @@ -60,6 +71,7 @@ struct FabricatedOverlay { std::string name_; std::string target_package_name_; std::string target_overlayable_; + std::string frro_path_; std::vector entries_; }; @@ -79,10 +91,14 @@ struct FabricatedOverlay { explicit FabricatedOverlay(pb::FabricatedOverlay&& overlay, std::string&& string_pool_data_, + std::vector binary_files_, + off_t total_binary_bytes_, std::optional crc_from_disk = {}); pb::FabricatedOverlay overlay_pb_; std::string string_pool_data_; + std::vector binary_files_; + uint32_t total_binary_bytes_; std::optional crc_from_disk_; mutable std::optional data_; diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h index af4dd8960cc32..2214a83bd2da5 100644 --- a/cmds/idmap2/include/idmap2/ResourceUtils.h +++ b/cmds/idmap2/include/idmap2/ResourceUtils.h @@ -19,6 +19,7 @@ #include #include +#include #include "androidfw/AssetManager2.h" #include "idmap2/Result.h" @@ -41,6 +42,7 @@ struct TargetValue { DataType data_type; DataValue data_value; std::string data_string_value; + std::optional data_binary_value; }; struct TargetValueWithConfig { diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp index bde9b0be43615..d517e29f3369e 100644 --- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp +++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp @@ -16,6 +16,10 @@ #include "idmap2/FabricatedOverlay.h" +#include // umask +#include // umask + +#include #include #include #include @@ -51,9 +55,13 @@ void Write32(std::ostream& stream, uint32_t value) { FabricatedOverlay::FabricatedOverlay(pb::FabricatedOverlay&& overlay, std::string&& string_pool_data, + std::vector binary_files, + off_t total_binary_bytes, std::optional crc_from_disk) : overlay_pb_(std::forward(overlay)), string_pool_data_(std::move(string_pool_data)), + binary_files_(std::move(binary_files)), + total_binary_bytes_(total_binary_bytes), crc_from_disk_(crc_from_disk) { } @@ -72,14 +80,23 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetOverlayable(const std FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue( const std::string& resource_name, uint8_t data_type, uint32_t data_value, const std::string& configuration) { - entries_.emplace_back(Entry{resource_name, data_type, data_value, "", configuration}); + entries_.emplace_back( + Entry{resource_name, data_type, data_value, "", std::nullopt, configuration}); return *this; } FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue( const std::string& resource_name, uint8_t data_type, const std::string& data_string_value, const std::string& configuration) { - entries_.emplace_back(Entry{resource_name, data_type, 0, data_string_value, configuration}); + entries_.emplace_back( + Entry{resource_name, data_type, 0, data_string_value, std::nullopt, configuration}); + return *this; +} + +FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue( + const std::string& resource_name, std::optional&& binary_value, + const std::string& configuration) { + entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value, configuration}); return *this; } @@ -135,7 +152,7 @@ Result FabricatedOverlay::Builder::Build() { } value->second = TargetValue{res_entry.data_type, res_entry.data_value, - res_entry.data_string_value}; + res_entry.data_string_value, res_entry.data_binary_value}; } pb::FabricatedOverlay overlay_pb; @@ -144,6 +161,11 @@ Result FabricatedOverlay::Builder::Build() { overlay_pb.set_target_package_name(target_package_name_); overlay_pb.set_target_overlayable(target_overlayable_); + std::vector binary_files; + size_t total_binary_bytes = 0; + // 16 for the number of bytes in the frro file before the binary data + const size_t FRRO_HEADER_SIZE = 16; + for (auto& package : package_map) { auto package_pb = overlay_pb.add_packages(); package_pb->set_name(package.first); @@ -162,6 +184,20 @@ Result FabricatedOverlay::Builder::Build() { if (value.second.data_type == Res_value::TYPE_STRING) { auto ref = string_pool.MakeRef(value.second.data_string_value); pb_value->set_data_value(ref.index()); + } else if (value.second.data_binary_value.has_value()) { + pb_value->set_data_type(Res_value::TYPE_STRING); + struct stat s; + if (fstat(value.second.data_binary_value->get(), &s) == -1) { + return Error("unable to get size of binary file: %d", errno); + } + std::string uri + = StringPrintf("frro:/%s?offset=%d&size=%d", frro_path_.c_str(), + static_cast (FRRO_HEADER_SIZE + total_binary_bytes), + static_cast (s.st_size)); + total_binary_bytes += s.st_size; + binary_files.emplace_back(value.second.data_binary_value->get()); + auto ref = string_pool.MakeRef(std::move(uri)); + pb_value->set_data_value(ref.index()); } else { pb_value->set_data_value(value.second.data_value); } @@ -169,10 +205,10 @@ Result FabricatedOverlay::Builder::Build() { } } } - android::BigBuffer string_buffer(kBufferSize); android::StringPool::FlattenUtf8(&string_buffer, string_pool, nullptr); - return FabricatedOverlay(std::move(overlay_pb), string_buffer.to_string()); + return FabricatedOverlay(std::move(overlay_pb), string_buffer.to_string(), + std::move(binary_files), total_binary_bytes); } Result FabricatedOverlay::FromBinaryStream(std::istream& stream) { @@ -190,7 +226,7 @@ Result FabricatedOverlay::FromBinaryStream(std::istream& stre return Error("Failed to read fabricated overlay version."); } - if (version != 1 && version != 2) { + if (version < 1 || version > 3) { return Error("Invalid fabricated overlay version '%u'.", version); } @@ -201,7 +237,14 @@ Result FabricatedOverlay::FromBinaryStream(std::istream& stre pb::FabricatedOverlay overlay{}; std::string sp_data; - if (version == 2) { + uint32_t total_binary_bytes; + if (version == 3) { + if (!Read32(stream, &total_binary_bytes)) { + return Error("Failed read total binary bytes."); + } + stream.seekg(total_binary_bytes, std::istream::cur); + } + if (version >= 2) { uint32_t sp_size; if (!Read32(stream, &sp_size)) { return Error("Failed read string pool size."); @@ -211,20 +254,15 @@ Result FabricatedOverlay::FromBinaryStream(std::istream& stre return Error("Failed to read string pool."); } sp_data = buf; - - if (!overlay.ParseFromIstream(&stream)) { - return Error("Failed read fabricated overlay proto."); - } - } else { - if (!overlay.ParseFromIstream(&stream)) { - return Error("Failed read fabricated overlay proto."); - } + } + 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), std::move(sp_data), + return FabricatedOverlay(std::move(overlay), std::move(sp_data), {}, total_binary_bytes, version == kFabricatedOverlayCurrentVersion ? std::optional(crc) : std::nullopt); @@ -274,6 +312,14 @@ Result FabricatedOverlay::ToBinaryStream(std::ostream& stream) const { Write32(stream, kFabricatedOverlayMagic); Write32(stream, kFabricatedOverlayCurrentVersion); Write32(stream, (*data)->pb_crc); + Write32(stream, total_binary_bytes_); + std::string file_contents; + for (const android::base::borrowed_fd fd : binary_files_) { + if (!ReadFdToString(fd, &file_contents)) { + return Error("Failed to read binary file data."); + } + stream.write(file_contents.data(), file_contents.length()); + } Write32(stream, (*data)->sp_data.length()); stream.write((*data)->sp_data.data(), (*data)->sp_data.length()); if (stream.bad()) { diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp index e804c879ee82b..e13a0eb5d4884 100644 --- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp +++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp @@ -17,6 +17,7 @@ #include #include #include +#include "TestHelpers.h" #include #include @@ -41,6 +42,10 @@ TEST(FabricatedOverlayTests, OverlayInfo) { } TEST(FabricatedOverlayTests, SetResourceValue) { + auto path = GetTestDataPath() + "/overlay/res/drawable/android.png"; + auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC)); + ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path; + auto overlay = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target") .SetResourceValue( @@ -54,6 +59,8 @@ TEST(FabricatedOverlayTests, SetResourceValue) { Res_value::TYPE_STRING, "foobar", "en-rUS-normal-xxhdpi-v21") + .SetResourceValue("com.example.target:drawable/dr1", fd, "port-xxhdpi-v7") + .setFrroPath("/foo/bar/biz.frro") .Build(); ASSERT_TRUE(overlay); auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay)); @@ -67,19 +74,28 @@ TEST(FabricatedOverlayTests, SetResourceValue) { auto pairs = container->GetOverlayData(*info); ASSERT_TRUE(pairs); - ASSERT_EQ(4U, pairs->pairs.size()); + ASSERT_EQ(5U, pairs->pairs.size()); auto string_pool = ResStringPool(pairs->string_pool_data->data.get(), pairs->string_pool_data->data_length, false); auto& it = pairs->pairs[0]; - ASSERT_EQ("com.example.target:integer/int1", it.resource_name); + ASSERT_EQ("com.example.target:drawable/dr1", it.resource_name); auto entry = std::get_if(&it.value); ASSERT_NE(nullptr, entry); + ASSERT_EQ(std::string("frro://foo/bar/biz.frro?offset=16&size=8341"), + string_pool.string8At(entry->value.data_value).value_or("")); + ASSERT_EQ(Res_value::TYPE_STRING, entry->value.data_type); + ASSERT_EQ("port-xxhdpi-v7", entry->config); + + it = pairs->pairs[1]; + ASSERT_EQ("com.example.target:integer/int1", it.resource_name); + entry = std::get_if(&it.value); + ASSERT_NE(nullptr, entry); ASSERT_EQ(1U, entry->value.data_value); ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->value.data_type); ASSERT_EQ("port", entry->config); - it = pairs->pairs[1]; + it = pairs->pairs[2]; ASSERT_EQ("com.example.target:string/int3", it.resource_name); entry = std::get_if(&it.value); ASSERT_NE(nullptr, entry); @@ -87,7 +103,7 @@ TEST(FabricatedOverlayTests, SetResourceValue) { ASSERT_EQ(Res_value::TYPE_REFERENCE, entry->value.data_type); ASSERT_EQ("xxhdpi-v7", entry->config); - it = pairs->pairs[2]; + it = pairs->pairs[3]; ASSERT_EQ("com.example.target:string/string1", it.resource_name); entry = std::get_if(&it.value); ASSERT_NE(nullptr, entry); @@ -95,7 +111,7 @@ TEST(FabricatedOverlayTests, SetResourceValue) { ASSERT_EQ(std::string("foobar"), string_pool.string8At(entry->value.data_value).value_or("")); ASSERT_EQ("en-rUS-normal-xxhdpi-v21", entry->config); - it = pairs->pairs[3]; + it = pairs->pairs[4]; ASSERT_EQ("com.example.target.split:integer/int2", it.resource_name); entry = std::get_if(&it.value); ASSERT_NE(nullptr, entry); diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 7b7dc17deea4d..b473f26b2230d 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -260,11 +260,17 @@ TEST(IdmapTests, FabricatedOverlay) { auto target = TargetResourceContainer::FromPath(target_apk_path); ASSERT_TRUE(target); + auto path = GetTestDataPath() + "/overlay/res/drawable/android.png"; + auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC)); + ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path; + auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target") .SetOverlayable("TestResources") .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "land-xxhdpi-v7") .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "land") .SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "xxhdpi-v7") + .SetResourceValue("drawable/dr1", fd, "port-xxhdpi-v7") + .setFrroPath("/foo/bar/biz.frro") .Build(); ASSERT_TRUE(frro); @@ -293,14 +299,19 @@ TEST(IdmapTests, FabricatedOverlay) { auto string_pool_data = data->GetStringPoolData(); auto string_pool = ResStringPool(string_pool_data.data(), string_pool_data.size(), false); + std::u16string expected_uri = u"frro://foo/bar/biz.frro?offset=16&size=8341"; + uint32_t uri_index + = string_pool.indexOfString(expected_uri.data(), expected_uri.length()).value_or(-1); const auto& target_inline_entries = data->GetTargetInlineEntries(); - ASSERT_EQ(target_inline_entries.size(), 3U); - ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1, "land-xxhdpi-v7", + ASSERT_EQ(target_inline_entries.size(), 4U); + ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::drawable::dr1, "port-xxhdpi-v7", + Res_value::TYPE_STRING, uri_index); + ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::integer::int1, "land-xxhdpi-v7", Res_value::TYPE_INT_DEC, 2U); - ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1, "land", + ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[2], R::target::string::str1, "land", Res_value::TYPE_REFERENCE, 0x7f010000); - ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[2], R::target::string::str2, "xxhdpi-v7", + ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[3], R::target::string::str2, "xxhdpi-v7", Res_value::TYPE_STRING, (uint32_t) (string_pool.indexOfString(u"foobar", 6)).value_or(-1)); } diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h index ad998b9a7a4c9..80c062d926404 100644 --- a/cmds/idmap2/tests/R.h +++ b/cmds/idmap2/tests/R.h @@ -26,24 +26,27 @@ namespace android::idmap2 { // clang-format off namespace R::target { namespace integer { // NOLINT(runtime/indentation_namespace) - constexpr ResourceId int1 = 0x7f010000; + constexpr ResourceId int1 = 0x7f020000; + } + namespace drawable { + constexpr ResourceId dr1 = 0x7f010000; } namespace string { // NOLINT(runtime/indentation_namespace) - constexpr ResourceId not_overlayable = 0x7f020003; - constexpr ResourceId other = 0x7f020004; - constexpr ResourceId policy_actor = 0x7f020005; - constexpr ResourceId policy_config_signature = 0x7f020006; - constexpr ResourceId policy_odm = 0x7f020007; - constexpr ResourceId policy_oem = 0x7f020008; - constexpr ResourceId policy_product = 0x7f020009; - constexpr ResourceId policy_public = 0x7f02000a; - constexpr ResourceId policy_signature = 0x7f02000b; - constexpr ResourceId policy_system = 0x7f02000c; - constexpr ResourceId policy_system_vendor = 0x7f02000d; - constexpr ResourceId str1 = 0x7f02000e; - constexpr ResourceId str2 = 0x7f02000f; - constexpr ResourceId str3 = 0x7f020010; - constexpr ResourceId str4 = 0x7f020011; + constexpr ResourceId not_overlayable = 0x7f030003; + constexpr ResourceId other = 0x7f030004; + constexpr ResourceId policy_actor = 0x7f030005; + constexpr ResourceId policy_config_signature = 0x7f030006; + constexpr ResourceId policy_odm = 0x7f030007; + constexpr ResourceId policy_oem = 0x7f030008; + constexpr ResourceId policy_product = 0x7f030009; + constexpr ResourceId policy_public = 0x7f03000a; + constexpr ResourceId policy_signature = 0x7f03000b; + constexpr ResourceId policy_system = 0x7f03000c; + constexpr ResourceId policy_system_vendor = 0x7f03000d; + constexpr ResourceId str1 = 0x7f03000e; + constexpr ResourceId str2 = 0x7f03000f; + constexpr ResourceId str3 = 0x7f030010; + constexpr ResourceId str4 = 0x7f030011; } // namespace string } // namespace R::target diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp index 7112eeb9ea0ce..68164e26f3526 100644 --- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp @@ -79,22 +79,22 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { ASSERT_CONTAINS_REGEX(ADDRESS "00000000 config count", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "00000004 overlay entry count", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "0000000a string pool index offset", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id: integer/int1", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 overlay id: integer/int1", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "7f02000e target id: string/str1", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f03000e target id: string/str1", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f02000b overlay id: string/str1", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "7f020010 target id: string/str3", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f030010 target id: string/str3", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f02000c overlay id: string/str3", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "7f020011 target id: string/str4", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f030011 target id: string/str4", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f02000d overlay id: string/str4", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 overlay id: integer/int1", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id: integer/int1", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f02000b overlay id: string/str1", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "7f02000e target id: string/str1", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f03000e target id: string/str1", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f02000c overlay id: string/str3", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "7f020010 target id: string/str3", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f030010 target id: string/str3", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f02000d overlay id: string/str4", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "7f020011 target id: string/str4", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f030011 target id: string/str4", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "000000b4 string pool size", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "........ string pool", stream.str()); } diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index 016d427e7452f..380e462a3abac 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "R.h" #include "TestConstants.h" #include "TestHelpers.h" @@ -76,7 +77,12 @@ Result MappingExists(const ResourceMapping& mapping, ResourceId target_res auto target_map = mapping.GetTargetToOverlayMap(); auto entry_map = target_map.find(target_resource); if (entry_map == target_map.end()) { - return Error("Failed to find mapping for target resource"); + std::string keys; + for (const auto &pair : target_map) { + keys.append(fmt::format("0x{:x}", pair.first)).append(" "); + } + return Error(R"(Failed to find mapping for target resource "0x%02x": "%s")", + target_resource, keys.c_str()); } auto actual_overlay_resource = std::get_if(&entry_map->second); @@ -108,7 +114,12 @@ Result MappingExists(const ResourceMapping& mapping, const ResourceId& tar auto target_map = mapping.GetTargetToOverlayMap(); auto entry_map = target_map.find(target_resource); if (entry_map == target_map.end()) { - return Error("Failed to find mapping for target resource"); + std::string keys; + for (const auto &pair : target_map) { + keys.append(fmt::format("{:x}", pair.first)).append(" "); + } + return Error(R"(Failed to find mapping for target resource "0x%02x": "%s")", + target_resource, keys.c_str()); } auto config_map = std::get_if(&entry_map->second); @@ -193,11 +204,16 @@ TEST(ResourceMappingTests, InlineResources) { } TEST(ResourceMappingTests, FabricatedOverlay) { + auto path = GetTestDataPath() + "/overlay/res/drawable/android.png"; + auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC)); + ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path; 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, "") .SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "") + .SetResourceValue("drawable/dr1", fd, "") + .setFrroPath("/foo/bar/biz.frro") .Build(); ASSERT_TRUE(frro); @@ -214,11 +230,16 @@ TEST(ResourceMappingTests, FabricatedOverlay) { auto string_pool_data = res.GetStringPoolData(); auto string_pool = ResStringPool(string_pool_data.data(), string_pool_data.size(), false); - ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U); + std::u16string expected_uri = u"frro://foo/bar/biz.frro?offset=16&size=8341"; + uint32_t uri_index + = string_pool.indexOfString(expected_uri.data(), expected_uri.length()).value_or(-1); + + ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U); 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::string::str2, Res_value::TYPE_STRING, (uint32_t) (string_pool.indexOfString(u"foobar", 6)).value_or(-1))); + ASSERT_RESULT(MappingExists(res, R::target::drawable::dr1, Res_value::TYPE_STRING, uri_index)); ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 2U)); } diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h index d5799adf0ec32..794d6221c2c0b 100644 --- a/cmds/idmap2/tests/TestConstants.h +++ b/cmds/idmap2/tests/TestConstants.h @@ -19,8 +19,8 @@ namespace android::idmap2::TestConstants { -constexpr const auto TARGET_CRC = 0x7c2d4719; -constexpr const auto TARGET_CRC_STRING = "7c2d4719"; +constexpr const auto TARGET_CRC = 0xa960a69; +constexpr const auto TARGET_CRC_STRING = "0a960a69"; constexpr const auto OVERLAY_CRC = 0xb71095cf; constexpr const auto OVERLAY_CRC_STRING = "b71095cf"; diff --git a/cmds/idmap2/tests/data/overlay/res/drawable/android.png b/cmds/idmap2/tests/data/overlay/res/drawable/android.png new file mode 100644 index 0000000000000000000000000000000000000000..b7317b0933fbd6b1f61cc4af252b15d39850537b GIT binary patch literal 8341 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 JZPs>;{V&e6Y%Tx* literal 0 HcmV?d00001 diff --git a/cmds/idmap2/tests/data/target/build b/cmds/idmap2/tests/data/target/build index e6df742cc9da2..cd13a7ec1bd81 100755 --- a/cmds/idmap2/tests/data/target/build +++ b/cmds/idmap2/tests/data/target/build @@ -17,5 +17,7 @@ aapt2 link --manifest AndroidManifest.xml -A assets -o target.apk compiled.flata rm compiled.flata aapt2 compile res/values/values.xml -o . -aapt2 link --manifest AndroidManifest.xml -A assets -o target-no-overlayable.apk values_values.arsc.flat -rm values_values.arsc.flat \ No newline at end of file +aapt2 compile res/drawable/dr1.png -o . +aapt2 link --manifest AndroidManifest.xml -A assets -o target-no-overlayable.apk values_values.arsc.flat drawable_dr1.png.flat +rm values_values.arsc.flat +rm drawable_dr1.png.flat diff --git a/cmds/idmap2/tests/data/target/res/drawable/dr1.png b/cmds/idmap2/tests/data/target/res/drawable/dr1.png new file mode 100644 index 0000000000000000000000000000000000000000..1a56e68fd6d295b0149cc78207bc0ad5782f4cb2 GIT binary patch literal 546 zcmV+-0^R+IP)EX>4Tx04R}tkv&MmKpe$iQ$;BiMGJ}uW~fdUL`5963Pq?8YK2xEOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4P#Iyou2NQwVT3N2ziIPS;0dyl(!fKV+m&1xG5G~G56 zv8b3zuZkV72w)h!=s~~CEMrcR;%GU(?&0I>U4&<~KKJM7QZp6teDHam6A8p|ubo~;!6mk{7 z$gzMDG{~+W{11M2Yh@=Vyrf_hXn%2>j}f3_7pPSn=lj@kYA1mI8Mx9L{!$f~`6Rv4 z(85PR_cm~G-O!Xh;Bp5Tcrs*Db|pVeA)5u>&*+=dK;JD8So3 + diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk index cc3491de894d8adf7a5c66723579e48716f9f1bf..680eeb609f8e9e3da913dec6dbb306f2d89dd346 100644 GIT binary patch delta 953 zcmZvbJ!n%=6vxlKFE4rdu9`$!BiKchKuZt@i-T=bOo-I@RY4r`@)D#_s=TCD7b7ly zK|$`|;OOQcg5uz=(80l}f{G~OR-uE?!NLD|IZry|!Y}8XcmDTW?ztx$yVvunM%{`K zmIEHAzV~UIj*V8gW)U(u;CH%{ZQosWTT2}{<%#RdS06OyPo)!M38d4tYULcPVz>-V z-F|uzCQ++QUvM_O?JOy!X#bnv3!JUZ%~xK`H1CEd^S5y-{cOGd5~JgUAIhK@PQA9` zd!6ot>vuiUlnPS8DO9BUa0f4;P-$FLeaqT@yn-%+fp6`p78)3`&HkUD9ZBJQdI{K`y2l=1}{KD+O zTC$ILf;bi(*%FH`xGLvGM|k2uFFN*vm|MbrTw>8(CZ01cAVNw?EJDo2ATPS0udEjx z25OKO9c3j>n-4Ls$W?ikcn814&dD?(^b delta 681 zcmZXSJxc>Y5Qb;>?vlHBIYT7TB5DLvNkmJ*LeN4;6B}EJXFw%rzQjg}f`1_FPf)>L zYr(=oECd_T#t#Sa2J0B90mC+Ehhwb=368l<&htOum=~(MQle}N+K@G>;JnT9-x_}R3 zB0AQ3Fd;6`I(}*U0z5h1AJwte@eta1tq0TPdQZLEe)kpeCRK74gssk12n#~DcGa~5}m@fdUgyT@0dUm0CNUjP6A diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk index 4a58c5e28f4994a3ee32203631c0a1866cfbba16..145e737ca138c7a660eaa7d4495ef38950e77ba6 100644 GIT binary patch delta 1357 zcmZvcUr19?9LLZ7x9!f&%{DD<Xxb5!Bp92{UC^(+BHDFA@0? zH;5=A=&2q85rTS+9)cizDhT=q)k_INfxh+q-kpn=*n!W^@BDt>^E>za&N*Az^Qt|P z9n^Gz76P{;pKRK#Vt?bnT0bn31m&XDRVe4?a^s~UjD4NcmoD7Q4j+$(o5Bc3GXv?9 z=oP|D;?ULmr_hBn>E6-M`}}%LD2gJsKVLn~Xy)i}`dQ!k>;A=C#oIT#9xVL{D1G>V zp@T0L7VCr{wU~hqn3^r;i&kf@Y~@uEaUjGhDiUZ2f!?FI)xNEAd_ z2Wrgz&5$hOU!0eiu-(FZ^jVB4Y|G=g@}4f?=YFaa)u8{jT@3SNR0@Bw@V zKfrIW2L1xpK+|w?LU-;N8_u1;T${$is%qRlVHLKwOGOO@THqmF6jJD9OSdf0o#A#lE+MsTysRlf6Sa^CW&};>$APj0j48%bl*a8wD35@@a zF5>gCK$YB^I(|KUW<_Va=N^~N8sFp==?nUNN2D+0^IelZ!{_4)TqFRW_q;L0lYaMg zWGn@Xuy{^5aTu@gM55;yMpgcF=&iJG=&HTb?4ZJ%gvPx&w-PCJOmUthnwzWqg}6HR zr=U7N6FY{geAA{Tg?F5@tm2H-RhlXnCp#vlt=Y-WnfaOQpuy_m?i!*OTP^X$i+_Aq BpR51? delta 1019 zcmZXTy^9k;7{=e3-OX+`-^oUh%W+W<4n#pj1ih2URU(RTVh|fcNPUux%{8mwKX42d zb{^VTO8gHjEG+zJ#76WQ1(g&wf`~rP?&PxQus>$rXWn^t_nDdJN8hZLuUvFoK@0Hg zls~xar$bd%8^Ix2-`3&lx(KO?lJO|sx;-9_;^TvHJQOYEbV^~pl8)TN-~fxUVLUNU z^~S+>2=>5t@Dn(g@j=NnoEK*1Tyk|+^`__DnmRFoK5wjemHBf4{c3L9#Q3mz;GI+x zv#Xc-KH?InffhIdj)66B4Gh68a2M==$KV-w3EqPD;3N19zJeL}A!05Rexa<^b%~%T zvm3U|P5*{D9aKCGrELao-#iQgrOlJzQNmwhhf7&(^>l*sRu|gOmM!Po~rq7(!(76;VUsp;2M0?i3TC4 zf*PoU255p7h=6BzhJI!>78*UGR>|e@lc^OKT9W<)#nM8Qu1)lFTF+`hPP=0@FQ@Sh ztXF_GzhVe+r(S*9>~}CEv}6#+BXce~s{*qft*7_T{Ej+$Ps~z#W#zwHh$Z`Nrp)#B aGIRc|x}PH7n&y7HTXk{H{y<&h)sVmD!er+F diff --git a/core/java/android/content/om/FabricatedOverlay.java b/core/java/android/content/om/FabricatedOverlay.java index 3ca056097c1f1..dbefa65f5c689 100644 --- a/core/java/android/content/om/FabricatedOverlay.java +++ b/core/java/android/content/om/FabricatedOverlay.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.FabricatedOverlayInternal; import android.os.FabricatedOverlayInternalEntry; +import android.os.ParcelFileDescriptor; import android.text.TextUtils; import com.android.internal.util.Preconditions; @@ -169,6 +170,24 @@ public class FabricatedOverlay { return this; } + /** + * Sets the value of the fabricated overlay + * + * @param resourceName name of the target resource to overlay (in the form + * [package]:type/entry) + * @param value the file descriptor whose contents are the value of the frro + * @param configuration The string representation of the config this overlay is enabled for + */ + public Builder setResourceValue(@NonNull String resourceName, ParcelFileDescriptor value, + String configuration) { + final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); + entry.resourceName = resourceName; + entry.binaryData = value; + entry.configuration = configuration; + mEntries.add(entry); + return this; + } + /** Builds an immutable fabricated overlay. */ public FabricatedOverlay build() { final FabricatedOverlayInternal overlay = new FabricatedOverlayInternal(); diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index ff072916292be..09d24d47cc7aa 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -40,8 +40,10 @@ import android.graphics.drawable.ColorStateListDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.DrawableContainer; import android.icu.text.PluralRules; +import android.net.Uri; import android.os.Build; import android.os.LocaleList; +import android.os.ParcelFileDescriptor; import android.os.Trace; import android.util.AttributeSet; import android.util.DisplayMetrics; @@ -59,6 +61,8 @@ import libcore.util.NativeAllocationRegistry; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; @@ -799,7 +803,21 @@ public class ResourcesImpl { private Drawable decodeImageDrawable(@NonNull AssetInputStream ais, @NonNull Resources wrapper, @NonNull TypedValue value) { ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais, - wrapper, value); + wrapper, value); + try { + return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> { + decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); + }); + } catch (IOException ioe) { + // This is okay. This may be something that ImageDecoder does not + // support, like SVG. + return null; + } + } + + @Nullable + private Drawable decodeImageDrawable(@NonNull FileInputStream fis, @NonNull Resources wrapper) { + ImageDecoder.Source src = ImageDecoder.createSource(wrapper, fis); try { return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> { decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); @@ -860,6 +878,17 @@ public class ResourcesImpl { } else { dr = loadXmlDrawable(wrapper, value, id, density, file); } + } else if (file.startsWith("frro://")) { + Uri uri = Uri.parse(file); + File f = new File('/' + uri.getHost() + uri.getPath()); + ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, + ParcelFileDescriptor.MODE_READ_ONLY); + AssetFileDescriptor afd = new AssetFileDescriptor( + pfd, + Long.parseLong(uri.getQueryParameter("offset")), + Long.parseLong(uri.getQueryParameter("size"))); + FileInputStream is = afd.createInputStream(); + dr = decodeImageDrawable(is, wrapper); } else { final InputStream is = mAssets.openNonAsset( value.assetCookie, file, AssetManager.ACCESS_STREAMING); diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 24628cd36ba5f..c5e381da93541 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -54,7 +54,7 @@ constexpr const uint32_t kFabricatedOverlayMagic = 0x4f525246; // FRRO (big endi // 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 = 2; +constexpr const uint32_t kFabricatedOverlayCurrentVersion = 3; // Returns whether or not the path represents a fabricated overlay. bool IsFabricatedOverlay(const std::string& path); diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java index bb918d594167e..7ec167bf56333 100644 --- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java +++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java @@ -29,6 +29,7 @@ import android.content.res.AssetManager; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Binder; +import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.ShellCommand; @@ -63,7 +64,8 @@ final class OverlayManagerShellCommand extends ShellCommand { private final IOverlayManager mInterface; private static final Map TYPE_MAP = Map.of( "color", TypedValue.TYPE_FIRST_COLOR_INT, - "string", TypedValue.TYPE_STRING); + "string", TypedValue.TYPE_STRING, + "drawable", -1); OverlayManagerShellCommand(@NonNull final Context ctx, @NonNull final IOverlayManager iom) { mContext = ctx; @@ -257,7 +259,7 @@ final class OverlayManagerShellCommand extends ShellCommand { String name = ""; String filename = null; String opt; - String configuration = null; + String config = null; while ((opt = getNextOption()) != null) { switch (opt) { case "--user": @@ -276,7 +278,7 @@ final class OverlayManagerShellCommand extends ShellCommand { filename = getNextArgRequired(); break; case "--config": - configuration = getNextArgRequired(); + config = getNextArgRequired(); break; default: err.println("Error: Unknown option: " + opt); @@ -311,7 +313,9 @@ final class OverlayManagerShellCommand extends ShellCommand { final String resourceName = getNextArgRequired(); final String typeStr = getNextArgRequired(); final String strData = String.join(" ", peekRemainingArgs()); - addOverlayValue(overlayBuilder, resourceName, typeStr, strData, configuration); + if (addOverlayValue(overlayBuilder, resourceName, typeStr, strData, config) != 0) { + return 1; + } } mInterface.commit(new OverlayManagerTransaction.Builder() @@ -368,8 +372,10 @@ final class OverlayManagerShellCommand extends ShellCommand { return 1; } String config = parser.getAttributeValue(null, "config"); - addOverlayValue(overlayBuilder, targetPackage + ':' + target, - overlayType, value, config); + if (addOverlayValue(overlayBuilder, targetPackage + ':' + target, + overlayType, value, config) != 0) { + return 1; + } } } } @@ -383,7 +389,7 @@ final class OverlayManagerShellCommand extends ShellCommand { return 0; } - private void addOverlayValue(FabricatedOverlay.Builder overlayBuilder, + private int addOverlayValue(FabricatedOverlay.Builder overlayBuilder, String resourceName, String typeString, String valueString, String configuration) { final int type; typeString = typeString.toLowerCase(Locale.getDefault()); @@ -398,6 +404,9 @@ final class OverlayManagerShellCommand extends ShellCommand { } if (type == TypedValue.TYPE_STRING) { overlayBuilder.setResourceValue(resourceName, type, valueString, configuration); + } else if (type < 0) { + ParcelFileDescriptor pfd = openFileForSystem(valueString, "r"); + overlayBuilder.setResourceValue(resourceName, pfd, configuration); } else { final int intData; if (valueString.startsWith("0x")) { @@ -407,6 +416,7 @@ final class OverlayManagerShellCommand extends ShellCommand { } overlayBuilder.setResourceValue(resourceName, type, intData, configuration); } + return 0; } private int runEnableExclusive() throws RemoteException {