Merge "Allow non-references to be copied between AssetManagers" into qt-dev
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 9519704..1b515ad 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -1319,7 +1319,7 @@
typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
- // Determine which ApkAssets are loaded in both theme AssetManagers
+ // Determine which ApkAssets are loaded in both theme AssetManagers.
std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets();
for (size_t i = 0; i < src_assets.size(); i++) {
const ApkAssets* src_asset = src_assets[i];
@@ -1328,7 +1328,7 @@
for (size_t j = 0; j < dest_assets.size(); j++) {
const ApkAssets* dest_asset = dest_assets[j];
- // Map the runtime package of the source apk asset to the destination apk asset
+ // Map the runtime package of the source apk asset to the destination apk asset.
if (src_asset->GetPath() == dest_asset->GetPath()) {
const std::vector<std::unique_ptr<const LoadedPackage>>& src_packages =
src_asset->GetLoadedArsc()->GetPackages();
@@ -1353,15 +1353,14 @@
package_map[src_package_id] = dest_package_id;
}
- src_to_dest_asset_cookies.insert(std::pair<ApkAssetsCookie, ApkAssetsCookie>(i, j));
- src_asset_cookie_id_map.insert(
- std::pair<ApkAssetsCookie, SourceToDestinationRuntimePackageMap>(i, package_map));
+ src_to_dest_asset_cookies.insert(std::make_pair(i, j));
+ src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
break;
}
}
}
- // Reset the data in the destination theme
+ // Reset the data in the destination theme.
for (size_t p = 0; p < packages_.size(); p++) {
if (packages_[p] != nullptr) {
packages_[p].reset();
@@ -1387,16 +1386,17 @@
continue;
}
- // If the attribute value represents an attribute or reference, the package id of the
- // value needs to be rewritten to the package id of the value in the destination
- uint32_t attribue_data = entry.value.data;
- if ((entry.value.dataType == Res_value::TYPE_ATTRIBUTE
- || entry.value.dataType == Res_value::TYPE_REFERENCE
- || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
- || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE)
- && attribue_data != 0x0) {
+ bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE
+ || entry.value.dataType == Res_value::TYPE_REFERENCE
+ || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
+ || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE)
+ && entry.value.data != 0x0;
- // Determine the package id of the reference in the destination AssetManager
+ // If the attribute value represents an attribute or reference, the package id of the
+ // value needs to be rewritten to the package id of the value in the destination.
+ uint32_t attribute_data = entry.value.data;
+ if (is_reference) {
+ // Determine the package id of the reference in the destination AssetManager.
auto value_package_map = src_asset_cookie_id_map.find(entry.cookie);
if (value_package_map == src_asset_cookie_id_map.end()) {
continue;
@@ -1408,14 +1408,28 @@
continue;
}
- attribue_data = fix_package_id(entry.value.data, value_dest_package->second);
+ attribute_data = fix_package_id(entry.value.data, value_dest_package->second);
+ }
+
+ // Find the cookie of the value in the destination. If the source apk is not loaded in the
+ // destination, only copy resources that do not reference resources in the source.
+ ApkAssetsCookie data_dest_cookie;
+ auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
+ if (value_dest_cookie != src_to_dest_asset_cookies.end()) {
+ data_dest_cookie = value_dest_cookie->second;
+ } else {
+ if (is_reference || entry.value.dataType == Res_value::TYPE_STRING) {
+ continue;
+ } else {
+ data_dest_cookie = 0x0;
+ }
}
// The package id of the attribute needs to be rewritten to the package id of the
- // attribute in the destination
+ // attribute in the destination.
int attribute_dest_package_id = p;
if (attribute_dest_package_id != 0x01) {
- // Find the cookie of the attribute resource id
+ // Find the cookie of the attribute resource id in the source AssetManager
FindEntryResult attribute_entry_result;
ApkAssetsCookie attribute_cookie =
o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ ,
@@ -1423,7 +1437,7 @@
true /* ignore_configuration */,
&attribute_entry_result);
- // Determine the package id of the attribute in the destination AssetManager
+ // Determine the package id of the attribute in the destination AssetManager.
auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie);
if (attribute_package_map == src_asset_cookie_id_map.end()) {
continue;
@@ -1436,13 +1450,13 @@
attribute_dest_package_id = attribute_dest_package->second;
}
- // Lazily instantiate the destination package
+ // Lazily instantiate the destination package.
std::unique_ptr<Package>& dest_package = packages_[attribute_dest_package_id];
if (dest_package == nullptr) {
dest_package.reset(new Package());
}
- // Lazily instantiate and resize the destination type
+ // Lazily instantiate and resize the destination type.
util::unique_cptr<ThemeType>& dest_type = dest_package->types[t];
if (dest_type == nullptr || dest_type->entry_count < type->entry_count) {
const size_t type_alloc_size = sizeof(ThemeType)
@@ -1450,7 +1464,7 @@
void* dest_data = malloc(type_alloc_size);
memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry));
- // Copy the existing destination type values if the type is resized
+ // Copy the existing destination type values if the type is resized.
if (dest_type != nullptr) {
memcpy(dest_data, type, sizeof(ThemeType)
+ (dest_type->entry_count * sizeof(ThemeEntry)));
@@ -1460,15 +1474,9 @@
dest_type->entry_count = type->entry_count;
}
- // Find the cookie of the value in the destination
- auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
- if (value_dest_cookie == src_to_dest_asset_cookies.end()) {
- continue;
- }
-
- dest_type->entries[e].cookie = value_dest_cookie->second;
+ dest_type->entries[e].cookie = data_dest_cookie;
dest_type->entries[e].value.dataType = entry.value.dataType;
- dest_type->entries[e].value.data = attribue_data;
+ dest_type->entries[e].value.data = attribute_data;
dest_type->entries[e].type_spec_flags = entry.type_spec_flags;
}
}
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 2c39cee..be5ecd9 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -282,48 +282,81 @@
}
TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
- AssetManager2 assetmanager_one;
- assetmanager_one.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(),
+ AssetManager2 assetmanager_dst;
+ assetmanager_dst.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(),
libclient_assets_.get()});
- AssetManager2 assetmanager_two;
- assetmanager_two.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(),
+ AssetManager2 assetmanager_src;
+ assetmanager_src.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(),
style_assets_.get()});
- auto theme_one = assetmanager_one.NewTheme();
- ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
+ auto theme_dst = assetmanager_dst.NewTheme();
+ ASSERT_TRUE(theme_dst->ApplyStyle(app::R::style::StyleOne));
- auto theme_two = assetmanager_two.NewTheme();
- ASSERT_TRUE(theme_two->ApplyStyle(R::style::Theme_One));
- ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo));
- ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03),
+ auto theme_src = assetmanager_src.NewTheme();
+ ASSERT_TRUE(theme_src->ApplyStyle(R::style::Theme_One));
+ ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleTwo));
+ ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03),
false /*force*/));
- ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02),
+ ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02),
false /*force*/));
- theme_one->SetTo(*theme_two);
+ theme_dst->SetTo(*theme_src);
Res_value value;
uint32_t flags;
- // System resources (present in destination asset manager)
- EXPECT_EQ(0, theme_one->GetAttribute(R::attr::foreground, &value, &flags));
+ // System resources (present in destination asset manager).
+ EXPECT_EQ(0, theme_dst->GetAttribute(R::attr::foreground, &value, &flags));
// The cookie of the style asset is 3 in the source and 2 in the destination.
- // Check that the cookie has been rewritten to the destination values
- EXPECT_EQ(2, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+ // Check that the cookie has been rewritten to the destination values.
+ EXPECT_EQ(2, theme_dst->GetAttribute(app::R::attr::attr_one, &value, &flags));
// The cookie of the lib_one asset is 2 in the source and 1 in the destination.
// The package id of the lib_one package is 0x03 in the source and 0x02 in the destination
- // Check that the cookie and packages have been rewritten to the destination values
- EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value,
+ // Check that the cookie and packages have been rewritten to the destination values.
+ EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value,
&flags));
- EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value,
+ EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value,
&flags));
// attr2 references an attribute in lib_one. Check that the resolution of the attribute value is
- // correct after the value of attr2 had its package id rewritten to the destination package id
+ // correct after the value of attr2 had its package id rewritten to the destination package id.
EXPECT_EQ(700, value.data);
}
+TEST_F(ThemeTest, CopyNonReferencesWhenPackagesDiffer) {
+ AssetManager2 assetmanager_dst;
+ assetmanager_dst.SetApkAssets({system_assets_.get()});
+
+ AssetManager2 assetmanager_src;
+ assetmanager_src.SetApkAssets({system_assets_.get(), style_assets_.get()});
+
+ auto theme_dst = assetmanager_dst.NewTheme();
+ auto theme_src = assetmanager_src.NewTheme();
+ ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleSeven));
+ theme_dst->SetTo(*theme_src);
+
+ Res_value value;
+ uint32_t flags;
+
+ // Allow inline resource values to be copied even if the source apk asset is not present in the
+ // destination.
+ EXPECT_EQ(0, theme_dst->GetAttribute(0x0101021b /* android:versionCode */, &value, &flags));
+
+ // Do not copy strings since the data is an index into the values string pool of the source apk
+ // asset.
+ EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010001 /* android:label */, &value, &flags));
+
+ // Do not copy values that reference another resource if the resource is not present in the
+ // destination.
+ EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010002 /* android:icon */, &value, &flags));
+ EXPECT_EQ(-1, theme_dst->GetAttribute(0x010100d1 /* android:tag */, &value, &flags));
+
+ // Allow @empty to and @null to be copied.
+ EXPECT_EQ(0, theme_dst->GetAttribute(0x010100d0 /* android:id */, &value, &flags));
+ EXPECT_EQ(0, theme_dst->GetAttribute(0x01010000 /* android:theme */, &value, &flags));
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h
index 538a847..f11486f 100644
--- a/libs/androidfw/tests/data/styles/R.h
+++ b/libs/androidfw/tests/data/styles/R.h
@@ -51,6 +51,7 @@
StyleFour = 0x7f020003u,
StyleFive = 0x7f020004u,
StyleSix = 0x7f020005u,
+ StyleSeven = 0x7f020006u,
};
};
};
diff --git a/libs/androidfw/tests/data/styles/build b/libs/androidfw/tests/data/styles/build
index 1ef8e6e..7b7c1f7 100755
--- a/libs/androidfw/tests/data/styles/build
+++ b/libs/androidfw/tests/data/styles/build
@@ -2,5 +2,7 @@
set -e
+PATH_TO_FRAMEWORK_RES=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
aapt2 compile -o compiled.flata --dir res
-aapt2 link -o styles.apk --manifest AndroidManifest.xml compiled.flata
+aapt2 link -o styles.apk --manifest AndroidManifest.xml -I $PATH_TO_FRAMEWORK_RES compiled.flata
diff --git a/libs/androidfw/tests/data/styles/res/values/styles.xml b/libs/androidfw/tests/data/styles/res/values/styles.xml
index 1a23176..06774a8 100644
--- a/libs/androidfw/tests/data/styles/res/values/styles.xml
+++ b/libs/androidfw/tests/data/styles/res/values/styles.xml
@@ -79,4 +79,14 @@
<item name="attr_three">3</item>
</style>
+ <public type="style" name="StyleSeven" id="0x7f020006" />
+ <style name="StyleSeven" >
+ <item name="android:versionCode">3</item>
+ <item name="android:label">"string"</item>
+ <item name="android:icon">?attr/attr_one</item>
+ <item name="android:tag">@string/string_one</item>
+ <item name="android:id">@null</item>
+ <item name="android:theme">@empty</item>
+ </style>
+
</resources>
diff --git a/libs/androidfw/tests/data/styles/styles.apk b/libs/androidfw/tests/data/styles/styles.apk
index cd5c7a1..92e9bf9 100644
--- a/libs/androidfw/tests/data/styles/styles.apk
+++ b/libs/androidfw/tests/data/styles/styles.apk
Binary files differ