Optimize FilterApkAssets by caching config
ResTable_config of every ResTable_type is read from device every time
AssetManager::RebuildFilterList is invoked. For large APKs (like
framework-res.apk), this causes a large number of page faults
when accessing the config from disk. The configs are also used in the
slow path of AssetManager::FindEntryInternal, which makes it even
slower. Instead cache the config on the TypeSpec of its ApkAsset.
Bug: 177247024
Test: libandroidfw_tests
Change-Id: I66d507c4eeb2399f7558f3d9dfc53c157129ada0
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 471b0ee..e1c0fab7 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -55,6 +55,12 @@
basic_de_fr_assets_ = ApkAssets::Load("basic/basic_de_fr.apk");
ASSERT_NE(nullptr, basic_de_fr_assets_);
+ basic_xhdpi_assets_ = ApkAssets::Load("basic/basic_xhdpi-v4.apk");
+ ASSERT_NE(nullptr, basic_de_fr_assets_);
+
+ basic_xxhdpi_assets_ = ApkAssets::Load("basic/basic_xxhdpi-v4.apk");
+ ASSERT_NE(nullptr, basic_de_fr_assets_);
+
style_assets_ = ApkAssets::Load("styles/styles.apk");
ASSERT_NE(nullptr, style_assets_);
@@ -87,6 +93,8 @@
protected:
std::unique_ptr<const ApkAssets> basic_assets_;
std::unique_ptr<const ApkAssets> basic_de_fr_assets_;
+ std::unique_ptr<const ApkAssets> basic_xhdpi_assets_;
+ std::unique_ptr<const ApkAssets> basic_xxhdpi_assets_;
std::unique_ptr<const ApkAssets> style_assets_;
std::unique_ptr<const ApkAssets> lib_one_assets_;
std::unique_ptr<const ApkAssets> lib_two_assets_;
@@ -225,6 +233,24 @@
ASSERT_EQ("com.android.lib_one:string/foo", ToFormattedResourceString(*name));
}
+TEST_F(AssetManager2Test, GetResourceNameNonMatchingConfig) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({basic_de_fr_assets_.get()});
+
+ auto value = assetmanager.GetResourceName(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ("com.android.basic:string/test1", ToFormattedResourceString(*value));
+}
+
+TEST_F(AssetManager2Test, GetResourceTypeSpecFlags) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({basic_de_fr_assets_.get()});
+
+ auto value = assetmanager.GetResourceTypeSpecFlags(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(ResTable_typeSpec::SPEC_PUBLIC | ResTable_config::CONFIG_LOCALE, *value);
+}
+
TEST_F(AssetManager2Test, FindsBagResourceFromSingleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
@@ -442,6 +468,29 @@
EXPECT_EQ(*low_ref, value->resid);
}
+TEST_F(AssetManager2Test, DensityOverride) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({basic_assets_.get(), basic_xhdpi_assets_.get(),
+ basic_xxhdpi_assets_.get()});
+ assetmanager.SetConfiguration({
+ .density = ResTable_config::DENSITY_XHIGH,
+ .sdkVersion = 21,
+ });
+
+ auto value = assetmanager.GetResource(basic::R::string::density, false /*may_be_bag*/);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
+ EXPECT_EQ("xhdpi", GetStringFromPool(assetmanager.GetStringPoolForCookie(value->cookie),
+ value->data));
+
+ value = assetmanager.GetResource(basic::R::string::density, false /*may_be_bag*/,
+ ResTable_config::DENSITY_XXHIGH);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
+ EXPECT_EQ("xxhdpi", GetStringFromPool(assetmanager.GetStringPoolForCookie(value->cookie),
+ value->data));
+}
+
TEST_F(AssetManager2Test, KeepLastReferenceIdUnmodifiedIfNoReferenceIsResolved) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
@@ -716,7 +765,7 @@
auto result = assetmanager.GetLastResourceResolution();
EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n"
- "\tFor config -de\n\tFound initial: com.android.basic", result);
+ "\tFor config -de\n\tFound initial: com.android.basic (basic/basic.apk)", result);
}
TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
@@ -736,8 +785,8 @@
auto result = assetmanager.GetLastResourceResolution();
EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n"
"\tFor config -de\n"
- "\tFound initial: com.android.basic\n"
- "\tFound better: com.android.basic -de", result);
+ "\tFound initial: com.android.basic (basic/basic.apk)\n"
+ "\tFound better: com.android.basic (basic/basic_de_fr.apk) -de", result);
}
TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {