From 742b11e05d8f0fc2abe058df4c83f890ddeff0e6 Mon Sep 17 00:00:00 2001 From: Brandon Liu Date: Thu, 3 Nov 2022 23:23:28 +0000 Subject: [PATCH] Fix tests affected by sparse.apk Regenerated sparse.apk with latest aapt2 and updated resource qualifier to orientation from sdk version because config sdk version was fully dropped in aapt2. Also added tests with runtime apk generated by Soong build target to make these tests more comprehensive. Applied parameterized test to avoid duplicate code. Bug: b/249370927 Test: Added and verified affected atests pass Change-Id: I94f6758d7862375fe4053f42fe89953d4afa48fd --- libs/androidfw/Android.bp | 2 + libs/androidfw/tests/LoadedArsc_test.cpp | 136 ++++++++++-------- libs/androidfw/tests/ResTable_test.cpp | 68 +++++---- libs/androidfw/tests/SparseEntry_bench.cpp | 67 ++++++--- libs/androidfw/tests/data/sparse/Android.bp | 14 ++ .../tests/data/sparse/AndroidManifest.xml | 1 + libs/androidfw/tests/data/sparse/R.h | 2 +- .../tests/data/sparse/gen_strings.sh | 10 +- .../tests/data/sparse/not_sparse.apk | Bin 62155 -> 62219 bytes .../{values-v26 => values-land}/strings.xml | 2 +- .../{values-v26 => values-land}/values.xml | 0 libs/androidfw/tests/data/sparse/sparse.apk | Bin 59459 -> 59523 bytes 12 files changed, 195 insertions(+), 107 deletions(-) create mode 100644 libs/androidfw/tests/data/sparse/Android.bp rename libs/androidfw/tests/data/sparse/res/{values-v26 => values-land}/strings.xml (99%) rename libs/androidfw/tests/data/sparse/res/{values-v26 => values-land}/values.xml (100%) diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index eb8d26adc7d74..b1f327c94f8eb 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -211,6 +211,8 @@ cc_test { "tests/data/**/*.apk", "tests/data/**/*.arsc", "tests/data/**/*.idmap", + ":FrameworkResourcesSparseTestApp", + ":FrameworkResourcesNotSparseTestApp", ], test_suites: ["device-tests"], } diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index d214e2dfef7bc..c90ec197b5efb 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -71,62 +71,6 @@ TEST(LoadedArscTest, LoadSinglePackageArsc) { ASSERT_TRUE(LoadedPackage::GetEntry(type.type, entry_index).has_value()); } -TEST(LoadedArscTest, LoadSparseEntryApp) { - std::string contents; - ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc", - &contents)); - - std::unique_ptr loaded_arsc = LoadedArsc::Load(contents.data(), - contents.length()); - ASSERT_THAT(loaded_arsc, NotNull()); - - const LoadedPackage* package = - loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9)); - ASSERT_THAT(package, NotNull()); - - const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1; - const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9); - - const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index); - ASSERT_THAT(type_spec, NotNull()); - ASSERT_THAT(type_spec->type_entries.size(), Ge(1u)); - - auto type = type_spec->type_entries[0]; - ASSERT_TRUE(LoadedPackage::GetEntry(type.type, entry_index).has_value()); -} - -TEST(LoadedArscTest, FindSparseEntryApp) { - std::string contents; - ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc", - &contents)); - - std::unique_ptr loaded_arsc = LoadedArsc::Load(contents.data(), - contents.length()); - ASSERT_THAT(loaded_arsc, NotNull()); - - const LoadedPackage* package = - loaded_arsc->GetPackageById(get_package_id(sparse::R::string::only_v26)); - ASSERT_THAT(package, NotNull()); - - const uint8_t type_index = get_type_id(sparse::R::string::only_v26) - 1; - const uint16_t entry_index = get_entry_id(sparse::R::string::only_v26); - - const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index); - ASSERT_THAT(type_spec, NotNull()); - ASSERT_THAT(type_spec->type_entries.size(), Ge(1u)); - - // Ensure that AAPT2 sparsely encoded the v26 config as expected. - auto type_entry = std::find_if( - type_spec->type_entries.begin(), type_spec->type_entries.end(), - [](const TypeSpec::TypeEntry& x) { return x.config.sdkVersion == 26; }); - ASSERT_NE(type_entry, type_spec->type_entries.end()); - ASSERT_NE(type_entry->type->flags & ResTable_type::FLAG_SPARSE, 0); - - // Test fetching a resource with only sparsely encoded configs by name. - auto id = package->FindEntryByName(u"string", u"only_v26"); - ASSERT_EQ(id.value(), fix_package_id(sparse::R::string::only_v26, 0)); -} - TEST(LoadedArscTest, LoadSharedLibrary) { std::string contents; ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc", @@ -404,4 +348,84 @@ TEST(LoadedArscTest, LoadCustomLoader) { // sizeof(Res_value) might not be backwards compatible. // TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); } +class LoadedArscParameterizedTest : + public testing::TestWithParam { +}; + +TEST_P(LoadedArscParameterizedTest, LoadSparseEntryApp) { + std::string contents; + ASSERT_TRUE(ReadFileFromZipToString(GetParam(), "resources.arsc", &contents)); + + std::unique_ptr loaded_arsc = LoadedArsc::Load(contents.data(), + contents.length()); + ASSERT_THAT(loaded_arsc, NotNull()); + + const LoadedPackage* package = + loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9)); + ASSERT_THAT(package, NotNull()); + + const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1; + const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9); + + const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index); + ASSERT_THAT(type_spec, NotNull()); + ASSERT_THAT(type_spec->type_entries.size(), Ge(1u)); + + auto type = type_spec->type_entries[0]; + ASSERT_TRUE(LoadedPackage::GetEntry(type.type, entry_index).has_value()); +} + +TEST_P(LoadedArscParameterizedTest, FindSparseEntryApp) { + std::string contents; + ASSERT_TRUE(ReadFileFromZipToString(GetParam(), "resources.arsc", &contents)); + + std::unique_ptr loaded_arsc = LoadedArsc::Load(contents.data(), + contents.length()); + ASSERT_THAT(loaded_arsc, NotNull()); + + const LoadedPackage* package = + loaded_arsc->GetPackageById(get_package_id(sparse::R::string::only_land)); + ASSERT_THAT(package, NotNull()); + + const uint8_t type_index = get_type_id(sparse::R::string::only_land) - 1; + + const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index); + ASSERT_THAT(type_spec, NotNull()); + ASSERT_THAT(type_spec->type_entries.size(), Ge(1u)); + + // Type Entry with default orientation is not sparse encoded because the ratio of + // populated entries to total entries is above threshold. + // Only find out default locale because Soong build system will introduce pseudo + // locales for the apk generated at runtime. + auto type_entry_default = std::find_if( + type_spec->type_entries.begin(), type_spec->type_entries.end(), + [] (const TypeSpec::TypeEntry& x) { return x.config.orientation == 0 && + x.config.locale == 0; }); + ASSERT_NE(type_entry_default, type_spec->type_entries.end()); + ASSERT_EQ(type_entry_default->type->flags & ResTable_type::FLAG_SPARSE, 0); + + // Type Entry with land orientation is sparse encoded as expected. + // Only find out default locale because Soong build system will introduce pseudo + // locales for the apk generated at runtime. + auto type_entry_land = std::find_if( + type_spec->type_entries.begin(), type_spec->type_entries.end(), + [](const TypeSpec::TypeEntry& x) { return x.config.orientation == + ResTable_config::ORIENTATION_LAND && + x.config.locale == 0; }); + ASSERT_NE(type_entry_land, type_spec->type_entries.end()); + ASSERT_NE(type_entry_land->type->flags & ResTable_type::FLAG_SPARSE, 0); + + // Test fetching a resource with only sparsely encoded configs by name. + auto id = package->FindEntryByName(u"string", u"only_land"); + ASSERT_EQ(id.value(), fix_package_id(sparse::R::string::only_land, 0)); +} + +INSTANTIATE_TEST_SUITE_P( + FrameWorkResourcesLoadedArscTests, + LoadedArscParameterizedTest, + ::testing::Values( + base::GetExecutableDirectory() + "/tests/data/sparse/sparse.apk", + base::GetExecutableDirectory() + "/FrameworkResourcesSparseTestApp.apk" + )); + } // namespace android diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp index 9aeb00c47e63f..fbf70981f2dec 100644 --- a/libs/androidfw/tests/ResTable_test.cpp +++ b/libs/androidfw/tests/ResTable_test.cpp @@ -15,6 +15,7 @@ */ #include "androidfw/ResourceTypes.h" +#include "android-base/file.h" #include #include @@ -41,34 +42,6 @@ TEST(ResTableTest, ShouldLoadSuccessfully) { ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size())); } -TEST(ResTableTest, ShouldLoadSparseEntriesSuccessfully) { - std::string contents; - ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc", - &contents)); - - ResTable table; - ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size())); - - ResTable_config config; - memset(&config, 0, sizeof(config)); - config.sdkVersion = 26; - table.setParameters(&config); - - String16 name(u"com.android.sparse:integer/foo_9"); - uint32_t flags; - uint32_t resid = - table.identifierForName(name.string(), name.size(), nullptr, 0, nullptr, 0, &flags); - ASSERT_NE(0u, resid); - - Res_value val; - ResTable_config selected_config; - ASSERT_GE( - table.getResource(resid, &val, false /*mayBeBag*/, 0u /*density*/, &flags, &selected_config), - 0); - EXPECT_EQ(Res_value::TYPE_INT_DEC, val.dataType); - EXPECT_EQ(900u, val.data); -} - TEST(ResTableTest, SimpleTypeIsRetrievedCorrectly) { std::string contents; ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", @@ -476,4 +449,43 @@ TEST(ResTableTest, TruncatedEncodeLength) { ASSERT_FALSE(invalid_pool->stringAt(invalid_val.data).has_value()); } +class ResTableParameterizedTest : + public testing::TestWithParam { +}; + +TEST_P(ResTableParameterizedTest, ShouldLoadSparseEntriesSuccessfully) { + std::string contents; + ASSERT_TRUE(ReadFileFromZipToString(GetParam(), "resources.arsc", &contents)); + + ResTable table; + ASSERT_EQ(NO_ERROR, table.add(contents.data(), contents.size())); + + ResTable_config config; + memset(&config, 0, sizeof(config)); + config.orientation = ResTable_config::ORIENTATION_LAND; + table.setParameters(&config); + + String16 name(u"com.android.sparse:integer/foo_9"); + uint32_t flags; + uint32_t resid = + table.identifierForName(name.string(), name.size(), nullptr, 0, nullptr, 0, &flags); + ASSERT_NE(0u, resid); + + Res_value val; + ResTable_config selected_config; + ASSERT_GE( + table.getResource(resid, &val, false /*mayBeBag*/, 0u /*density*/, &flags, &selected_config), + 0); + EXPECT_EQ(Res_value::TYPE_INT_DEC, val.dataType); + EXPECT_EQ(900u, val.data); +} + +INSTANTIATE_TEST_SUITE_P( + FrameWorkResourcesResTableTests, + ResTableParameterizedTest, + ::testing::Values( + base::GetExecutableDirectory() + "/tests/data/sparse/sparse.apk", + base::GetExecutableDirectory() + "/FrameworkResourcesSparseTestApp.apk" + )); + } // namespace android diff --git a/libs/androidfw/tests/SparseEntry_bench.cpp b/libs/androidfw/tests/SparseEntry_bench.cpp index c9b4ad8af2780..fffeeb802873d 100644 --- a/libs/androidfw/tests/SparseEntry_bench.cpp +++ b/libs/androidfw/tests/SparseEntry_bench.cpp @@ -16,6 +16,7 @@ #include "androidfw/AssetManager.h" #include "androidfw/ResourceTypes.h" +#include "android-base/file.h" #include "BenchmarkHelpers.h" #include "data/sparse/R.h" @@ -24,40 +25,74 @@ namespace sparse = com::android::sparse; namespace android { +static void BM_SparseEntryGetResourceHelper(const std::vector& paths, + uint32_t resid, benchmark::State& state, void (*GetResourceBenchmarkFunc)( + const std::vector&, const ResTable_config*, + uint32_t, benchmark::State&)){ + ResTable_config config; + memset(&config, 0, sizeof(config)); + config.orientation = ResTable_config::ORIENTATION_LAND; + GetResourceBenchmarkFunc(paths, &config, resid, state); +} + static void BM_SparseEntryGetResourceOldSparse(benchmark::State& state, uint32_t resid) { - ResTable_config config; - memset(&config, 0, sizeof(config)); - config.sdkVersion = 26; - GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/sparse.apk"}, &config, resid, state); + BM_SparseEntryGetResourceHelper({GetTestDataPath() + "/sparse/sparse.apk"}, resid, + state, &GetResourceBenchmarkOld); } BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparse, Small, sparse::R::integer::foo_9); BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparse, Large, sparse::R::string::foo_999); static void BM_SparseEntryGetResourceOldNotSparse(benchmark::State& state, uint32_t resid) { - ResTable_config config; - memset(&config, 0, sizeof(config)); - config.sdkVersion = 26; - GetResourceBenchmarkOld({GetTestDataPath() + "/sparse/not_sparse.apk"}, &config, resid, state); + BM_SparseEntryGetResourceHelper({GetTestDataPath() + "/sparse/not_sparse.apk"}, resid, + state, &GetResourceBenchmarkOld); } BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparse, Small, sparse::R::integer::foo_9); BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparse, Large, sparse::R::string::foo_999); static void BM_SparseEntryGetResourceSparse(benchmark::State& state, uint32_t resid) { - ResTable_config config; - memset(&config, 0, sizeof(config)); - config.sdkVersion = 26; - GetResourceBenchmark({GetTestDataPath() + "/sparse/sparse.apk"}, &config, resid, state); + BM_SparseEntryGetResourceHelper({GetTestDataPath() + "/sparse/sparse.apk"}, resid, + state, &GetResourceBenchmark); } BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparse, Small, sparse::R::integer::foo_9); BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparse, Large, sparse::R::string::foo_999); static void BM_SparseEntryGetResourceNotSparse(benchmark::State& state, uint32_t resid) { - ResTable_config config; - memset(&config, 0, sizeof(config)); - config.sdkVersion = 26; - GetResourceBenchmark({GetTestDataPath() + "/sparse/not_sparse.apk"}, &config, resid, state); + BM_SparseEntryGetResourceHelper({GetTestDataPath() + "/sparse/not_sparse.apk"}, resid, + state, &GetResourceBenchmark); } BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparse, Small, sparse::R::integer::foo_9); BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparse, Large, sparse::R::string::foo_999); +static void BM_SparseEntryGetResourceOldSparseRuntime(benchmark::State& state, uint32_t resid) { + BM_SparseEntryGetResourceHelper({base::GetExecutableDirectory() + + "/FrameworkResourcesSparseTestApp.apk"}, resid, state, + &GetResourceBenchmarkOld); +} +BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparseRuntime, Small, sparse::R::integer::foo_9); +BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldSparseRuntime, Large, sparse::R::string::foo_999); + +static void BM_SparseEntryGetResourceOldNotSparseRuntime(benchmark::State& state, uint32_t resid) { + BM_SparseEntryGetResourceHelper({base::GetExecutableDirectory() + + "/FrameworkResourcesNotSparseTestApp.apk"}, resid, state, + &GetResourceBenchmarkOld); +} +BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparseRuntime, Small, sparse::R::integer::foo_9); +BENCHMARK_CAPTURE(BM_SparseEntryGetResourceOldNotSparseRuntime, Large, sparse::R::string::foo_999); + +static void BM_SparseEntryGetResourceSparseRuntime(benchmark::State& state, uint32_t resid) { + BM_SparseEntryGetResourceHelper({base::GetExecutableDirectory() + + "/FrameworkResourcesSparseTestApp.apk"}, resid, state, + &GetResourceBenchmark); +} +BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparseRuntime, Small, sparse::R::integer::foo_9); +BENCHMARK_CAPTURE(BM_SparseEntryGetResourceSparseRuntime, Large, sparse::R::string::foo_999); + +static void BM_SparseEntryGetResourceNotSparseRuntime(benchmark::State& state, uint32_t resid) { + BM_SparseEntryGetResourceHelper({base::GetExecutableDirectory() + + "/FrameworkResourcesNotSparseTestApp.apk"}, resid, state, + &GetResourceBenchmark); +} +BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparseRuntime, Small, sparse::R::integer::foo_9); +BENCHMARK_CAPTURE(BM_SparseEntryGetResourceNotSparseRuntime, Large, sparse::R::string::foo_999); + } // namespace android diff --git a/libs/androidfw/tests/data/sparse/Android.bp b/libs/androidfw/tests/data/sparse/Android.bp new file mode 100644 index 0000000000000..0fed79e397844 --- /dev/null +++ b/libs/androidfw/tests/data/sparse/Android.bp @@ -0,0 +1,14 @@ +android_test_helper_app { + name: "FrameworkResourcesSparseTestApp", + sdk_version: "current", + min_sdk_version: "32", + aaptflags: [ + "--enable-sparse-encoding", + ], +} + +android_test_helper_app { + name: "FrameworkResourcesNotSparseTestApp", + sdk_version: "current", + min_sdk_version: "32", +} diff --git a/libs/androidfw/tests/data/sparse/AndroidManifest.xml b/libs/androidfw/tests/data/sparse/AndroidManifest.xml index 27911b62447a9..9c23a7227631e 100644 --- a/libs/androidfw/tests/data/sparse/AndroidManifest.xml +++ b/libs/androidfw/tests/data/sparse/AndroidManifest.xml @@ -17,4 +17,5 @@ + diff --git a/libs/androidfw/tests/data/sparse/R.h b/libs/androidfw/tests/data/sparse/R.h index 2492dbf33f4a1..a66e1af150c4a 100644 --- a/libs/androidfw/tests/data/sparse/R.h +++ b/libs/androidfw/tests/data/sparse/R.h @@ -42,7 +42,7 @@ struct R { struct string { enum : uint32_t { foo_999 = 0x7f0203e7, - only_v26 = 0x7f0203e8 + only_land = 0x7f0203e8 }; }; }; diff --git a/libs/androidfw/tests/data/sparse/gen_strings.sh b/libs/androidfw/tests/data/sparse/gen_strings.sh index 4ea5468c7df9f..114ecbb7d8606 100755 --- a/libs/androidfw/tests/data/sparse/gen_strings.sh +++ b/libs/androidfw/tests/data/sparse/gen_strings.sh @@ -1,20 +1,20 @@ #!/bin/bash OUTPUT_default=res/values/strings.xml -OUTPUT_v26=res/values-v26/strings.xml +OUTPUT_land=res/values-land/strings.xml echo "" > $OUTPUT_default -echo "" > $OUTPUT_v26 +echo "" > $OUTPUT_land for i in {0..999} do echo " $i" >> $OUTPUT_default if [ "$(($i % 3))" -eq "0" ] then - echo " $(($i * 10))" >> $OUTPUT_v26 + echo " $(($i * 10))" >> $OUTPUT_land fi done echo "" >> $OUTPUT_default -echo " only v26" >> $OUTPUT_v26 -echo "" >> $OUTPUT_v26 +echo " only land" >> $OUTPUT_land +echo "" >> $OUTPUT_land diff --git a/libs/androidfw/tests/data/sparse/not_sparse.apk b/libs/androidfw/tests/data/sparse/not_sparse.apk index b08a621195c0a4e60981c77591c7a9aaa739446a..4d4d4a8490337c424049b1c3e55f49f4ff1fe5ed 100644 GIT binary patch delta 4626 zcmeHLZETZO6uxcQbgtBeMhBBHH+9YsYqq8t$QUU>AnXIs8XP#6W?yc$UDC3wn8n_S zi!3_GD8>)QAaUw4H~gq>;D|wNP$7(DR#7Cl5ZPQd1qzr&1ia_H?`>||UAX@8&rWjB zdCob{d2ajOyfMGA>lh^5ZV`uRioi(MUyryV=@viRD>}}Zx<`ngR^M81NiKU;v(~vG$9?0E6SFrr zlpXx#)SkwP!M5Dxp6*R~fzj7%udnjtzU^53#AMT??%JbWcNlwurQgmqR<*S@7q#E` zYhmHu-o;}Zj~!l?GDIQ~3wa4Ly^r9kW_TE+=;^K6yTW;H_cb=|y{o zH>MAEypWV$dZFTw_NHMx?Zdt=PN#o4@_E)J!0-IT=+9s}TZ+eM*@t@XaU;L>V4%WO)eD{mF>jkSq^N>fvlqH= z0kR|>->QcxUGacnF~bay7=@+ZIS`1Ngo0|A0TKbjVul$YQGn&&InWY_#MNbaGZ!R0 zRce?45(QZPus}c{BCL}UVUKD>E{NL^L5gy)f~b?hz!dVh{edSYDqZTZ%7e%ZGeDvU z10}W>*`IGrM}!&}Ry=ipVKKuDkSM}H;d(O{Bs>t+Fay)%d@mNq=IS{AoOvw&&Vi7u zxGZnxf`q3^4KqNZ0Lvd12na-kbuuFCQLV@YaXTVNQ4UrRbut*3LLRq2@We!=OC45u z5Sd{HNEBh9#P%Zl^Ns0z3o@jnh&;N_#UmvzCi2IvBl~F>Uzbl-P=nX^i EFJl42g8%>k delta 4556 zcmeBv#(erIbA5m}GYbO{a4;}Tn9n%TL72mhk%57SnSntVDC(G(Qk0*W;+vS4nU-2y zqF0fdGj)=^Ka-=t(fdVmbDSFMxqN+cI$Bv>xVgP^*W~!D$vGj*!Nk7PIosRYzEA#S z{=)sS;uiXoUgX_7`{s6~wQ;qyMv(G^9=@-MOLm1l-c|oVzPWlrL;44{dyc}s+;f`U zH>`~a_BFX2ko>izJ86ma9v{m)A)2e2?OkF&`X&UGcD`A->P1NU4Jn^fac)O0god=w zG(5g0`Oi~Tq)Vq@S>;>B!pN^CDf%Wrm6;`_6=(%xc zZGD*7PT`=iT5-ej`meXo817mp7xS$)eD~Vj{YK8kE7i-*PtJ<|+5ar9viVYX=anOA z3k@wNWEM^On}12YdHI4>d$WIBXUccyt?!roWghtT+B;X9R^{`O-`D57=h9kTyL@xZ zi=AgDUHcWyy6)lYjKp&8(wrYwV#*(ErzAH8<#)@SnKf@e10>)rKw%FG`BlqKT$}QN zfdPd17#JCfQj7CTi;`1|^%9GUlNp#8c)(J?xB*JaFs#}9mT{pmD>HMMk=f?irl-xh zIXLq3aw_A2e1^$|xyoV;plAh0EyxBaVA;GX*N$=W9aA1gsmT{j)hEm3*VLn^Le_!I z1{r|N$H&Ge2X_gK!B7uj5u*vDk{ER$HN>ie*$;LFF`B6D2u);5@fr?{G2wb-)%e)> zdc01Yi5Mn&YaAXUJVdFI$$$qd6#25&3 z1hHx%PKS`_df@gWOW<`el4&r9z=V*^z{N&08+U1erVwwiMjc2EvFc#<4SdsSwR@YJ~>eeq@XBx)_T? zU_!`d;9{ehJz7A*0uM+dhZ$Npp~xYt1F_NhFe7n@6QAd3;|O?~BhKYicf@D`2}>Yg z8b>ODrYaI6i;U!m-w{am<5!5}CzvDf`wXH1Sq(@8nGa&a?MIftrVu0s0?6t>Y;-%gADC5JAK&IfBo^)1Y7My3#k3O@#5M}D(WeV-pn7hGU7 j%eh7s9^~9930 9960 9990 - only v26 + only land diff --git a/libs/androidfw/tests/data/sparse/res/values-v26/values.xml b/libs/androidfw/tests/data/sparse/res/values-land/values.xml similarity index 100% rename from libs/androidfw/tests/data/sparse/res/values-v26/values.xml rename to libs/androidfw/tests/data/sparse/res/values-land/values.xml diff --git a/libs/androidfw/tests/data/sparse/sparse.apk b/libs/androidfw/tests/data/sparse/sparse.apk index 9fd01fbf2941e7569d1c62235fbe38c831845277..0f2d75a62b96a30a9ac994b38fffb994bb83b405 100644 GIT binary patch delta 4622 zcmeHLZETZO6uxcQbgooF(T%wAnXIw85}rgvoAN>E@@dd46%34 zMV2_oC`6PoNI+fYh9A`p98rV?1;fx;M3LY^bYD{jz3GG9CA~Z6nPOhddbIdT=kwQgyglWfYYEGj?&$PZ?45I?>-!}KqpF8y zWjDlKiq1LoQLDvvZ+2r{>Gi9%-3F%4qpP0I? zw)nu$r+3zk_O)az_H?Yx@(;gJbz_+)<1NSXC&o668LmIF_bzj1f6>?R=JJ;2hP>9B zf6dL^)ipo3=J=sSsr7w}&re@4daJT$U_AT4`GIF+^+B6$=t^wc{FA?B_ii8bo|(66 za7|KQ+eTj7w65j9r>`c<_=5-9o7owM)9gb#~1jQrKk9Gy<@Yt6L!&bnUkVy-R1 zKoRxA>)|;WRSc^U0*AdynJe&34F;kN4>+!eE1o*Qu$W;6NEBh9a6K=dXmA)&)8hn`dUy`AU|8|g@fa#J zuK~!CNPN2X&7uuh1Ohkkl7*;%WfMGGi43H?oK;e3m7bH9o)i47S`|@I1#u@LNKp<}5Op#bm_i=6Kk&pvrAr-F zc@UXl21pcPpoI5A`}2*7h)@H=il+`REM}Mi5=9s&T<`zBAl2{BeIowT!H3o4A|BLl z*CTDkuo`vxLR4Qse%t#`y|TH0{`&TBKQSl4$p3@mI~L5G74a8=DxrjKU*d)2=u1IJ F{sqMDzAgX& delta 4548 zcmZp^$b9$$bA5m}GYbO{a4;}Tn9n%TL72mhk%57SnSntVDC(G(Qk0*W;+vS4nU-2y zqF0fdGj)=^Ka-=t(fdVmbDSFMxqN+cI$Bv>xVgP^*W~!D$vGj*!Nk7PIosRYzEA#S z{=)sS;uiXoUgX_7`{s6~wQ;qyMv(G^9=@-MOLm1l-c|oVzPWlrL;44{dyc}s+;f`U zH>`~a_BFX2ko>izJ86ma9v{m)A)2e2?OkF&`X&UGcD`A->P1NU4Jn^fac)O0god=w zG(5g0`Oi~Tq)Vq@S>;>B!pN^CDf%Wrm6;`_6=(%xc zZGD*7PT`=iT5-ej`meXo817mp7xS$)eD~Vj{YK8kE7i-*PtJ<|+5ar9viVYX=anOA z3k@wNWEM^On}12YdHI4>d$WIBXUccyt?!roWghtT+B;X9R^{`O-`D57=h9kTyL@xZ zi=AgDUHcWyy6)lYjKp&8(wrYwV#*(ErzAH8<#)@SnKf@e10>)rKw%FG`6$gVFL<5- zLmr6v7#JCfQj7CTi;`1|^%9GUlNp#8c)(J?xB*JaFs#}9mT{pmD>HMMk=f?irl-xh zIXLq3aw_A2e1^$|xyoV;plAh0EyxBaVA;GX*N$=W9aA1gsmT{j)hEm3C)A^;Le_!I z1{r|N$H&Ge2X_gK!B7uj5u*vDk{ER$HN>ie*$;LFF`B6D2u);5@fr?{G2wb-)%e)> zdc01Yi5Mn&YaAXUJVdFI$$$qd6#25&3 z1hHx%PKS`_df@gWOW<`el4&r9z=V*^z{N&08+U1erVwwiMjc2EvFc#<4SdsSwR@YJ~>eeq@XBx)_T? zU_!`d;9{ehJz7A*0uM+dhZ$Npp~xYt1F_NhFe7n@6QAd3;|O?~BhKYicf@D`2}>Yg z8b>ODrYaI6i;U!m-w{am<5!5}CzvDf`wXH1Sq(@8nGa&a?MIftrVu0s0?6t>Y;-%gADC5JAK&IfBo^)1Y7My3#k3O@#5M}D(deV-qs3%+^d hSsy7Ll8-0}B8E