#include "FileFinder.h"
#include "CacheUpdater.h"
+#include <utils/WorkQueue.h>
+
#if HAVE_PRINTF_ZD
# define ZD "%zd"
# define ZD_TYPE ssize_t
#define NOISY(x) // x
+// Number of threads to use for preprocessing images.
+static const size_t MAX_THREADS = 4;
+
// ==========================================================================
// ==========================================================================
// ==========================================================================
return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
}
-static status_t preProcessImages(Bundle* bundle, const sp<AaptAssets>& assets,
+class PreProcessImageWorkUnit : public WorkQueue::WorkUnit {
+public:
+ PreProcessImageWorkUnit(const Bundle* bundle, const sp<AaptAssets>& assets,
+ const sp<AaptFile>& file, volatile bool* hasErrors) :
+ mBundle(bundle), mAssets(assets), mFile(file), mHasErrors(hasErrors) {
+ }
+
+ virtual bool run() {
+ status_t status = preProcessImage(mBundle, mAssets, mFile, NULL);
+ if (status) {
+ *mHasErrors = true;
+ }
+ return true; // continue even if there are errors
+ }
+
+private:
+ const Bundle* mBundle;
+ sp<AaptAssets> mAssets;
+ sp<AaptFile> mFile;
+ volatile bool* mHasErrors;
+};
+
+static status_t preProcessImages(const Bundle* bundle, const sp<AaptAssets>& assets,
const sp<ResourceTypeSet>& set, const char* type)
{
- bool hasErrors = false;
+ volatile bool hasErrors = false;
ssize_t res = NO_ERROR;
if (bundle->getUseCrunchCache() == false) {
+ WorkQueue wq(MAX_THREADS, false);
ResourceDirIterator it(set, String8(type));
- Vector<sp<AaptFile> > newNameFiles;
- Vector<String8> newNamePaths;
while ((res=it.next()) == NO_ERROR) {
- res = preProcessImage(bundle, assets, it.getFile(), NULL);
- if (res < NO_ERROR) {
+ PreProcessImageWorkUnit* w = new PreProcessImageWorkUnit(
+ bundle, assets, it.getFile(), &hasErrors);
+ status_t status = wq.schedule(w);
+ if (status) {
+ fprintf(stderr, "preProcessImages failed: schedule() returned %d\n", status);
hasErrors = true;
+ delete w;
+ break;
}
}
+ status_t status = wq.finish();
+ if (status) {
+ fprintf(stderr, "preProcessImages failed: finish() returned %d\n", status);
+ hasErrors = true;
+ }
}
return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
}
return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
}
+static status_t writeTextLayoutClasses(
+ FILE* fp, const sp<AaptAssets>& assets,
+ const sp<AaptSymbols>& symbols, bool includePrivate)
+{
+ String16 attr16("attr");
+ String16 package16(assets->getPackage());
+
+ bool hasErrors = false;
+
+ size_t i;
+ size_t N = symbols->getNestedSymbols().size();
+ for (i=0; i<N; i++) {
+ sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i);
+ String16 nclassName16(symbols->getNestedSymbols().keyAt(i));
+ String8 realClassName(nclassName16);
+ if (fixupSymbol(&nclassName16) != NO_ERROR) {
+ hasErrors = true;
+ }
+ String8 nclassName(nclassName16);
+
+ SortedVector<uint32_t> idents;
+ Vector<uint32_t> origOrder;
+ Vector<bool> publicFlags;
+
+ size_t a;
+ size_t NA = nsymbols->getSymbols().size();
+ for (a=0; a<NA; a++) {
+ const AaptSymbolEntry& sym(nsymbols->getSymbols().valueAt(a));
+ int32_t code = sym.typeCode == AaptSymbolEntry::TYPE_INT32
+ ? sym.int32Val : 0;
+ bool isPublic = true;
+ if (code == 0) {
+ String16 name16(sym.name);
+ uint32_t typeSpecFlags;
+ code = assets->getIncludedResources().identifierForName(
+ name16.string(), name16.size(),
+ attr16.string(), attr16.size(),
+ package16.string(), package16.size(), &typeSpecFlags);
+ if (code == 0) {
+ fprintf(stderr, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n",
+ nclassName.string(), sym.name.string());
+ hasErrors = true;
+ }
+ isPublic = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
+ }
+ idents.add(code);
+ origOrder.add(code);
+ publicFlags.add(isPublic);
+ }
+
+ NA = idents.size();
+
+ fprintf(fp, "int[] styleable %s {", nclassName.string());
+
+ for (a=0; a<NA; a++) {
+ if (a != 0) {
+ fprintf(fp, ",");
+ }
+ fprintf(fp, " 0x%08x", idents[a]);
+ }
+
+ fprintf(fp, " }\n");
+
+ for (a=0; a<NA; a++) {
+ ssize_t pos = idents.indexOf(origOrder.itemAt(a));
+ if (pos >= 0) {
+ const AaptSymbolEntry& sym = nsymbols->getSymbols().valueAt(a);
+ if (!publicFlags.itemAt(a) && !includePrivate) {
+ continue;
+ }
+ String8 name8(sym.name);
+ String16 comment(sym.comment);
+ String16 typeComment;
+ if (comment.size() <= 0) {
+ comment = getAttributeComment(assets, name8, &typeComment);
+ } else {
+ getAttributeComment(assets, name8, &typeComment);
+ }
+ String16 name(name8);
+ if (fixupSymbol(&name) != NO_ERROR) {
+ hasErrors = true;
+ }
+
+ uint32_t typeSpecFlags = 0;
+ String16 name16(sym.name);
+ assets->getIncludedResources().identifierForName(
+ name16.string(), name16.size(),
+ attr16.string(), attr16.size(),
+ package16.string(), package16.size(), &typeSpecFlags);
+ //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
+ // String8(attr16).string(), String8(name16).string(), typeSpecFlags);
+ const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
+
+ fprintf(fp,
+ "int styleable %s_%s %d\n",
+ nclassName.string(),
+ String8(name).string(), (int)pos);
+ }
+ }
+ }
+
+ return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+}
+
static status_t writeSymbolClass(
FILE* fp, const sp<AaptAssets>& assets, bool includePrivate,
const sp<AaptSymbols>& symbols, const String8& className, int indent,
if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) {
continue;
}
- if (!includePrivate && !sym.isPublic) {
+ if (!assets->isJavaSymbol(sym, includePrivate)) {
continue;
}
String16 name(sym.name);
- String8 realName(name);
if (fixupSymbol(&name) != NO_ERROR) {
return UNKNOWN_ERROR;
}
if (sym.typeCode != AaptSymbolEntry::TYPE_STRING) {
continue;
}
- if (!includePrivate && !sym.isPublic) {
+ if (!assets->isJavaSymbol(sym, includePrivate)) {
continue;
}
String16 name(sym.name);
return NO_ERROR;
}
+static status_t writeTextSymbolClass(
+ FILE* fp, const sp<AaptAssets>& assets, bool includePrivate,
+ const sp<AaptSymbols>& symbols, const String8& className)
+{
+ size_t i;
+ status_t err = NO_ERROR;
+
+ size_t N = symbols->getSymbols().size();
+ for (i=0; i<N; i++) {
+ const AaptSymbolEntry& sym = symbols->getSymbols().valueAt(i);
+ if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) {
+ continue;
+ }
+
+ if (!assets->isJavaSymbol(sym, includePrivate)) {
+ continue;
+ }
+
+ String16 name(sym.name);
+ if (fixupSymbol(&name) != NO_ERROR) {
+ return UNKNOWN_ERROR;
+ }
+
+ fprintf(fp, "int %s %s 0x%08x\n",
+ className.string(),
+ String8(name).string(), (int)sym.int32Val);
+ }
+
+ N = symbols->getNestedSymbols().size();
+ for (i=0; i<N; i++) {
+ sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i);
+ String8 nclassName(symbols->getNestedSymbols().keyAt(i));
+ if (nclassName == "styleable") {
+ err = writeTextLayoutClasses(fp, assets, nsymbols, includePrivate);
+ } else {
+ err = writeTextSymbolClass(fp, assets, includePrivate, nsymbols, nclassName);
+ }
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+
+ return NO_ERROR;
+}
+
status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
const String8& package, bool includePrivate)
{
return NO_ERROR;
}
+ const char* textSymbolsDest = bundle->getOutputTextSymbols();
+
+ String8 R("R");
const size_t N = assets->getSymbols().size();
for (size_t i=0; i<N; i++) {
sp<AaptSymbols> symbols = assets->getSymbols().valueAt(i);
String8 className(assets->getSymbols().keyAt(i));
String8 dest(bundle->getRClassDir());
+
if (bundle->getMakePackageDirs()) {
String8 pkg(package);
const char* last = pkg.string();
}
fprintf(fp,
- "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
- " *\n"
- " * This class was automatically generated by the\n"
- " * aapt tool from the resource data it found. It\n"
- " * should not be modified by hand.\n"
- " */\n"
- "\n"
- "package %s;\n\n", package.string());
-
- status_t err = writeSymbolClass(fp, assets, includePrivate, symbols, className, 0, bundle->getNonConstantId());
+ "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
+ " *\n"
+ " * This class was automatically generated by the\n"
+ " * aapt tool from the resource data it found. It\n"
+ " * should not be modified by hand.\n"
+ " */\n"
+ "\n"
+ "package %s;\n\n", package.string());
+
+ status_t err = writeSymbolClass(fp, assets, includePrivate, symbols,
+ className, 0, bundle->getNonConstantId());
if (err != NO_ERROR) {
return err;
}
fclose(fp);
+ if (textSymbolsDest != NULL && R == className) {
+ String8 textDest(textSymbolsDest);
+ textDest.appendPath(className);
+ textDest.append(".txt");
+
+ FILE* fp = fopen(textDest.string(), "w+");
+ if (fp == NULL) {
+ fprintf(stderr, "ERROR: Unable to open text symbol file %s: %s\n",
+ textDest.string(), strerror(errno));
+ return UNKNOWN_ERROR;
+ }
+ if (bundle->getVerbose()) {
+ printf(" Writing text symbols for class %s.\n", className.string());
+ }
+
+ status_t err = writeTextSymbolClass(fp, assets, includePrivate, symbols,
+ className);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ fclose(fp);
+ }
+
// If we were asked to generate a dependency file, we'll go ahead and add this R.java
// as a target in the dependency file right next to it.
- if (bundle->getGenDependencies()) {
+ if (bundle->getGenDependencies() && R == className) {
// Add this R.java to the dependency file
String8 dependencyFile(bundle->getRClassDir());
dependencyFile.appendPath("R.java.d");
- fp = fopen(dependencyFile.string(), "a");
+ FILE *fp = fopen(dependencyFile.string(), "a");
fprintf(fp,"%s \\\n", dest.string());
fclose(fp);
}
}
-
class ProguardKeepSet
{
public:
keep->add(rule, location);
}
+void
+addProguardKeepMethodRule(ProguardKeepSet* keep, const String8& memberName,
+ const char* pkg, const String8& srcName, int line)
+{
+ String8 rule("-keepclassmembers class * { *** ");
+ rule += memberName;
+ rule += "(...); }";
+
+ String8 location("onClick ");
+ location += srcName;
+ char lineno[20];
+ sprintf(lineno, ":%d", line);
+ location += lineno;
+
+ keep->add(rule, location);
+}
+
status_t
writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
{
status_t
writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
- const char* startTag, const KeyedVector<String8, NamespaceAttributePair>* tagAttrPairs)
+ const char* startTag, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs)
{
status_t err;
ResXMLTree tree;
} else if (tagAttrPairs != NULL) {
ssize_t tagIndex = tagAttrPairs->indexOfKey(tag);
if (tagIndex >= 0) {
- const NamespaceAttributePair& nsAttr = tagAttrPairs->valueAt(tagIndex);
- ssize_t attrIndex = tree.indexOfAttribute(nsAttr.ns, nsAttr.attr);
- if (attrIndex < 0) {
- // fprintf(stderr, "%s:%d: <%s> does not have attribute %s:%s.\n",
- // layoutFile->getPrintableSource().string(), tree.getLineNumber(),
- // tag.string(), nsAttr.ns, nsAttr.attr);
- } else {
- size_t len;
- addProguardKeepRule(keep,
- String8(tree.getAttributeStringValue(attrIndex, &len)), NULL,
- layoutFile->getPrintableSource(), tree.getLineNumber());
+ const Vector<NamespaceAttributePair>& nsAttrVector = tagAttrPairs->valueAt(tagIndex);
+ for (size_t i = 0; i < nsAttrVector.size(); i++) {
+ const NamespaceAttributePair& nsAttr = nsAttrVector[i];
+
+ ssize_t attrIndex = tree.indexOfAttribute(nsAttr.ns, nsAttr.attr);
+ if (attrIndex < 0) {
+ // fprintf(stderr, "%s:%d: <%s> does not have attribute %s:%s.\n",
+ // layoutFile->getPrintableSource().string(), tree.getLineNumber(),
+ // tag.string(), nsAttr.ns, nsAttr.attr);
+ } else {
+ size_t len;
+ addProguardKeepRule(keep,
+ String8(tree.getAttributeStringValue(attrIndex, &len)), NULL,
+ layoutFile->getPrintableSource(), tree.getLineNumber());
+ }
}
}
}
+ ssize_t attrIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "onClick");
+ if (attrIndex >= 0) {
+ size_t len;
+ addProguardKeepMethodRule(keep,
+ String8(tree.getAttributeStringValue(attrIndex, &len)), NULL,
+ layoutFile->getPrintableSource(), tree.getLineNumber());
+ }
}
return NO_ERROR;
}
-static void addTagAttrPair(KeyedVector<String8, NamespaceAttributePair>* dest,
+static void addTagAttrPair(KeyedVector<String8, Vector<NamespaceAttributePair> >* dest,
const char* tag, const char* ns, const char* attr) {
- dest->add(String8(tag), NamespaceAttributePair(ns, attr));
+ String8 tagStr(tag);
+ ssize_t index = dest->indexOfKey(tagStr);
+
+ if (index < 0) {
+ Vector<NamespaceAttributePair> vector;
+ vector.add(NamespaceAttributePair(ns, attr));
+ dest->add(tagStr, vector);
+ } else {
+ dest->editValueAt(index).add(NamespaceAttributePair(ns, attr));
+ }
}
status_t
status_t err;
// tag:attribute pairs that should be checked in layout files.
- KeyedVector<String8, NamespaceAttributePair> kLayoutTagAttrPairs;
+ KeyedVector<String8, Vector<NamespaceAttributePair> > kLayoutTagAttrPairs;
addTagAttrPair(&kLayoutTagAttrPairs, "view", NULL, "class");
addTagAttrPair(&kLayoutTagAttrPairs, "fragment", NULL, "class");
addTagAttrPair(&kLayoutTagAttrPairs, "fragment", RESOURCES_ANDROID_NAMESPACE, "name");
// tag:attribute pairs that should be checked in xml files.
- KeyedVector<String8, NamespaceAttributePair> kXmlTagAttrPairs;
+ KeyedVector<String8, Vector<NamespaceAttributePair> > kXmlTagAttrPairs;
addTagAttrPair(&kXmlTagAttrPairs, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE, "fragment");
addTagAttrPair(&kXmlTagAttrPairs, "header", RESOURCES_ANDROID_NAMESPACE, "fragment");
const sp<AaptDir>& d = dirs.itemAt(k);
const String8& dirName = d->getLeaf();
const char* startTag = NULL;
- const KeyedVector<String8, NamespaceAttributePair>* tagAttrPairs = NULL;
+ const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL;
if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
tagAttrPairs = &kLayoutTagAttrPairs;
} else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
startTag = "PreferenceScreen";
tagAttrPairs = &kXmlTagAttrPairs;
+ } else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) {
+ startTag = "menu";
+ tagAttrPairs = NULL;
} else {
continue;
}
if (overlay.get()) {
return writeProguardForLayouts(keep, overlay);
}
+
return NO_ERROR;
}