diff options
author | 2014-06-18 15:06:01 -0700 | |
---|---|---|
committer | 2014-08-04 18:48:14 -0700 | |
commit | 833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1 (patch) | |
tree | a57e8389088178108de1424faf41ea3bb87c934a /tools/aapt/ResourceTable.cpp | |
parent | 5c09e8ad5ee8e67976066366527ee58792551953 (diff) |
AAPT support for feature splits
This change allows the developer to add a base package for
which to build a feature split. The generated resource types
will begin after the base APK's defined types so as not
to collide or override resources.
Multiple features can be generated by first choosing an
arbitrary order for the features. Then for each feature,
the base APK and any preceding features are specified
with the --feature-of flags.
So with a base APK 'A' and features, 'B', and 'C',
'B' would be built with
aapt package [...] --feature-of A [...]
and 'C' would be built with
aapt package [...] --feature-of A --feature-of B [...]
Change-Id: I1be66e3f8df9a737b21c71f8a93685376c7e6780
Diffstat (limited to 'tools/aapt/ResourceTable.cpp')
-rw-r--r-- | tools/aapt/ResourceTable.cpp | 251 |
1 files changed, 118 insertions, 133 deletions
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index ac5463864366..cf1d4fd33a78 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -1713,12 +1713,49 @@ status_t compileResourceFile(Bundle* bundle, return hasErrors ? UNKNOWN_ERROR : NO_ERROR; } -ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage) - : mAssetsPackage(assetsPackage), mNextPackageId(1), mHaveAppPackage(false), - mIsAppPackage(!bundle->getExtending()), mIsSharedLibrary(bundle->getBuildSharedLibrary()), - mNumLocal(0), - mBundle(bundle) -{ +ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage, ResourceTable::PackageType type) + : mAssetsPackage(assetsPackage) + , mPackageType(type) + , mTypeIdOffset(0) + , mNumLocal(0) + , mBundle(bundle) +{ + ssize_t packageId = -1; + switch (mPackageType) { + case App: + case AppFeature: + packageId = 0x7f; + break; + + case System: + packageId = 0x01; + break; + + case SharedLibrary: + packageId = 0x00; + break; + + default: + assert(0); + break; + } + sp<Package> package = new Package(mAssetsPackage, packageId); + mPackages.add(assetsPackage, package); + mOrderedPackages.add(package); + + // Every resource table always has one first entry, the bag attributes. + const SourcePos unknown(String8("????"), 0); + getType(mAssetsPackage, String16("attr"), unknown); +} + +static uint32_t findLargestTypeIdForPackage(const ResTable& table, const String16& packageName) { + const size_t basePackageCount = table.getBasePackageCount(); + for (size_t i = 0; i < basePackageCount; i++) { + if (packageName == table.getBasePackageName(i)) { + return table.getLastTypeIdForPackage(i); + } + } + return 0; } status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets) @@ -1728,59 +1765,22 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets return err; } - // For future reference to included resources. mAssets = assets; - - const ResTable& incl = assets->getIncludedResources(); - - // Retrieve all the packages. - const size_t N = incl.getBasePackageCount(); - for (size_t phase=0; phase<2; phase++) { - for (size_t i=0; i<N; i++) { - const String16 name = incl.getBasePackageName(i); - uint32_t id = incl.getBasePackageId(i); - - // First time through: only add base packages (id - // is not 0); second time through add the other - // packages. - if (phase != 0) { - if (id != 0) { - // Skip base packages -- already one. - id = 0; - } else { - // Assign a dynamic id. - id = mNextPackageId; - } - } else if (id != 0) { - if (id == 127) { - if (mHaveAppPackage) { - fprintf(stderr, "Included resources have two application packages!\n"); - return UNKNOWN_ERROR; - } - mHaveAppPackage = true; - } - if (mNextPackageId > id) { - fprintf(stderr, "Included base package ID %d already in use!\n", id); - return UNKNOWN_ERROR; - } - } - if (id != 0) { - NOISY(fprintf(stderr, "Including package %s with ID=%d\n", - String8(name).string(), id)); - sp<Package> p = new Package(name, id); - mPackages.add(name, p); - mOrderedPackages.add(p); - - if (id >= mNextPackageId) { - mNextPackageId = id+1; - } - } + mTypeIdOffset = findLargestTypeIdForPackage(assets->getIncludedResources(), mAssetsPackage); + + const String8& featureAfter = bundle->getFeatureAfterPackage(); + if (!featureAfter.isEmpty()) { + AssetManager featureAssetManager; + if (!featureAssetManager.addAssetPath(featureAfter, NULL)) { + fprintf(stderr, "ERROR: Feature package '%s' not found.\n", + featureAfter.string()); + return UNKNOWN_ERROR; } - } - // Every resource table always has one first entry, the bag attributes. - const SourcePos unknown(String8("????"), 0); - sp<Type> attr = getType(mAssetsPackage, String16("attr"), unknown); + const ResTable& featureTable = featureAssetManager.getResources(false); + mTypeIdOffset = max(mTypeIdOffset, + findLargestTypeIdForPackage(featureTable, mAssetsPackage)); + } return NO_ERROR; } @@ -1820,24 +1820,16 @@ status_t ResourceTable::addEntry(const SourcePos& sourcePos, const int32_t format, const bool overwrite) { - // Check for adding entries in other packages... for now we do - // nothing. We need to do the right thing here to support skinning. uint32_t rid = mAssets->getIncludedResources() .identifierForName(name.string(), name.size(), type.string(), type.size(), package.string(), package.size()); if (rid != 0) { - return NO_ERROR; + sourcePos.error("Resource entry %s/%s is already defined in package %s.", + String8(type).string(), String8(name).string(), String8(package).string()); + return UNKNOWN_ERROR; } -#if 0 - if (name == String16("left")) { - printf("Adding entry left: file=%s, line=%d, type=%s, value=%s\n", - sourcePos.file.string(), sourcePos.line, String8(type).string(), - String8(value).string()); - } -#endif - sp<Entry> e = getEntry(package, type, name, sourcePos, overwrite, params, doSetIndex); if (e == NULL) { @@ -1868,15 +1860,11 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos, type.string(), type.size(), package.string(), package.size()); if (rid != 0) { - return NO_ERROR; - } - -#if 0 - if (name == String16("left")) { - printf("Adding bag left: file=%s, line=%d, type=%s\n", - sourcePos.file.striing(), sourcePos.line, String8(type).string()); + sourcePos.error("Resource entry %s/%s is already defined in package %s.", + String8(type).string(), String8(name).string(), String8(package).string()); + return UNKNOWN_ERROR; } -#endif + if (overlay && !mBundle->getAutoAddOverlay() && !hasBagOrEntry(package, type, name)) { bool canAdd = false; sp<Package> p = mPackages.valueFor(package); @@ -2117,9 +2105,6 @@ uint32_t ResourceTable::getResId(const String16& package, uint32_t id = ResourceIdCache::lookup(package, type, name, onlyPublic); if (id != 0) return id; // cache hit - sp<Package> p = mPackages.valueFor(package); - if (p == NULL) return 0; - // First look for this in the included resources... uint32_t specFlags = 0; uint32_t rid = mAssets->getIncludedResources() @@ -2134,13 +2119,11 @@ uint32_t ResourceTable::getResId(const String16& package, } } - if (Res_INTERNALID(rid)) { - return ResourceIdCache::store(package, type, name, onlyPublic, rid); - } - return ResourceIdCache::store(package, type, name, onlyPublic, - Res_MAKEID(p->getAssignedId()-1, Res_GETTYPE(rid), Res_GETENTRY(rid))); + return ResourceIdCache::store(package, type, name, onlyPublic, rid); } + sp<Package> p = mPackages.valueFor(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); @@ -2294,9 +2277,12 @@ uint32_t ResourceTable::getCustomResourceWithCreation( } if (mAssetsPackage != package) { - mCurrentXmlPos.warning("creating resource for external package %s: %s/%s.", + mCurrentXmlPos.error("creating resource for external package %s: %s/%s.", String8(package).string(), String8(type).string(), String8(name).string()); - mCurrentXmlPos.printf("This will be an error in a future version of AAPT."); + if (package == String16("android")) { + mCurrentXmlPos.printf("did you mean to use @+id instead of @+android:id?"); + } + return 0; } String16 value("false"); @@ -2479,6 +2465,7 @@ status_t ResourceTable::assignResourceIds() continue; } + // 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) { firstError = err; @@ -2512,6 +2499,11 @@ status_t ResourceTable::assignResourceIds() } } + uint32_t typeIdOffset = 0; + if (mPackageType == AppFeature && p->getName() == mAssetsPackage) { + typeIdOffset = mTypeIdOffset; + } + const SourcePos unknown(String8("????"), 0); sp<Type> attr = p->getType(String16("attr"), unknown); @@ -2527,7 +2519,7 @@ status_t ResourceTable::assignResourceIds() } const size_t N = t->getOrderedConfigs().size(); - t->setIndex(ti+1); + t->setIndex(ti + 1 + typeIdOffset); LOG_ALWAYS_FATAL_IF(ti == 0 && attr != t, "First type is not attr!"); @@ -2599,7 +2591,7 @@ status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols) { if (rid == 0) { return UNKNOWN_ERROR; } - if (Res_GETPACKAGE(rid) == (size_t)(p->getAssignedId()-1)) { + if (Res_GETPACKAGE(rid) + 1 == p->getAssignedId()) { typeSymbols->addSymbol(String8(c->getName()), rid, c->getPos()); String16 comment(c->getComment()); @@ -2608,11 +2600,6 @@ status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols) { // String8(c->getName()).string(), String8(comment).string()); comment = c->getTypeComment(); typeSymbols->appendTypeComment(String8(c->getName()), comment); - } else { -#if 0 - printf("**** NO MATCH: 0x%08x vs 0x%08x\n", - Res_GETPACKAGE(rid), p->getAssignedId()); -#endif } } } @@ -2749,7 +2736,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& } continue; } else if (p->getAssignedId() == 0x00) { - if (!bundle->getBuildSharedLibrary()) { + if (mPackageType != SharedLibrary) { fprintf(stderr, "ERROR: Package %s can not have ID=0x00 unless building a shared library.", String8(p->getName()).string()); return UNKNOWN_ERROR; @@ -2761,15 +2748,24 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& StringPool typeStrings(useUTF8); StringPool keyStrings(useUTF8); + ssize_t stringsAdded = 0; const size_t N = p->getOrderedTypes().size(); for (size_t ti=0; ti<N; ti++) { sp<Type> t = p->getOrderedTypes().itemAt(ti); if (t == NULL) { typeStrings.add(String16("<empty>"), false); + stringsAdded++; continue; } + + while (stringsAdded < t->getIndex() - 1) { + typeStrings.add(String16("<empty>"), false); + stringsAdded++; + } + const String16 typeName(t->getName()); typeStrings.add(typeName, false); + stringsAdded++; // This is a hack to tweak the sorting order of the final strings, // to put stuff that is generally not language-specific first. @@ -2862,7 +2858,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& memset(header, 0, sizeof(*header)); header->header.type = htods(RES_TABLE_PACKAGE_TYPE); header->header.headerSize = htods(sizeof(*header)); - header->id = htodl(p->getAssignedId()); + header->id = htodl(static_cast<uint32_t>(p->getAssignedId())); strcpy16_htod(header->name, p->getName().string()); // Write the string blocks. @@ -2902,7 +2898,9 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16("<empty>"), "Type name %s not found", String8(typeName).string()); - + if (t == NULL) { + continue; + } const bool filterable = (typeName != mipmap16); const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0; @@ -3062,21 +3060,25 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& tHeader->header.size = htodl(data->getSize()-typeStart); } - bool missing_entry = false; - const char* log_prefix = bundle->getErrorOnMissingConfigEntry() ? - "error" : "warning"; - 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)); - missing_entry = true; + // If we're building splits, then each invocation of the flattening + // step will have 'missing' entries. Don't warn/error for this case. + if (bundle->getSplitConfigurations().isEmpty()) { + bool missing_entry = false; + const char* log_prefix = bundle->getErrorOnMissingConfigEntry() ? + "error" : "warning"; + 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)); + missing_entry = true; + } + } + if (bundle->getErrorOnMissingConfigEntry() && missing_entry) { + fprintf(stderr, "Error: Missing entries, quit!\n"); + return NOT_ENOUGH_DATA; } - } - if (bundle->getErrorOnMissingConfigEntry() && missing_entry) { - fprintf(stderr, "Error: Missing entries, quit!\n"); - return NOT_ENOUGH_DATA; } } @@ -3819,8 +3821,8 @@ status_t ResourceTable::Type::applyPublicEntryOrder() return hasError ? UNKNOWN_ERROR : NO_ERROR; } -ResourceTable::Package::Package(const String16& name, ssize_t includedId) - : mName(name), mIncludedId(includedId), +ResourceTable::Package::Package(const String16& name, size_t packageId) + : mName(name), mPackageId(packageId), mTypeStringsMapping(0xffffffff), mKeyStringsMapping(0xffffffff) { @@ -3945,26 +3947,10 @@ status_t ResourceTable::Package::applyPublicTypeOrder() sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package) { - sp<Package> p = mPackages.valueFor(package); - if (p == NULL) { - if (mIsAppPackage) { - if (mHaveAppPackage) { - fprintf(stderr, "Adding multiple application package resources; only one is allowed.\n" - "Use -x to create extended resources.\n"); - return NULL; - } - mHaveAppPackage = true; - p = new Package(package, mIsSharedLibrary ? 0 : 127); - } else { - p = new Package(package, mNextPackageId); - } - //printf("*** NEW PACKAGE: \"%s\" id=%d\n", - // String8(package).string(), p->getAssignedId()); - mPackages.add(package, p); - mOrderedPackages.add(p); - mNextPackageId++; + if (package != mAssetsPackage) { + return NULL; } - return p; + return mPackages.valueFor(package); } sp<ResourceTable::Type> ResourceTable::getType(const String16& package, @@ -3997,11 +3983,10 @@ sp<ResourceTable::Entry> ResourceTable::getEntry(const String16& package, sp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID, const ResTable_config* config) const { - int pid = Res_GETPACKAGE(resID)+1; + size_t pid = Res_GETPACKAGE(resID)+1; const size_t N = mOrderedPackages.size(); - size_t i; sp<Package> p; - for (i=0; i<N; i++) { + for (size_t i = 0; i < N; i++) { sp<Package> check = mOrderedPackages[i]; if (check->getAssignedId() == pid) { p = check; |