Add error checking to aapt for split generation

Change-Id: Ica627db6a671f6a6c35f98bfd9c03598ffe103ce
This commit is contained in:
Adam Lesinski
2014-11-03 12:03:08 -08:00
parent f7ffcaa7a4
commit de7de47fef
9 changed files with 241 additions and 5 deletions

View File

@ -3645,8 +3645,12 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
Entry entry;
status_t err = getEntry(grp, t, e, &desiredConfig, &entry);
if (err != NO_ERROR) {
// Only log the failure when we're not running on the host as
// part of a tool. The caller will do its own logging.
#ifndef STATIC_ANDROIDFW_FOR_TOOLS
ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) (error %d)\n",
resID, t, e, err);
#endif
return err;
}

View File

@ -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

View File

@ -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

View File

@ -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 <algorithm>
#if HAVE_PRINTF_ZD
# define ZD "%zd"
# define ZD_TYPE ssize_t
@ -1550,6 +1554,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
// Re-flatten because we may have added new resource IDs
// --------------------------------------------------------------
ResTable finalResTable;
sp<AaptFile> resFile;
@ -1560,6 +1565,13 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil
return err;
}
KeyedVector<Symbol, Vector<SymbolDefinition> > densityVaryingResources;
if (builder->getSplits().size() > 1) {
// Only look for density varying resources if we're generating
// splits.
table.getDensityVaryingResources(densityVaryingResources);
}
Vector<sp<ApkSplit> >& 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<AaptAssets>& assets, sp<ApkBuil
return err;
}
} else {
ResTable resTable;
err = resTable.add(flattenedTable->getData(), 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<ConfigDescription>& splitConfigs = split->getConfigs();
for (std::set<ConfigDescription>::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<SymbolDefinition>& 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<AaptFile> generatedManifest = new AaptFile(String8("AndroidManifest.xml"),
AaptGroupEntry(), String8());
err = generateAndroidManifestForSplit(bundle, assets, split,

View File

@ -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<Symbol, Vector<SymbolDefinition> >& resources) {
const ConfigDescription nullConfig;
const size_t packageCount = mOrderedPackages.size();
for (size_t p = 0; p < packageCount; p++) {
const Vector<sp<Type> >& types = mOrderedPackages[p]->getOrderedTypes();
const size_t typeCount = types.size();
for (size_t t = 0; t < typeCount; t++) {
const Vector<sp<ConfigList> >& configs = types[t]->getOrderedConfigs();
const size_t configCount = configs.size();
for (size_t c = 0; c < configCount; c++) {
const DefaultKeyedVector<ConfigDescription, sp<Entry> >& 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>& entry = configEntries.valueAt(ce);
AaptUtil::appendValue(resources, symbol, SymbolDefinition(symbol, config, entry->getPos()));
}
}
}
}
}
}

View File

@ -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 <map>
#include <queue>
#include <set>
#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<String16, uint32_t> mKeyStringsMapping;
};
void getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources);
private:
void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
sp<Package> getPackage(const String16& package);

View File

@ -140,6 +140,12 @@ SourcePos::printf(const char* fmt, ...) const
ErrorPos(this->file, this->line, msg, ErrorPos::NOTE).print(stderr);
}
bool
SourcePos::operator<(const SourcePos& rhs) const
{
return (file < rhs.file) || (line < rhs.line);
}
bool
SourcePos::hasErrors()
{

View File

@ -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);
};

95
tools/aapt/Symbol.h Normal file
View File

@ -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 <utils/String8.h>
#include <utils/String16.h>
#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