From 6ba873faec0d165b74acfecf1533f58433d431e9 Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Thu, 21 Apr 2016 16:29:58 -0700 Subject: [PATCH] AAPT: ProGuard config for components in main dex. Create an analogue of "aapt -G" which outputs a proguard configuration that keeps only components which need to be in the main dex. BUG: 27383099 Change-Id: Ic18c8c563794ff27a5598a214111d1b446a005f1 (cherry picked from commit 86229cb622fccde8ab8cbe85eead91a34313a708) --- tools/aapt/Bundle.h | 5 ++- tools/aapt/Command.cpp | 6 +++ tools/aapt/Main.cpp | 13 ++++++ tools/aapt/Main.h | 1 + tools/aapt/Resource.cpp | 97 +++++++++++++++++++++++++++++++---------- 5 files changed, 98 insertions(+), 24 deletions(-) diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index cbe7c5dacc1e5..3f466ccc4fb77 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -55,7 +55,7 @@ public: mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL), mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL), mAutoAddOverlay(false), mGenDependencies(false), mNoVersionVectors(false), - mCrunchedOutputDir(NULL), mProguardFile(NULL), + mCrunchedOutputDir(NULL), mProguardFile(NULL), mMainDexProguardFile(NULL), mAndroidManifestFile(NULL), mPublicOutputFile(NULL), mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL), mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL), @@ -139,6 +139,8 @@ public: void setCrunchedOutputDir(const char* dir) { mCrunchedOutputDir = dir; } const char* getProguardFile() const { return mProguardFile; } void setProguardFile(const char* file) { mProguardFile = file; } + const char* getMainDexProguardFile() const { return mMainDexProguardFile; } + void setMainDexProguardFile(const char* file) { mMainDexProguardFile = file; } const android::Vector& getResourceSourceDirs() const { return mResourceSourceDirs; } void addResourceSourceDir(const char* dir) { mResourceSourceDirs.insertAt(dir,0); } const char* getAndroidManifestFile() const { return mAndroidManifestFile; } @@ -290,6 +292,7 @@ private: bool mNoVersionVectors; const char* mCrunchedOutputDir; const char* mProguardFile; + const char* mMainDexProguardFile; const char* mAndroidManifestFile; const char* mPublicOutputFile; const char* mRClassDir; diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index 5e2e82601b478..ba4aac6f32a8a 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -2573,6 +2573,12 @@ int doPackage(Bundle* bundle) goto bail; } + // Write out the Main Dex ProGuard file + err = writeMainDexProguardFile(bundle, assets); + if (err < 0) { + goto bail; + } + // Write the apk if (outputAPKFile) { // Gather all resources and add them to the APK Builder. The builder will then diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp index bcf0d5e53c077..28bdf44b08bd0 100644 --- a/tools/aapt/Main.cpp +++ b/tools/aapt/Main.cpp @@ -67,6 +67,7 @@ void usage(void) " [--max-res-version VAL] \\\n" " [-I base-package [-I base-package ...]] \\\n" " [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n" + " [-D main-dex-class-list-file] \\\n" " [-S resource-sources [-S resource-sources ...]] \\\n" " [-F apk-file] [-J R-file-dir] \\\n" " [--product product1,product2,...] \\\n" @@ -120,6 +121,7 @@ void usage(void) " localization=\"suggested\"\n" " -A additional directory in which to find raw asset files\n" " -G A file to output proguard options into.\n" + " -D A file to output proguard options for the main dex into.\n" " -F specify the apk file to output\n" " -I add an existing package to base include set\n" " -J specify where to output R.java resource constant definitions\n" @@ -385,6 +387,17 @@ int main(int argc, char* const argv[]) convertPath(argv[0]); bundle.setProguardFile(argv[0]); break; + case 'D': + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '-D' option\n"); + wantUsage = true; + goto bail; + } + convertPath(argv[0]); + bundle.setMainDexProguardFile(argv[0]); + break; case 'I': argc--; argv++; diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h index e84c4c503cd2a..a493842b8d103 100644 --- a/tools/aapt/Main.h +++ b/tools/aapt/Main.h @@ -54,6 +54,7 @@ extern android::status_t writeResourceSymbols(Bundle* bundle, bool includePrivate, bool emitCallback); extern android::status_t writeProguardFile(Bundle* bundle, const sp& assets); +extern android::status_t writeMainDexProguardFile(Bundle* bundle, const sp& assets); extern bool isValidResourceType(const String8& type); diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 1b30d362a7169..d05ae3cec0286 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -2830,7 +2830,7 @@ addProguardKeepMethodRule(ProguardKeepSet* keep, const String8& memberName, } status_t -writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp& assets) +writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp& assets, bool mainDex) { status_t err; ResXMLTree tree; @@ -2842,6 +2842,7 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp& ass sp assGroup; sp assFile; String8 pkg; + String8 defaultProcess; // First, look for a package file to parse. This is required to // be able to generate the resource information. @@ -2898,6 +2899,15 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp& ass addProguardKeepRule(keep, agent, pkg.string(), assFile->getPrintableSource(), tree.getLineNumber()); } + + if (mainDex) { + defaultProcess = AaptXml::getAttribute(tree, + "http://schemas.android.com/apk/res/android", "process", &error); + if (error != "") { + fprintf(stderr, "ERROR: %s\n", error.string()); + return -1; + } + } } else if (tag == "instrumentation") { keepTag = true; } @@ -2914,7 +2924,23 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp& ass fprintf(stderr, "ERROR: %s\n", error.string()); return -1; } - if (name.length() > 0) { + + keepTag = name.length() > 0; + + if (keepTag && mainDex) { + String8 componentProcess = AaptXml::getAttribute(tree, + "http://schemas.android.com/apk/res/android", "process", &error); + if (error != "") { + fprintf(stderr, "ERROR: %s\n", error.string()); + return -1; + } + + const String8& process = + componentProcess.length() > 0 ? componentProcess : defaultProcess; + keepTag = process.length() > 0 && process.find(":") != 0; + } + + if (keepTag) { addProguardKeepRule(keep, name, pkg.string(), assFile->getPrintableSource(), tree.getLineNumber()); } @@ -3097,30 +3123,12 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp& assets) } status_t -writeProguardFile(Bundle* bundle, const sp& assets) +writeProguardSpec(const char* filename, const ProguardKeepSet& keep, status_t err) { - status_t err = -1; - - if (!bundle->getProguardFile()) { - return NO_ERROR; - } - - ProguardKeepSet keep; - - err = writeProguardForAndroidManifest(&keep, assets); - if (err < 0) { - return err; - } - - err = writeProguardForLayouts(&keep, assets); - if (err < 0) { - return err; - } - - FILE* fp = fopen(bundle->getProguardFile(), "w+"); + FILE* fp = fopen(filename, "w+"); if (fp == NULL) { fprintf(stderr, "ERROR: Unable to open class file %s: %s\n", - bundle->getProguardFile(), strerror(errno)); + filename, strerror(errno)); return UNKNOWN_ERROR; } @@ -3139,6 +3147,49 @@ writeProguardFile(Bundle* bundle, const sp& assets) return err; } +status_t +writeProguardFile(Bundle* bundle, const sp& assets) +{ + status_t err = -1; + + if (!bundle->getProguardFile()) { + return NO_ERROR; + } + + ProguardKeepSet keep; + + err = writeProguardForAndroidManifest(&keep, assets, false); + if (err < 0) { + return err; + } + + err = writeProguardForLayouts(&keep, assets); + if (err < 0) { + return err; + } + + return writeProguardSpec(bundle->getProguardFile(), keep, err); +} + +status_t +writeMainDexProguardFile(Bundle* bundle, const sp& assets) +{ + status_t err = -1; + + if (!bundle->getMainDexProguardFile()) { + return NO_ERROR; + } + + ProguardKeepSet keep; + + err = writeProguardForAndroidManifest(&keep, assets, true); + if (err < 0) { + return err; + } + + return writeProguardSpec(bundle->getMainDexProguardFile(), keep, err); +} + // Loops through the string paths and writes them to the file pointer // Each file path is written on its own line with a terminating backslash. status_t writePathsToFile(const sp& files, FILE* fp)