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) {