libandroidfw: Fix mass logspam of ResourceTypes warnings
An overlay was incorrectly leaking its own resources into the framework resource package, which caused warnings for every app that tried to access framework resources (all of them). This change skips including any resources that are not overlaying anything (not present in IDMAP). Bug: 36256974 Test: make libandroidfw_tests Change-Id: I8c710af6849bb848938825aacca02799ee96c003
This commit is contained in:
@@ -1,2 +1,7 @@
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 100
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
CommentPragmas: NOLINT:.*
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
|
||||
@@ -6431,32 +6431,42 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
|
||||
}
|
||||
|
||||
if (newEntryCount > 0) {
|
||||
bool addToType = true;
|
||||
uint8_t typeIndex = typeSpec->id - 1;
|
||||
ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id);
|
||||
if (idmapIndex >= 0) {
|
||||
typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
|
||||
} else if (header->resourceIDMap != NULL) {
|
||||
// This is an overlay, but the types in this overlay are not
|
||||
// overlaying anything according to the idmap. We can skip these
|
||||
// as they will otherwise conflict with the other resources in the package
|
||||
// without a mapping.
|
||||
addToType = false;
|
||||
}
|
||||
|
||||
TypeList& typeList = group->types.editItemAt(typeIndex);
|
||||
if (!typeList.isEmpty()) {
|
||||
const Type* existingType = typeList[0];
|
||||
if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
|
||||
ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
|
||||
(int) newEntryCount, (int) existingType->entryCount);
|
||||
// We should normally abort here, but some legacy apps declare
|
||||
// resources in the 'android' package (old bug in AAPT).
|
||||
if (addToType) {
|
||||
TypeList& typeList = group->types.editItemAt(typeIndex);
|
||||
if (!typeList.isEmpty()) {
|
||||
const Type* existingType = typeList[0];
|
||||
if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
|
||||
ALOGW("ResTable_typeSpec entry count inconsistent: "
|
||||
"given %d, previously %d",
|
||||
(int) newEntryCount, (int) existingType->entryCount);
|
||||
// We should normally abort here, but some legacy apps declare
|
||||
// resources in the 'android' package (old bug in AAPT).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Type* t = new Type(header, package, newEntryCount);
|
||||
t->typeSpec = typeSpec;
|
||||
t->typeSpecFlags = (const uint32_t*)(
|
||||
((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
|
||||
if (idmapIndex >= 0) {
|
||||
t->idmapEntries = idmapEntries[idmapIndex];
|
||||
Type* t = new Type(header, package, newEntryCount);
|
||||
t->typeSpec = typeSpec;
|
||||
t->typeSpecFlags = (const uint32_t*)(
|
||||
((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
|
||||
if (idmapIndex >= 0) {
|
||||
t->idmapEntries = idmapEntries[idmapIndex];
|
||||
}
|
||||
typeList.add(t);
|
||||
group->largestTypeId = max(group->largestTypeId, typeSpec->id);
|
||||
}
|
||||
typeList.add(t);
|
||||
group->largestTypeId = max(group->largestTypeId, typeSpec->id);
|
||||
} else {
|
||||
ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec->id);
|
||||
}
|
||||
@@ -6499,31 +6509,40 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
|
||||
}
|
||||
|
||||
if (newEntryCount > 0) {
|
||||
bool addToType = true;
|
||||
uint8_t typeIndex = type->id - 1;
|
||||
ssize_t idmapIndex = idmapEntries.indexOfKey(type->id);
|
||||
if (idmapIndex >= 0) {
|
||||
typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
|
||||
} else if (header->resourceIDMap != NULL) {
|
||||
// This is an overlay, but the types in this overlay are not
|
||||
// overlaying anything according to the idmap. We can skip these
|
||||
// as they will otherwise conflict with the other resources in the package
|
||||
// without a mapping.
|
||||
addToType = false;
|
||||
}
|
||||
|
||||
TypeList& typeList = group->types.editItemAt(typeIndex);
|
||||
if (typeList.isEmpty()) {
|
||||
ALOGE("No TypeSpec for type %d", type->id);
|
||||
return (mError=BAD_TYPE);
|
||||
}
|
||||
if (addToType) {
|
||||
TypeList& typeList = group->types.editItemAt(typeIndex);
|
||||
if (typeList.isEmpty()) {
|
||||
ALOGE("No TypeSpec for type %d", type->id);
|
||||
return (mError=BAD_TYPE);
|
||||
}
|
||||
|
||||
Type* t = typeList.editItemAt(typeList.size() - 1);
|
||||
if (t->package != package) {
|
||||
ALOGE("No TypeSpec for type %d", type->id);
|
||||
return (mError=BAD_TYPE);
|
||||
}
|
||||
Type* t = typeList.editItemAt(typeList.size() - 1);
|
||||
if (t->package != package) {
|
||||
ALOGE("No TypeSpec for type %d", type->id);
|
||||
return (mError=BAD_TYPE);
|
||||
}
|
||||
|
||||
t->configs.add(type);
|
||||
t->configs.add(type);
|
||||
|
||||
if (kDebugTableGetEntry) {
|
||||
ResTable_config thisConfig;
|
||||
thisConfig.copyFromDtoH(type->config);
|
||||
ALOGI("Adding config to type %d: %s\n", type->id,
|
||||
thisConfig.toString().string());
|
||||
if (kDebugTableGetEntry) {
|
||||
ResTable_config thisConfig;
|
||||
thisConfig.copyFromDtoH(type->config);
|
||||
ALOGI("Adding config to type %d: %s\n", type->id,
|
||||
thisConfig.toString().string());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ALOGV("Skipping empty ResTable_type for type %d", type->id);
|
||||
|
||||
@@ -30,25 +30,23 @@ class IdmapTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
std::string contents;
|
||||
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
|
||||
"resources.arsc", &contents));
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
target_table_.add(contents.data(), contents.size(), 0, true));
|
||||
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc",
|
||||
&contents));
|
||||
ASSERT_EQ(NO_ERROR, target_table_.add(contents.data(), contents.size(), 0, true));
|
||||
|
||||
ASSERT_TRUE(
|
||||
ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk",
|
||||
"resources.arsc", &overlay_data_));
|
||||
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk",
|
||||
"resources.arsc", &overlay_data_));
|
||||
ResTable overlay_table;
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
overlay_table.add(overlay_data_.data(), overlay_data_.size()));
|
||||
ASSERT_EQ(NO_ERROR, overlay_table.add(overlay_data_.data(), overlay_data_.size()));
|
||||
|
||||
char target_name[256] = "com.android.basic";
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
target_table_.createIdmap(overlay_table, 0, 0, target_name,
|
||||
target_name, &data_, &data_size_));
|
||||
ASSERT_EQ(NO_ERROR, target_table_.createIdmap(overlay_table, 0, 0, target_name, target_name,
|
||||
&data_, &data_size_));
|
||||
}
|
||||
|
||||
void TearDown() override { ::free(data_); }
|
||||
void TearDown() override {
|
||||
::free(data_);
|
||||
}
|
||||
|
||||
ResTable target_table_;
|
||||
std::string overlay_data_;
|
||||
@@ -56,13 +54,12 @@ class IdmapTest : public ::testing::Test {
|
||||
size_t data_size_ = 0;
|
||||
};
|
||||
|
||||
TEST_F(IdmapTest, canLoadIdmap) {
|
||||
TEST_F(IdmapTest, CanLoadIdmap) {
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
target_table_.add(overlay_data_.data(), overlay_data_.size(), data_,
|
||||
data_size_));
|
||||
target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
|
||||
}
|
||||
|
||||
TEST_F(IdmapTest, overlayOverridesResourceValue) {
|
||||
TEST_F(IdmapTest, OverlayOverridesResourceValue) {
|
||||
Res_value val;
|
||||
ssize_t block = target_table_.getResource(R::string::test2, &val, false);
|
||||
ASSERT_GE(block, 0);
|
||||
@@ -71,45 +68,60 @@ TEST_F(IdmapTest, overlayOverridesResourceValue) {
|
||||
ASSERT_TRUE(pool != NULL);
|
||||
ASSERT_LT(val.data, pool->size());
|
||||
|
||||
size_t strLen;
|
||||
const char16_t* targetStr16 = pool->stringAt(val.data, &strLen);
|
||||
ASSERT_TRUE(targetStr16 != NULL);
|
||||
ASSERT_EQ(String16("test2"), String16(targetStr16, strLen));
|
||||
size_t str_len;
|
||||
const char16_t* target_str16 = pool->stringAt(val.data, &str_len);
|
||||
ASSERT_TRUE(target_str16 != NULL);
|
||||
ASSERT_EQ(String16("test2"), String16(target_str16, str_len));
|
||||
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
target_table_.add(overlay_data_.data(), overlay_data_.size(), data_,
|
||||
data_size_));
|
||||
target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
|
||||
|
||||
ssize_t newBlock = target_table_.getResource(R::string::test2, &val, false);
|
||||
ASSERT_GE(newBlock, 0);
|
||||
ASSERT_NE(block, newBlock);
|
||||
ssize_t new_block = target_table_.getResource(R::string::test2, &val, false);
|
||||
ASSERT_GE(new_block, 0);
|
||||
ASSERT_NE(block, new_block);
|
||||
ASSERT_EQ(Res_value::TYPE_STRING, val.dataType);
|
||||
pool = target_table_.getTableStringBlock(newBlock);
|
||||
pool = target_table_.getTableStringBlock(new_block);
|
||||
ASSERT_TRUE(pool != NULL);
|
||||
ASSERT_LT(val.data, pool->size());
|
||||
|
||||
targetStr16 = pool->stringAt(val.data, &strLen);
|
||||
ASSERT_TRUE(targetStr16 != NULL);
|
||||
ASSERT_EQ(String16("test2-overlay"), String16(targetStr16, strLen));
|
||||
target_str16 = pool->stringAt(val.data, &str_len);
|
||||
ASSERT_TRUE(target_str16 != NULL);
|
||||
ASSERT_EQ(String16("test2-overlay"), String16(target_str16, str_len));
|
||||
}
|
||||
|
||||
TEST_F(IdmapTest, overlaidResourceHasSameName) {
|
||||
TEST_F(IdmapTest, OverlaidResourceHasSameName) {
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
target_table_.add(overlay_data_.data(), overlay_data_.size(), data_,
|
||||
data_size_));
|
||||
target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
|
||||
|
||||
ResTable::resource_name resName;
|
||||
ASSERT_TRUE(
|
||||
target_table_.getResourceName(R::array::integerArray1, false, &resName));
|
||||
ResTable::resource_name res_name;
|
||||
ASSERT_TRUE(target_table_.getResourceName(R::array::integerArray1, false, &res_name));
|
||||
|
||||
ASSERT_TRUE(resName.package != NULL);
|
||||
ASSERT_TRUE(resName.type != NULL);
|
||||
ASSERT_TRUE(resName.name != NULL);
|
||||
ASSERT_TRUE(res_name.package != NULL);
|
||||
ASSERT_TRUE(res_name.type != NULL);
|
||||
ASSERT_TRUE(res_name.name != NULL);
|
||||
|
||||
EXPECT_EQ(String16("com.android.basic"),
|
||||
String16(resName.package, resName.packageLen));
|
||||
EXPECT_EQ(String16("array"), String16(resName.type, resName.typeLen));
|
||||
EXPECT_EQ(String16("integerArray1"), String16(resName.name, resName.nameLen));
|
||||
EXPECT_EQ(String16("com.android.basic"), String16(res_name.package, res_name.packageLen));
|
||||
EXPECT_EQ(String16("array"), String16(res_name.type, res_name.typeLen));
|
||||
EXPECT_EQ(String16("integerArray1"), String16(res_name.name, res_name.nameLen));
|
||||
}
|
||||
|
||||
constexpr const uint32_t kNonOverlaidResourceId = 0x7fff0000u;
|
||||
|
||||
TEST_F(IdmapTest, OverlayDoesNotIncludeNonOverlaidResources) {
|
||||
// First check that the resource we're trying to not include when overlaid is present when
|
||||
// the overlay is loaded as a standalone APK.
|
||||
ResTable table;
|
||||
ASSERT_EQ(NO_ERROR, table.add(overlay_data_.data(), overlay_data_.size(), 0, true));
|
||||
|
||||
Res_value val;
|
||||
ssize_t block = table.getResource(kNonOverlaidResourceId, &val, false /*mayBeBag*/);
|
||||
ASSERT_GE(block, 0);
|
||||
|
||||
// Now add the overlay and verify that the unoverlaid resource is gone.
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
target_table_.add(overlay_data_.data(), overlay_data_.size(), data_, data_size_));
|
||||
block = target_table_.getResource(kNonOverlaidResourceId, &val, false /*mayBeBag*/);
|
||||
ASSERT_LT(block, 0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Binary file not shown.
@@ -20,4 +20,6 @@
|
||||
<item>10</item>
|
||||
<item>11</item>
|
||||
</integer-array>
|
||||
<public type="animator" name="unoverlaid" id="0x7fff0000" />
|
||||
<item type="animator" name="unoverlaid">@null</item>
|
||||
</resources>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 100
|
||||
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
CommentPragmas: NOLINT:.*
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
|
||||
Reference in New Issue
Block a user