Add error checking to aapt for split generation
Change-Id: Ica627db6a671f6a6c35f98bfd9c03598ffe103ce
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
95
tools/aapt/Symbol.h
Normal 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
|
||||
|
Reference in New Issue
Block a user