Loading libs/androidfw/include/androidfw/ResourceTypes.h +13 −0 Original line number Original line Diff line number Diff line Loading @@ -263,6 +263,8 @@ enum { RES_TABLE_OVERLAYABLE_POLICY_TYPE = 0x0205, RES_TABLE_OVERLAYABLE_POLICY_TYPE = 0x0205, RES_TABLE_STAGED_ALIAS_TYPE = 0x0206, RES_TABLE_STAGED_ALIAS_TYPE = 0x0206, RES_TABLE_FLAGGED = 0x0207, RES_TABLE_FLAGGED = 0x0207, RES_TABLE_FLAG_LIST = 0x0208, }; }; /** /** Loading Loading @@ -1600,6 +1602,7 @@ union ResTable_sparseTypeEntry { static_assert(sizeof(ResTable_sparseTypeEntry) == sizeof(uint32_t), static_assert(sizeof(ResTable_sparseTypeEntry) == sizeof(uint32_t), "ResTable_sparseTypeEntry must be 4 bytes in size"); "ResTable_sparseTypeEntry must be 4 bytes in size"); /** /** * A container for other chunks all of whose values are behind a given flag. * A container for other chunks all of whose values are behind a given flag. * * Loading @@ -1621,6 +1624,16 @@ struct ResTable_flagged { uint8_t padding[3]; uint8_t padding[3]; }; }; /** * A chunk that contains a list of the names of all the read/write flags used by the * ResTable_flagged chunks in the file. Specifically, all data after the header is an array of * ResStringPool_ref objects for the flag names in no specific order. References use the global * values stringpool. */ struct ResTable_flag_list { struct ResChunk_header header; }; struct ResTable_map_entry; struct ResTable_map_entry; /** /** Loading tools/aapt2/Debug.cpp +22 −0 Original line number Original line Diff line number Diff line Loading @@ -661,6 +661,9 @@ class ChunkPrinter { case RES_TABLE_FLAGGED: case RES_TABLE_FLAGGED: printer_->Print("[RES_TABLE_FLAGGED]"); printer_->Print("[RES_TABLE_FLAGGED]"); break; break; case RES_TABLE_FLAG_LIST: printer_->Print("[RES_TABLE_FLAG_LIST]"); break; default: default: break; break; } } Loading Loading @@ -941,6 +944,21 @@ class ChunkPrinter { return success; return success; } } bool PrintFlagList(const ResTable_flag_list* chunk) { auto index = reinterpret_cast<const uint32_t*>(reinterpret_cast<const char*>(chunk) + chunk->header.headerSize); size_t count = (chunk->header.size - chunk->header.headerSize) / sizeof(uint32_t); printer_->Println(StringPrintf(" count: %zu", count)); printer_->Indent(); for (int i = 0; i < count; i++) { auto id = android::util::DeviceToHost32(index[i]); const auto flag_name = android::util::GetString(value_pool_, id); printer_->Println(StringPrintf("[%d] flag name: %u '%s'", i, id, flag_name.c_str())); } printer_->Undent(); return true; } bool PrintChunk(ResChunkPullParser&& parser) { bool PrintChunk(ResChunkPullParser&& parser) { while (ResChunkPullParser::IsGoodEvent(parser.Next())) { while (ResChunkPullParser::IsGoodEvent(parser.Next())) { auto chunk = parser.chunk(); auto chunk = parser.chunk(); Loading Loading @@ -973,6 +991,10 @@ class ChunkPrinter { PrintFlagged(reinterpret_cast<const ResTable_flagged*>(chunk)); PrintFlagged(reinterpret_cast<const ResTable_flagged*>(chunk)); break; break; case RES_TABLE_FLAG_LIST: PrintFlagList(reinterpret_cast<const ResTable_flag_list*>(chunk)); break; default: default: printer_->Print("\n"); printer_->Print("\n"); break; break; Loading tools/aapt2/format/binary/TableFlattener.cpp +12 −0 Original line number Original line Diff line number Diff line Loading @@ -645,6 +645,18 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { android::StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool, android::StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool, context->GetDiagnostics()); context->GetDiagnostics()); if (!flag_map.empty()) { android::BigBuffer flag_buffer(1024); ChunkWriter flag_writer(&flag_buffer); ResTable_flag_list* flag_list = flag_writer.StartChunk<ResTable_flag_list>(RES_TABLE_FLAG_LIST); uint32_t* indices = flag_writer.NextBlock<uint32_t>(flag_map.size()); for (const auto& [_, ref] : flag_map) { *indices++ = android::util::HostToDevice32(ref.index()); } flag_writer.Finish(); table_writer.buffer()->AppendBuffer(std::move(flag_buffer)); } android::BigBuffer package_buffer(1024); android::BigBuffer package_buffer(1024); // Flatten each package. // Flatten each package. Loading tools/aapt2/link/FlaggedResources_test.cpp +7 −2 Original line number Original line Diff line number Diff line Loading @@ -244,13 +244,18 @@ TEST_F(FlaggedResourcesTest, ReadWriteFlagChunk) { std::string output; std::string output; DumpChunksToString(loaded_apk.get(), &output); DumpChunksToString(loaded_apk.get(), &output); std::string expected = std::string expected1 = R"OUT_END( [RES_TABLE_FLAG_LIST] chunkSize: 12 headerSize: 8 count: 1 [0] flag name: 1 'test.package.rwFlag')OUT_END"; ASSERT_TRUE(output.contains(expected1)); std::string expected2 = R"OUT_END( [RES_TABLE_FLAGGED] chunkSize: 120 headerSize: 16 name: test.package.rwFlag negated: false R"OUT_END( [RES_TABLE_FLAGGED] chunkSize: 120 headerSize: 16 name: test.package.rwFlag negated: false [ResTable_type] chunkSize: 104 headerSize: 84 id: 0x01 name: string flags: 0x00 (DENSE) entryCount: 1 entryStart: 88 config: [ResTable_type] chunkSize: 104 headerSize: 84 id: 0x01 name: string flags: 0x00 (DENSE) entryCount: 1 entryStart: 88 config: [ResTable_entry] id: 0x0000 name: text1 keyIndex: 0 size: 8 flags: 0x0000 [ResTable_entry] id: 0x0000 name: text1 keyIndex: 0 size: 8 flags: 0x0000 [Res_value] size: 8 dataType: 0x03 data: 0x00000000 ("foobar"))OUT_END"; [Res_value] size: 8 dataType: 0x03 data: 0x00000000 ("foobar"))OUT_END"; ASSERT_TRUE(output.contains(expected)); ASSERT_TRUE(output.contains(expected2)); } } } // namespace aapt } // namespace aapt Loading
libs/androidfw/include/androidfw/ResourceTypes.h +13 −0 Original line number Original line Diff line number Diff line Loading @@ -263,6 +263,8 @@ enum { RES_TABLE_OVERLAYABLE_POLICY_TYPE = 0x0205, RES_TABLE_OVERLAYABLE_POLICY_TYPE = 0x0205, RES_TABLE_STAGED_ALIAS_TYPE = 0x0206, RES_TABLE_STAGED_ALIAS_TYPE = 0x0206, RES_TABLE_FLAGGED = 0x0207, RES_TABLE_FLAGGED = 0x0207, RES_TABLE_FLAG_LIST = 0x0208, }; }; /** /** Loading Loading @@ -1600,6 +1602,7 @@ union ResTable_sparseTypeEntry { static_assert(sizeof(ResTable_sparseTypeEntry) == sizeof(uint32_t), static_assert(sizeof(ResTable_sparseTypeEntry) == sizeof(uint32_t), "ResTable_sparseTypeEntry must be 4 bytes in size"); "ResTable_sparseTypeEntry must be 4 bytes in size"); /** /** * A container for other chunks all of whose values are behind a given flag. * A container for other chunks all of whose values are behind a given flag. * * Loading @@ -1621,6 +1624,16 @@ struct ResTable_flagged { uint8_t padding[3]; uint8_t padding[3]; }; }; /** * A chunk that contains a list of the names of all the read/write flags used by the * ResTable_flagged chunks in the file. Specifically, all data after the header is an array of * ResStringPool_ref objects for the flag names in no specific order. References use the global * values stringpool. */ struct ResTable_flag_list { struct ResChunk_header header; }; struct ResTable_map_entry; struct ResTable_map_entry; /** /** Loading
tools/aapt2/Debug.cpp +22 −0 Original line number Original line Diff line number Diff line Loading @@ -661,6 +661,9 @@ class ChunkPrinter { case RES_TABLE_FLAGGED: case RES_TABLE_FLAGGED: printer_->Print("[RES_TABLE_FLAGGED]"); printer_->Print("[RES_TABLE_FLAGGED]"); break; break; case RES_TABLE_FLAG_LIST: printer_->Print("[RES_TABLE_FLAG_LIST]"); break; default: default: break; break; } } Loading Loading @@ -941,6 +944,21 @@ class ChunkPrinter { return success; return success; } } bool PrintFlagList(const ResTable_flag_list* chunk) { auto index = reinterpret_cast<const uint32_t*>(reinterpret_cast<const char*>(chunk) + chunk->header.headerSize); size_t count = (chunk->header.size - chunk->header.headerSize) / sizeof(uint32_t); printer_->Println(StringPrintf(" count: %zu", count)); printer_->Indent(); for (int i = 0; i < count; i++) { auto id = android::util::DeviceToHost32(index[i]); const auto flag_name = android::util::GetString(value_pool_, id); printer_->Println(StringPrintf("[%d] flag name: %u '%s'", i, id, flag_name.c_str())); } printer_->Undent(); return true; } bool PrintChunk(ResChunkPullParser&& parser) { bool PrintChunk(ResChunkPullParser&& parser) { while (ResChunkPullParser::IsGoodEvent(parser.Next())) { while (ResChunkPullParser::IsGoodEvent(parser.Next())) { auto chunk = parser.chunk(); auto chunk = parser.chunk(); Loading Loading @@ -973,6 +991,10 @@ class ChunkPrinter { PrintFlagged(reinterpret_cast<const ResTable_flagged*>(chunk)); PrintFlagged(reinterpret_cast<const ResTable_flagged*>(chunk)); break; break; case RES_TABLE_FLAG_LIST: PrintFlagList(reinterpret_cast<const ResTable_flag_list*>(chunk)); break; default: default: printer_->Print("\n"); printer_->Print("\n"); break; break; Loading
tools/aapt2/format/binary/TableFlattener.cpp +12 −0 Original line number Original line Diff line number Diff line Loading @@ -645,6 +645,18 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) { android::StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool, android::StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool, context->GetDiagnostics()); context->GetDiagnostics()); if (!flag_map.empty()) { android::BigBuffer flag_buffer(1024); ChunkWriter flag_writer(&flag_buffer); ResTable_flag_list* flag_list = flag_writer.StartChunk<ResTable_flag_list>(RES_TABLE_FLAG_LIST); uint32_t* indices = flag_writer.NextBlock<uint32_t>(flag_map.size()); for (const auto& [_, ref] : flag_map) { *indices++ = android::util::HostToDevice32(ref.index()); } flag_writer.Finish(); table_writer.buffer()->AppendBuffer(std::move(flag_buffer)); } android::BigBuffer package_buffer(1024); android::BigBuffer package_buffer(1024); // Flatten each package. // Flatten each package. Loading
tools/aapt2/link/FlaggedResources_test.cpp +7 −2 Original line number Original line Diff line number Diff line Loading @@ -244,13 +244,18 @@ TEST_F(FlaggedResourcesTest, ReadWriteFlagChunk) { std::string output; std::string output; DumpChunksToString(loaded_apk.get(), &output); DumpChunksToString(loaded_apk.get(), &output); std::string expected = std::string expected1 = R"OUT_END( [RES_TABLE_FLAG_LIST] chunkSize: 12 headerSize: 8 count: 1 [0] flag name: 1 'test.package.rwFlag')OUT_END"; ASSERT_TRUE(output.contains(expected1)); std::string expected2 = R"OUT_END( [RES_TABLE_FLAGGED] chunkSize: 120 headerSize: 16 name: test.package.rwFlag negated: false R"OUT_END( [RES_TABLE_FLAGGED] chunkSize: 120 headerSize: 16 name: test.package.rwFlag negated: false [ResTable_type] chunkSize: 104 headerSize: 84 id: 0x01 name: string flags: 0x00 (DENSE) entryCount: 1 entryStart: 88 config: [ResTable_type] chunkSize: 104 headerSize: 84 id: 0x01 name: string flags: 0x00 (DENSE) entryCount: 1 entryStart: 88 config: [ResTable_entry] id: 0x0000 name: text1 keyIndex: 0 size: 8 flags: 0x0000 [ResTable_entry] id: 0x0000 name: text1 keyIndex: 0 size: 8 flags: 0x0000 [Res_value] size: 8 dataType: 0x03 data: 0x00000000 ("foobar"))OUT_END"; [Res_value] size: 8 dataType: 0x03 data: 0x00000000 ("foobar"))OUT_END"; ASSERT_TRUE(output.contains(expected)); ASSERT_TRUE(output.contains(expected2)); } } } // namespace aapt } // namespace aapt