From de7de47fef1dcaa26d553665d89e4d3792325c3f Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 3 Nov 2014 12:03:08 -0800 Subject: Add error checking to aapt for split generation Change-Id: Ica627db6a671f6a6c35f98bfd9c03598ffe103ce --- tools/aapt/AaptConfig.cpp | 19 +++++++++ tools/aapt/AaptConfig.h | 6 +++ tools/aapt/Resource.cpp | 69 ++++++++++++++++++++++++++++++++ tools/aapt/ResourceTable.cpp | 32 +++++++++++++++ tools/aapt/ResourceTable.h | 13 +++--- tools/aapt/SourcePos.cpp | 6 +++ tools/aapt/SourcePos.h | 2 + tools/aapt/Symbol.h | 95 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 237 insertions(+), 5 deletions(-) create mode 100644 tools/aapt/Symbol.h (limited to 'tools/aapt') diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp index f447462..848d9a1 100644 --- a/tools/aapt/AaptConfig.cpp +++ b/tools/aapt/AaptConfig.cpp @@ -794,4 +794,23 @@ bool isSameExcept(const ResTable_config& a, const ResTable_config& b, int axisMa return a.diff(b) == axisMask; } +bool isDensityOnly(const ResTable_config& config) { + if (config.density == ResTable_config::DENSITY_NONE) { + return false; + } + + if (config.density == ResTable_config::DENSITY_ANY) { + if (config.sdkVersion != SDK_L) { + // Someone modified the sdkVersion from the default, this is not safe to assume. + return false; + } + } else if (config.sdkVersion != SDK_DONUT) { + return false; + } + + const uint32_t mask = ResTable_config::CONFIG_DENSITY | ResTable_config::CONFIG_VERSION; + const ConfigDescription nullConfig; + return (nullConfig.diff(config) & ~mask) == 0; +} + } // namespace AaptConfig diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h index 2963539..f73a508 100644 --- a/tools/aapt/AaptConfig.h +++ b/tools/aapt/AaptConfig.h @@ -80,6 +80,12 @@ android::String8 getVersion(const android::ResTable_config& config); */ bool isSameExcept(const android::ResTable_config& a, const android::ResTable_config& b, int configMask); +/** + * Returns true if the configuration only has the density specified. In the case + * of 'anydpi', the version is ignored. + */ +bool isDensityOnly(const android::ResTable_config& config); + } // namespace AaptConfig #endif // __AAPT_CONFIG_H diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index b9bd03a..0d8db13 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -4,6 +4,7 @@ // Build resource files from raw assets. // #include "AaptAssets.h" +#include "AaptUtil.h" #include "AaptXml.h" #include "CacheUpdater.h" #include "CrunchCache.h" @@ -13,9 +14,12 @@ #include "Main.h" #include "ResourceTable.h" #include "StringPool.h" +#include "Symbol.h" #include "WorkQueue.h" #include "XMLNode.h" +#include + #if HAVE_PRINTF_ZD # define ZD "%zd" # define ZD_TYPE ssize_t @@ -1550,6 +1554,7 @@ status_t buildResources(Bundle* bundle, const sp& assets, sp resFile; @@ -1560,6 +1565,13 @@ status_t buildResources(Bundle* bundle, const sp& assets, sp > densityVaryingResources; + if (builder->getSplits().size() > 1) { + // Only look for density varying resources if we're generating + // splits. + table.getDensityVaryingResources(densityVaryingResources); + } + Vector >& splits = builder->getSplits(); const size_t numSplits = splits.size(); for (size_t i = 0; i < numSplits; i++) { @@ -1583,6 +1595,63 @@ status_t buildResources(Bundle* bundle, const sp& assets, spgetData(), flattenedTable->getSize()); + if (err != NO_ERROR) { + fprintf(stderr, "Generated resource table for split '%s' is corrupt.\n", + split->getPrintableName().string()); + return err; + } + + bool hasError = false; + const std::set& splitConfigs = split->getConfigs(); + for (std::set::const_iterator iter = splitConfigs.begin(); + iter != splitConfigs.end(); + ++iter) { + const ConfigDescription& config = *iter; + if (AaptConfig::isDensityOnly(config)) { + // Each density only split must contain all + // density only resources. + Res_value val; + resTable.setParameters(&config); + const size_t densityVaryingResourceCount = densityVaryingResources.size(); + for (size_t k = 0; k < densityVaryingResourceCount; k++) { + const Symbol& symbol = densityVaryingResources.keyAt(k); + ssize_t block = resTable.getResource(symbol.id, &val, true); + if (block < 0) { + // Maybe it's in the base? + finalResTable.setParameters(&config); + block = finalResTable.getResource(symbol.id, &val, true); + } + + if (block < 0) { + hasError = true; + SourcePos().error("%s has no definition for density split '%s'", + symbol.toString().string(), config.toString().string()); + + if (bundle->getVerbose()) { + const Vector& defs = densityVaryingResources[k]; + const size_t defCount = std::min(size_t(5), defs.size()); + for (size_t d = 0; d < defCount; d++) { + const SymbolDefinition& def = defs[d]; + def.source.error("%s has definition for %s", + symbol.toString().string(), def.config.toString().string()); + } + + if (defCount < defs.size()) { + SourcePos().error("and %d more ...", (int) (defs.size() - defCount)); + } + } + } + } + } + } + + if (hasError) { + return UNKNOWN_ERROR; + } + + // Generate the AndroidManifest for this split. sp generatedManifest = new AaptFile(String8("AndroidManifest.xml"), AaptGroupEntry(), String8()); err = generateAndroidManifestForSplit(bundle, assets, split, diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 0f94f85..beff604 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -6,6 +6,7 @@ #include "ResourceTable.h" +#include "AaptUtil.h" #include "XMLNode.h" #include "ResourceFilter.h" #include "ResourceIdCache.h" @@ -4486,3 +4487,34 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle, return NO_ERROR; } + +void ResourceTable::getDensityVaryingResources(KeyedVector >& resources) { + const ConfigDescription nullConfig; + + const size_t packageCount = mOrderedPackages.size(); + for (size_t p = 0; p < packageCount; p++) { + const Vector >& types = mOrderedPackages[p]->getOrderedTypes(); + const size_t typeCount = types.size(); + for (size_t t = 0; t < typeCount; t++) { + const Vector >& configs = types[t]->getOrderedConfigs(); + const size_t configCount = configs.size(); + for (size_t c = 0; c < configCount; c++) { + const DefaultKeyedVector >& configEntries = configs[c]->getEntries(); + const size_t configEntryCount = configEntries.size(); + for (size_t ce = 0; ce < configEntryCount; ce++) { + const ConfigDescription& config = configEntries.keyAt(ce); + if (AaptConfig::isDensityOnly(config)) { + // This configuration only varies with regards to density. + const Symbol symbol(mOrderedPackages[p]->getName(), + types[t]->getName(), + configs[c]->getName(), + getResId(mOrderedPackages[p], types[t], configs[c]->getEntryIndex())); + + const sp& entry = configEntries.valueAt(ce); + AaptUtil::appendValue(resources, symbol, SymbolDefinition(symbol, config, entry->getPos())); + } + } + } + } + } +} diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index eac5dd3..db392c8 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -7,15 +7,16 @@ #ifndef RESOURCE_TABLE_H #define RESOURCE_TABLE_H -#include "ConfigDescription.h" -#include "StringPool.h" -#include "SourcePos.h" -#include "ResourceFilter.h" - #include #include #include +#include "ConfigDescription.h" +#include "ResourceFilter.h" +#include "SourcePos.h" +#include "StringPool.h" +#include "Symbol.h" + using namespace std; class XMLNode; @@ -543,6 +544,8 @@ public: DefaultKeyedVector mKeyStringsMapping; }; + void getDensityVaryingResources(KeyedVector >& resources); + private: void writePublicDefinitions(const String16& package, FILE* fp, bool pub); sp getPackage(const String16& package); diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp index ae25047..3864320 100644 --- a/tools/aapt/SourcePos.cpp +++ b/tools/aapt/SourcePos.cpp @@ -141,6 +141,12 @@ SourcePos::printf(const char* fmt, ...) const } bool +SourcePos::operator<(const SourcePos& rhs) const +{ + return (file < rhs.file) || (line < rhs.line); +} + +bool SourcePos::hasErrors() { return g_errors.size() > 0; diff --git a/tools/aapt/SourcePos.h b/tools/aapt/SourcePos.h index 4ce817f..13cfb9d 100644 --- a/tools/aapt/SourcePos.h +++ b/tools/aapt/SourcePos.h @@ -21,6 +21,8 @@ public: void warning(const char* fmt, ...) const; void printf(const char* fmt, ...) const; + bool operator<(const SourcePos& rhs) const; + static bool hasErrors(); static void printErrors(FILE* to); }; diff --git a/tools/aapt/Symbol.h b/tools/aapt/Symbol.h new file mode 100644 index 0000000..e157541 --- /dev/null +++ b/tools/aapt/Symbol.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AAPT_SYMBOL_H +#define AAPT_SYMBOL_H + +#include +#include + +#include "ConfigDescription.h" +#include "SourcePos.h" + +/** + * A resource symbol, not attached to any configuration or context. + */ +struct Symbol { + inline Symbol(); + inline Symbol(const android::String16& p, const android::String16& t, const android::String16& n, uint32_t i); + inline android::String8 toString() const; + inline bool operator<(const Symbol& rhs) const; + + android::String16 package; + android::String16 type; + android::String16 name; + uint32_t id; + +}; + +/** + * A specific defintion of a symbol, defined with a configuration and a definition site. + */ +struct SymbolDefinition { + inline SymbolDefinition(); + inline SymbolDefinition(const Symbol& s, const ConfigDescription& c, const SourcePos& src); + inline bool operator<(const SymbolDefinition& rhs) const; + + Symbol symbol; + ConfigDescription config; + SourcePos source; +}; + +// +// Implementations +// + +Symbol::Symbol() { +} + +Symbol::Symbol(const android::String16& p, const android::String16& t, const android::String16& n, uint32_t i) + : package(p) + , type(t) + , name(n) + , id(i) { +} + +android::String8 Symbol::toString() const { + return android::String8::format("%s:%s/%s (0x%08x)", + android::String8(package).string(), + android::String8(type).string(), + android::String8(name).string(), + (int) id); +} + +bool Symbol::operator<(const Symbol& rhs) const { + return (package < rhs.package) || (type < rhs.type) || (name < rhs.name) || (id < rhs.id); +} + +SymbolDefinition::SymbolDefinition() { +} + +SymbolDefinition::SymbolDefinition(const Symbol& s, const ConfigDescription& c, const SourcePos& src) + : symbol(s) + , config(c) + , source(src) { +} + +bool SymbolDefinition::operator<(const SymbolDefinition& rhs) const { + return (symbol < rhs.symbol) || (config < rhs.config) || (source < rhs.source); +} + +#endif // AAPT_SYMBOL_H + -- cgit v1.1