diff options
author | Adam Lesinski <adamlesinski@google.com> | 2014-11-19 17:49:26 -0800 |
---|---|---|
committer | Adam Lesinski <adamlesinski@google.com> | 2014-12-03 15:59:20 -0800 |
commit | 9b624c186cb6059dfb3ec24bfb6386a0fc17b88c (patch) | |
tree | e57516e076eddb75d4c657704522f43067153c2a | |
parent | 92ad4dd017a13364b4001bdb04911202932f81c2 (diff) | |
download | frameworks_base-9b624c186cb6059dfb3ec24bfb6386a0fc17b88c.zip frameworks_base-9b624c186cb6059dfb3ec24bfb6386a0fc17b88c.tar.gz frameworks_base-9b624c186cb6059dfb3ec24bfb6386a0fc17b88c.tar.bz2 |
AAPT: Move private attrs to new type for framework
Private attributes are typically placed after public
attributes in the resource table. Each time a new version
of the Android framework is released, new public attributes
take the place of the private attributes, and the private
attributes are shifted after the new public ones.
This means that any apps built against the newer SDK
may inadvertently be using private attributes on older
devices.
This change moves all private attributes to a completely
different type ID, so there will never be collisions across
versions.
These private attributes are automatically moved to a synthesized
type only for the system resources.
Bug:18263655
Change-Id: I7a850512953fadcc9f3524d509cea30249782db8
-rw-r--r-- | include/androidfw/ResourceTypes.h | 3 | ||||
-rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 103 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.cpp | 168 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.h | 15 |
4 files changed, 221 insertions, 68 deletions
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index 6b84494..5a28be5 100644 --- a/include/androidfw/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -1828,6 +1828,9 @@ private: const ResTable_config* config, Entry* outEntry) const; + uint32_t findEntry(const PackageGroup* group, ssize_t typeIndex, const char16_t* name, + size_t nameLen, uint32_t* outTypeSpecFlags) const; + status_t parsePackage( const ResTable_package* const pkg, const Header* const header); diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 6dfb4dc..d7b9765 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -4173,6 +4173,9 @@ nope: String8(name, nameLen).string(), String8(package, packageLen).string())); + const String16 attr("attr"); + const String16 attrPrivate("^attr-private"); + const size_t NG = mPackageGroups.size(); for (size_t ig=0; ig<NG; ig++) { const PackageGroup* group = mPackageGroups[ig]; @@ -4185,64 +4188,72 @@ nope: const size_t packageCount = group->packages.size(); for (size_t pi = 0; pi < packageCount; pi++) { - ssize_t ti = group->packages[pi]->typeStrings.indexOfString(type, typeLen); - if (ti < 0) { - continue; - } + const char16_t* targetType = type; + size_t targetTypeLen = typeLen; - ti += group->packages[pi]->typeIdOffset; + do { + ssize_t ti = group->packages[pi]->typeStrings.indexOfString( + targetType, targetTypeLen); + if (ti < 0) { + continue; + } - const TypeList& typeList = group->types[ti]; - if (typeList.isEmpty()) { - TABLE_NOISY(printf("Expected type structure not found in package %s for index %d\n", - String8(group->name).string(), ti)); - continue; - } + ti += group->packages[pi]->typeIdOffset; - const size_t typeCount = typeList.size(); - for (size_t i = 0; i < typeCount; i++) { - const Type* t = typeList[i]; - const ssize_t ei = t->package->keyStrings.indexOfString(name, nameLen); - if (ei < 0) { - continue; + const uint32_t identifier = findEntry(group, ti, name, nameLen, + outTypeSpecFlags); + if (identifier != 0) { + if (fakePublic && outTypeSpecFlags) { + *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC; + } + return identifier; } + } while (strzcmp16(attr.string(), attr.size(), targetType, targetTypeLen) == 0 + && (targetType = attrPrivate.string()) + && (targetTypeLen = attrPrivate.size()) + ); + } + break; + } + return 0; +} - const size_t configCount = t->configs.size(); - for (size_t j = 0; j < configCount; j++) { - const TypeVariant tv(t->configs[j]); - for (TypeVariant::iterator iter = tv.beginEntries(); - iter != tv.endEntries(); - iter++) { - const ResTable_entry* entry = *iter; - if (entry == NULL) { - continue; - } +uint32_t ResTable::findEntry(const PackageGroup* group, ssize_t typeIndex, const char16_t* name, + size_t nameLen, uint32_t* outTypeSpecFlags) const { + const TypeList& typeList = group->types[typeIndex]; + const size_t typeCount = typeList.size(); + for (size_t i = 0; i < typeCount; i++) { + const Type* t = typeList[i]; + const ssize_t ei = t->package->keyStrings.indexOfString(name, nameLen); + if (ei < 0) { + continue; + } - if (dtohl(entry->key.index) == (size_t) ei) { - uint32_t resId = Res_MAKEID(group->id - 1, ti, iter.index()); - if (outTypeSpecFlags) { - Entry result; - if (getEntry(group, ti, iter.index(), NULL, &result) != NO_ERROR) { - ALOGW("Failed to find spec flags for %s:%s/%s (0x%08x)", - String8(group->name).string(), - String8(String16(type, typeLen)).string(), - String8(String16(name, nameLen)).string(), - resId); - return 0; - } - *outTypeSpecFlags = result.specFlags; + const size_t configCount = t->configs.size(); + for (size_t j = 0; j < configCount; j++) { + const TypeVariant tv(t->configs[j]); + for (TypeVariant::iterator iter = tv.beginEntries(); + iter != tv.endEntries(); + iter++) { + const ResTable_entry* entry = *iter; + if (entry == NULL) { + continue; + } - if (fakePublic) { - *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC; - } - } - return resId; + if (dtohl(entry->key.index) == (size_t) ei) { + uint32_t resId = Res_MAKEID(group->id - 1, typeIndex, iter.index()); + if (outTypeSpecFlags) { + Entry result; + if (getEntry(group, typeIndex, iter.index(), NULL, &result) != NO_ERROR) { + ALOGW("Failed to find spec flags for 0x%08x", resId); + return 0; } + *outTypeSpecFlags = result.specFlags; } + return resId; } } } - break; } return 0; } diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index bdc6586..6d03311 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -12,6 +12,7 @@ #include "ResourceIdCache.h" #include "SdkConstants.h" +#include <algorithm> #include <androidfw/ResourceTypes.h> #include <utils/ByteOrder.h> #include <utils/TypeHelpers.h> @@ -19,6 +20,8 @@ #define NOISY(x) //x +static const char* kAttrPrivateType = "^attr-private"; + status_t compileXmlFile(const Bundle* bundle, const sp<AaptAssets>& assets, const String16& resourceName, @@ -2131,8 +2134,16 @@ uint32_t ResourceTable::getResId(const String16& package, if (p == NULL) return 0; sp<Type> t = p->getTypes().valueFor(type); if (t == NULL) return 0; - sp<ConfigList> c = t->getConfigs().valueFor(name); - if (c == NULL) return 0; + sp<ConfigList> c = t->getConfigs().valueFor(name); + if (c == NULL) { + if (type != String16("attr")) { + return 0; + } + t = p->getTypes().valueFor(String16(kAttrPrivateType)); + if (t == NULL) return 0; + c = t->getConfigs().valueFor(name); + if (c == NULL) return 0; + } int32_t ei = c->getEntryIndex(); if (ei < 0) return 0; @@ -2266,7 +2277,15 @@ uint32_t ResourceTable::getCustomResource( sp<Type> t = p->getTypes().valueFor(type); if (t == NULL) return 0; sp<ConfigList> c = t->getConfigs().valueFor(name); - if (c == NULL) return 0; + if (c == NULL) { + if (type != String16("attr")) { + return 0; + } + t = p->getTypes().valueFor(String16(kAttrPrivateType)); + if (t == NULL) return 0; + c = t->getConfigs().valueFor(name); + if (c == NULL) return 0; + } int32_t ei = c->getEntryIndex(); if (ei < 0) return 0; return getResId(p, t, ei); @@ -2470,6 +2489,10 @@ status_t ResourceTable::assignResourceIds() continue; } + if (mPackageType == System) { + p->movePrivateAttrs(); + } + // This has no sense for packages being built as AppFeature (aka with a non-zero offset). status_t err = p->applyPublicTypeOrder(); if (err != NO_ERROR && firstError == NO_ERROR) { @@ -2540,15 +2563,20 @@ status_t ResourceTable::assignResourceIds() } } + // Assign resource IDs to keys in bags... for (size_t ti = 0; ti < typeCount; ti++) { sp<Type> t = p->getOrderedTypes().itemAt(ti); if (t == NULL) { continue; } + const size_t N = t->getOrderedConfigs().size(); for (size_t ci=0; ci<N; ci++) { sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci); + if (c == NULL) { + continue; + } //printf("Ordered config #%d: %p\n", ci, c.get()); const size_t N = c->getEntries().size(); for (size_t ei=0; ei<N; ei++) { @@ -2586,9 +2614,15 @@ status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols) { if (t == NULL) { continue; } + const size_t N = t->getOrderedConfigs().size(); - sp<AaptSymbols> typeSymbols = - outSymbols->addNestedSymbol(String8(t->getName()), t->getPos()); + sp<AaptSymbols> typeSymbols; + if (t->getName() == String16(kAttrPrivateType)) { + typeSymbols = outSymbols->addNestedSymbol(String8("attr"), t->getPos()); + } else { + typeSymbols = outSymbols->addNestedSymbol(String8(t->getName()), t->getPos()); + } + if (typeSymbols == NULL) { return UNKNOWN_ERROR; } @@ -2954,6 +2988,10 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& for (size_t ei=0; ei<N; ei++) { sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei); + if (cl == NULL) { + continue; + } + if (cl->getPublic()) { typeSpecFlags[ei] |= htodl(ResTable_typeSpec::SPEC_PUBLIC); } @@ -2984,12 +3022,13 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& // We need to write one type chunk for each configuration for // which we have entries in this type. - const size_t NC = t->getUniqueConfigs().size(); + const SortedVector<ConfigDescription> uniqueConfigs(t->getUniqueConfigs()); + const size_t NC = uniqueConfigs.size(); const size_t typeSize = sizeof(ResTable_type) + sizeof(uint32_t)*N; for (size_t ci=0; ci<NC; ci++) { - ConfigDescription config = t->getUniqueConfigs().itemAt(ci); + const ConfigDescription& config = uniqueConfigs[ci]; NOISY(printf("Writing config %d config: imsi:%d/%d lang:%c%c cnt:%c%c " "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d " @@ -3061,7 +3100,10 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& // Build the entries inside of this type. for (size_t ei=0; ei<N; ei++) { sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei); - sp<Entry> e = cl->getEntries().valueFor(config); + sp<Entry> e = NULL; + if (cl != NULL) { + e = cl->getEntries().valueFor(config); + } // Set the offset for this entry in its type. uint32_t* index = (uint32_t*) @@ -3096,9 +3138,11 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& for (size_t i = 0; i < N; ++i) { if (!validResources[i]) { sp<ConfigList> c = t->getOrderedConfigs().itemAt(i); - fprintf(stderr, "%s: no entries written for %s/%s (0x%08x)\n", log_prefix, - String8(typeName).string(), String8(c->getName()).string(), - Res_MAKEID(p->getAssignedId() - 1, ti, i)); + if (c != NULL) { + fprintf(stderr, "%s: no entries written for %s/%s (0x%08x)\n", log_prefix, + String8(typeName).string(), String8(c->getName()).string(), + Res_MAKEID(p->getAssignedId() - 1, ti, i)); + } missing_entry = true; } } @@ -3807,11 +3851,45 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry, */ } - mUniqueConfigs.add(cdesc); - return e; } +sp<ResourceTable::ConfigList> ResourceTable::Type::removeEntry(const String16& entry) { + ssize_t idx = mConfigs.indexOfKey(entry); + if (idx < 0) { + return NULL; + } + + sp<ConfigList> removed = mConfigs.valueAt(idx); + mConfigs.removeItemsAt(idx); + + Vector<sp<ConfigList> >::iterator iter = std::find( + mOrderedConfigs.begin(), mOrderedConfigs.end(), removed); + if (iter != mOrderedConfigs.end()) { + mOrderedConfigs.erase(iter); + } + + mPublic.removeItem(entry); + return removed; +} + +SortedVector<ConfigDescription> ResourceTable::Type::getUniqueConfigs() const { + SortedVector<ConfigDescription> unique; + const size_t entryCount = mOrderedConfigs.size(); + for (size_t i = 0; i < entryCount; i++) { + if (mOrderedConfigs[i] == NULL) { + continue; + } + const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configs = + mOrderedConfigs[i]->getEntries(); + const size_t configCount = configs.size(); + for (size_t j = 0; j < configCount; j++) { + unique.add(configs.keyAt(j)); + } + } + return unique; +} + status_t ResourceTable::Type::applyPublicEntryOrder() { size_t N = mOrderedConfigs.size(); @@ -3838,11 +3916,10 @@ status_t ResourceTable::Type::applyPublicEntryOrder() //printf("#%d: \"%s\"\n", i, String8(e->getName()).string()); if (e->getName() == name) { if (idx >= (int32_t)mOrderedConfigs.size()) { - p.sourcePos.error("Public entry identifier 0x%x entry index " - "is larger than available symbols (index %d, total symbols %d).\n", - p.ident, idx, mOrderedConfigs.size()); - hasError = true; - } else if (mOrderedConfigs.itemAt(idx) == NULL) { + mOrderedConfigs.resize(idx + 1); + } + + if (mOrderedConfigs.itemAt(idx) == NULL) { e->setPublic(true); e->setPublicSourcePos(p.sourcePos); mOrderedConfigs.replaceAt(e, idx); @@ -4018,6 +4095,61 @@ status_t ResourceTable::Package::applyPublicTypeOrder() return NO_ERROR; } +void ResourceTable::Package::movePrivateAttrs() { + sp<Type> attr = mTypes.valueFor(String16("attr")); + if (attr == NULL) { + // Nothing to do. + return; + } + + Vector<sp<ConfigList> > privateAttrs; + + bool hasPublic = false; + const Vector<sp<ConfigList> >& configs = attr->getOrderedConfigs(); + const size_t configCount = configs.size(); + for (size_t i = 0; i < configCount; i++) { + if (configs[i] == NULL) { + continue; + } + + if (attr->isPublic(configs[i]->getName())) { + hasPublic = true; + } else { + privateAttrs.add(configs[i]); + } + } + + // Only if we have public attributes do we create a separate type for + // private attributes. + if (!hasPublic) { + return; + } + + // Create a new type for private attributes. + sp<Type> privateAttrType = getType(String16(kAttrPrivateType), SourcePos()); + + const size_t privateAttrCount = privateAttrs.size(); + for (size_t i = 0; i < privateAttrCount; i++) { + const sp<ConfigList>& cl = privateAttrs[i]; + + // Remove the private attributes from their current type. + attr->removeEntry(cl->getName()); + + // Add it to the new type. + const DefaultKeyedVector<ConfigDescription, sp<Entry> >& entries = cl->getEntries(); + const size_t entryCount = entries.size(); + for (size_t j = 0; j < entryCount; j++) { + const sp<Entry>& oldEntry = entries[j]; + sp<Entry> entry = privateAttrType->getEntry( + cl->getName(), oldEntry->getPos(), &entries.keyAt(j)); + *entry = *oldEntry; + } + + // Move the symbols to the new type. + + } +} + sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package) { if (package != mAssetsPackage) { diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index db392c8..81590bc 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -470,6 +470,14 @@ public: bool overlay = false, bool autoAddOverlay = false); + bool isPublic(const String16& entry) const { + return mPublic.indexOfKey(entry) >= 0; + } + + sp<ConfigList> removeEntry(const String16& entry); + + SortedVector<ConfigDescription> getUniqueConfigs() const; + const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; } int32_t getPublicIndex() const { return mPublicIndex; } @@ -479,19 +487,16 @@ public: status_t applyPublicEntryOrder(); - const SortedVector<ConfigDescription>& getUniqueConfigs() const { return mUniqueConfigs; } - const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; } const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; } - const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; } const SourcePos& getPos() const { return mPos; } + private: String16 mName; SourcePos* mFirstPublicSourcePos; DefaultKeyedVector<String16, Public> mPublic; - SortedVector<ConfigDescription> mUniqueConfigs; DefaultKeyedVector<String16, sp<ConfigList> > mConfigs; Vector<sp<ConfigList> > mOrderedConfigs; SortedVector<String16> mCanAddEntries; @@ -527,6 +532,8 @@ public: const DefaultKeyedVector<String16, sp<Type> >& getTypes() const { return mTypes; } const Vector<sp<Type> >& getOrderedTypes() const { return mOrderedTypes; } + void movePrivateAttrs(); + private: status_t setStrings(const sp<AaptFile>& data, ResStringPool* strings, |