in libresource/ResourceTypes.cpp [5855:6147]
status_t ResTable::parsePackage(const ResTable_package* const pkg,
const Header* const header)
{
const uint8_t* base = (const uint8_t*)pkg;
status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
header->dataEnd, "ResTable_package");
if (err != NO_ERROR) {
return (mError=err);
}
const uint32_t pkgSize = dtohl(pkg->header.size);
if (dtohl(pkg->typeStrings) >= pkgSize) {
ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.",
dtohl(pkg->typeStrings), pkgSize);
return (mError=BAD_TYPE);
}
if ((dtohl(pkg->typeStrings)&0x3) != 0) {
ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.",
dtohl(pkg->typeStrings));
return (mError=BAD_TYPE);
}
if (dtohl(pkg->keyStrings) >= pkgSize) {
ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.",
dtohl(pkg->keyStrings), pkgSize);
return (mError=BAD_TYPE);
}
if ((dtohl(pkg->keyStrings)&0x3) != 0) {
ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.",
dtohl(pkg->keyStrings));
return (mError=BAD_TYPE);
}
uint32_t id = dtohl(pkg->id);
KeyedVector<uint8_t, IdmapEntries> idmapEntries;
if (header->resourceIDMap != NULL) {
uint8_t targetPackageId = 0;
status_t err = parseIdmap(header->resourceIDMap, header->resourceIDMapSize, &targetPackageId, &idmapEntries);
if (err != NO_ERROR) {
ALOGW("Overlay is broken");
return (mError=err);
}
id = targetPackageId;
}
if (id >= 256) {
LOG_ALWAYS_FATAL("Package id out of range");
return NO_ERROR;
} else if (id == 0) {
// This is a library so assign an ID
id = mNextPackageId++;
}
PackageGroup* group = NULL;
Package* package = new Package(this, header, pkg);
if (package == NULL) {
return (mError=NO_MEMORY);
}
err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
header->dataEnd-(base+dtohl(pkg->typeStrings)));
if (err != NO_ERROR) {
delete group;
delete package;
return (mError=err);
}
err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
header->dataEnd-(base+dtohl(pkg->keyStrings)));
if (err != NO_ERROR) {
delete group;
delete package;
return (mError=err);
}
size_t idx = mPackageMap[id];
if (idx == 0) {
idx = mPackageGroups.size() + 1;
char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
group = new PackageGroup(this, String16(tmpName), id);
if (group == NULL) {
delete package;
return (mError=NO_MEMORY);
}
err = mPackageGroups.add(group);
if (err < NO_ERROR) {
return (mError=err);
}
mPackageMap[id] = static_cast<uint8_t>(idx);
// Find all packages that reference this package
size_t N = mPackageGroups.size();
for (size_t i = 0; i < N; i++) {
mPackageGroups[i]->dynamicRefTable.addMapping(
group->name, static_cast<uint8_t>(group->id));
}
} else {
group = mPackageGroups.itemAt(idx - 1);
if (group == NULL) {
return (mError=UNKNOWN_ERROR);
}
}
err = group->packages.add(package);
if (err < NO_ERROR) {
return (mError=err);
}
// Iterate through all chunks.
const ResChunk_header* chunk =
(const ResChunk_header*)(((const uint8_t*)pkg)
+ dtohs(pkg->header.headerSize));
const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
if (kDebugTableNoisy) {
ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
(void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
}
const size_t csize = dtohl(chunk->size);
const uint16_t ctype = dtohs(chunk->type);
if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
err = validate_chunk(&typeSpec->header, sizeof(*typeSpec),
endPos, "ResTable_typeSpec");
if (err != NO_ERROR) {
return (mError=err);
}
const size_t typeSpecSize = dtohl(typeSpec->header.size);
const size_t newEntryCount = dtohl(typeSpec->entryCount);
if (kDebugLoadTableNoisy) {
ALOGI("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
(void*)(base-(const uint8_t*)chunk),
dtohs(typeSpec->header.type),
dtohs(typeSpec->header.headerSize),
(void*)typeSpecSize);
}
// look for block overrun or int overflow when multiplying by 4
if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
|| dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
> typeSpecSize)) {
ALOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
(void*)(dtohs(typeSpec->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
(void*)typeSpecSize);
return (mError=BAD_TYPE);
}
if (typeSpec->id == 0) {
ALOGW("ResTable_type has an id of 0.");
return (mError=BAD_TYPE);
}
if (newEntryCount > 0) {
uint8_t typeIndex = typeSpec->id - 1;
ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id);
if (idmapIndex >= 0) {
typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
}
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];
}
typeList.add(t);
group->largestTypeId = max(group->largestTypeId, typeSpec->id);
} else {
ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec->id);
}
} else if (ctype == RES_TABLE_TYPE_TYPE) {
const ResTable_type* type = (const ResTable_type*)(chunk);
err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
endPos, "ResTable_type");
if (err != NO_ERROR) {
return (mError=err);
}
const uint32_t typeSize = dtohl(type->header.size);
const size_t newEntryCount = dtohl(type->entryCount);
if (kDebugLoadTableNoisy) {
printf("Type off %p: type=0x%x, headerSize=0x%x, size=%u\n",
(void*)(base-(const uint8_t*)chunk),
dtohs(type->header.type),
dtohs(type->header.headerSize),
typeSize);
}
if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*newEntryCount) > typeSize) {
ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.",
(void*)(dtohs(type->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
typeSize);
return (mError=BAD_TYPE);
}
if (newEntryCount != 0
&& dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.",
dtohl(type->entriesStart), typeSize);
return (mError=BAD_TYPE);
}
if (type->id == 0) {
ALOGW("ResTable_type has an id of 0.");
return (mError=BAD_TYPE);
}
if (newEntryCount > 0) {
uint8_t typeIndex = type->id - 1;
ssize_t idmapIndex = idmapEntries.indexOfKey(type->id);
if (idmapIndex >= 0) {
typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
}
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 (newEntryCount != t->entryCount) {
ALOGE("ResTable_type entry count inconsistent: given %d, previously %d",
(int)newEntryCount, (int)t->entryCount);
return (mError=BAD_TYPE);
}
if (t->package != package) {
ALOGE("No TypeSpec for type %d", type->id);
return (mError=BAD_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());
}
} else {
ALOGV("Skipping empty ResTable_type for type %d", type->id);
}
} else if (ctype == RES_TABLE_LIBRARY_TYPE) {
if (group->dynamicRefTable.entries().size() == 0) {
status_t err = group->dynamicRefTable.load((const ResTable_lib_header*) chunk);
if (err != NO_ERROR) {
return (mError=err);
}
// Fill in the reference table with the entries we already know about.
size_t N = mPackageGroups.size();
for (size_t i = 0; i < N; i++) {
group->dynamicRefTable.addMapping(mPackageGroups[i]->name, mPackageGroups[i]->id);
}
} else {
ALOGW("Found multiple library tables, ignoring...");
}
} else {
status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
endPos, "ResTable_package:unknown");
if (err != NO_ERROR) {
return (mError=err);
}
}
chunk = (const ResChunk_header*)
(((const uint8_t*)chunk) + csize);
}
return NO_ERROR;
}