Merge "Allow non-references to be copied between AssetManagers" into qt-dev am: 4108c7fca4
am: 7768b376af
Change-Id: Icf9de4247ba48fccb05c87fd83e896558fab2802
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -51,6 +51,7 @@ struct R {
|
||||
StyleFour = 0x7f020003u,
|
||||
StyleFive = 0x7f020004u,
|
||||
StyleSix = 0x7f020005u,
|
||||
StyleSeven = 0x7f020006u,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user