Merge "Allow non-references to be copied between AssetManagers" into qt-dev am: 4108c7fca4

am: 7768b376af

Change-Id: Icf9de4247ba48fccb05c87fd83e896558fab2802
This commit is contained in:
Ryan Mitchell
2019-04-05 20:34:34 -07:00
committed by android-build-merger
6 changed files with 105 additions and 51 deletions

View File

@@ -1319,7 +1319,7 @@ void Theme::SetTo(const Theme& o) {
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 @@ void Theme::SetTo(const Theme& o) {
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 @@ void Theme::SetTo(const Theme& o) {
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 @@ void Theme::SetTo(const Theme& o) {
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 @@ void Theme::SetTo(const Theme& o) {
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 @@ void Theme::SetTo(const Theme& o) {
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 @@ void Theme::SetTo(const Theme& o) {
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 Theme::SetTo(const Theme& o) {
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 @@ void Theme::SetTo(const Theme& o) {
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;
}
}

View File

@@ -282,48 +282,81 @@ TEST_F(ThemeTest, CopyThemeSameAssetManager) {
}
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

View File

@@ -51,6 +51,7 @@ struct R {
StyleFour = 0x7f020003u,
StyleFive = 0x7f020004u,
StyleSix = 0x7f020005u,
StyleSeven = 0x7f020006u,
};
};
};

View File

@@ -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

View File

@@ -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>