]> git.saurik.com Git - android/aapt.git/commitdiff
Add --output-text-symbols option to aapt.
authorXavier Ducrohet <xav@android.com>
Tue, 11 Sep 2012 21:45:22 +0000 (14:45 -0700)
committerXavier Ducrohet <xav@android.com>
Wed, 12 Sep 2012 01:19:00 +0000 (18:19 -0700)
Library projects in the SDK are built using --non-constant-id
to generate a temporary R.java class.
When the library is packaged with the application to generate an
apk, the R class is recreated with the proper IDs due to all the
resources coming from the app and all the libraries.

However for large apps with many libraries (each with their own
R class in their package), this means a lot of unnecessary IDs:
all R classes contains all the IDs including for resources from
by projects they don't have access through the dependency graph.

For really large apps (X,000 resources), with lots of libraries
(10+), this can generate tens of thousands of resources, which
can trigger dalvik's limit of 65K fields and methods per dex
files.

This changes lets aapt generate not only the R class but a simple
text file containing the list of all those IDs so that it is
easier to parse back. The SDK build system will not ask aapt
to generate the R class of the libraries (through the
--extra-packages option), instead it will then read this
file to know what IDs are needed for each library and generate
a much smaller R class for each library (using the same text
file output from compiling all the resources to get the final
integer value).

Change-Id: I4db959fec372cf3ead9950e4b2b82fa1ae7eed2d

Bundle.h
Main.cpp
Resource.cpp

index be0829185897bc2a5308f34b4df8798782cfc358..fde3bd68f834606299e816108d202c6246826f17 100644 (file)
--- a/Bundle.h
+++ b/Bundle.h
@@ -61,7 +61,8 @@ public:
           mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
           mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), mExtraPackages(NULL),
           mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false), mProduct(NULL),
-          mUseCrunchCache(false), mErrorOnFailedInsert(false), mArgc(0), mArgv(NULL)
+          mUseCrunchCache(false), mErrorOnFailedInsert(false), mOutputTextSymbols(NULL),
+          mArgc(0), mArgv(NULL)
         {}
     ~Bundle(void) {}
 
@@ -173,6 +174,8 @@ public:
     void setProduct(const char * val) { mProduct = val; }
     void setUseCrunchCache(bool val) { mUseCrunchCache = val; }
     bool getUseCrunchCache() const { return mUseCrunchCache; }
+    const char* getOutputTextSymbols() const { return mOutputTextSymbols; }
+    void setOutputTextSymbols(const char* val) { mOutputTextSymbols = val; }
 
     /*
      * Set and get the file specification.
@@ -279,6 +282,7 @@ private:
     const char* mProduct;
     bool        mUseCrunchCache;
     bool        mErrorOnFailedInsert;
+    const char* mOutputTextSymbols;
 
     /* file specification */
     int         mArgc;
index 1773f48e59be2348fb9dabacf7c5004bfb828cae..f398de0630b981cdd655da2c1322508cf8b60aa1 100644 (file)
--- a/Main.cpp
+++ b/Main.cpp
@@ -69,7 +69,8 @@ void usage(void)
         "        [-F apk-file] [-J R-file-dir] \\\n"
         "        [--product product1,product2,...] \\\n"
         "        [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
-        "        [raw-files-dir [raw-files-dir] ...]\n"
+        "        [raw-files-dir [raw-files-dir] ...] \\\n"
+        "        [--output-text-symbols DIR]\n"
         "\n"
         "   Package the android resources.  It will read assets and resources that are\n"
         "   supplied with the -M -A -S or raw-files-dir arguments.  The -J -P -F and -R\n"
@@ -182,6 +183,9 @@ void usage(void)
         "       with --debug-mode, --min-sdk-version, --target-sdk-version --version-code\n"
         "       and --version-name.\n"
         "       Insertion typically fails if the manifest already defines the attribute.\n"
+        "   --output-text-symbols\n"
+        "       Generates a text file containing the resource symbols of the R class in the\n"
+        "       specified folder.\n"
         "   --ignore-assets\n"
         "       Assets to be ignored. Default pattern is:\n"
         "       %s\n",
@@ -549,6 +553,15 @@ int main(int argc, char* const argv[])
                     bundle.setAutoAddOverlay(true);
                 } else if (strcmp(cp, "-error-on-failed-insert") == 0) {
                     bundle.setErrorOnFailedInsert(true);
+                } else if (strcmp(cp, "-output-text-symbols") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '-output-text-symbols' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setOutputTextSymbols(argv[0]);
                 } else if (strcmp(cp, "-product") == 0) {
                     argc--;
                     argv++;
index e2e0dc37ce961f585f4296f8c50262d018cee926..50334185fdf576c0cf82c19f98bfe9b9ec855dcb 100644 (file)
@@ -1852,6 +1852,110 @@ static status_t writeLayoutClasses(
     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,
@@ -1879,7 +1983,6 @@ static status_t writeSymbolClass(
             continue;
         }
         String16 name(sym.name);
-        String8 realName(name);
         if (fixupSymbol(&name) != NO_ERROR) {
             return UNKNOWN_ERROR;
         }
@@ -1991,6 +2094,51 @@ static status_t writeSymbolClass(
     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)
 {
@@ -1998,11 +2146,15 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
         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();
@@ -2034,14 +2186,14 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
         }
 
         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());
+            "/* 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());
@@ -2050,14 +2202,37 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
         }
         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);
         }
@@ -2067,7 +2242,6 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
 }
 
 
-
 class ProguardKeepSet
 {
 public: