am 71137e6b: am 1553c82e: Add a flag (-G) to aapt to have it output the classes that shouldn\'t be obfuscated by ProGuard.
Merge commit '71137e6b7ac5d96482f5d038a60aa4ebef01ff3f' * commit '71137e6b7ac5d96482f5d038a60aa4ebef01ff3f': Add a flag (-G) to aapt to have it output the classes that shouldn't be obfuscated by ProGuard.
This commit is contained in:
@@ -1819,6 +1819,19 @@ void AaptAssets::print() const
|
||||
AaptDir::print();
|
||||
}
|
||||
|
||||
sp<AaptDir> AaptAssets::resDir(const String8& name)
|
||||
{
|
||||
const Vector<sp<AaptDir> >& dirs = mDirs;
|
||||
const size_t N = dirs.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
const sp<AaptDir>& d = dirs.itemAt(i);
|
||||
if (d->getLeaf() == name) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
valid_symbol_name(const String8& symbol)
|
||||
{
|
||||
|
||||
@@ -508,6 +508,7 @@ public:
|
||||
void print() const;
|
||||
|
||||
inline const Vector<sp<AaptDir> >& resDirs() { return mDirs; }
|
||||
sp<AaptDir> resDir(const String8& name);
|
||||
|
||||
inline sp<AaptAssets> getOverlay() { return mOverlay; }
|
||||
inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
mRequireLocalization(false), mPseudolocalize(false),
|
||||
mValues(false),
|
||||
mCompressionMethod(0), mOutputAPKFile(NULL),
|
||||
mAssetSourceDir(NULL),
|
||||
mAssetSourceDir(NULL), mProguardFile(NULL),
|
||||
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
|
||||
mRClassDir(NULL), mResourceIntermediatesDir(NULL),
|
||||
mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
|
||||
@@ -88,6 +88,8 @@ public:
|
||||
*/
|
||||
const char* getAssetSourceDir() const { return mAssetSourceDir; }
|
||||
void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; }
|
||||
const char* getProguardFile() const { return mProguardFile; }
|
||||
void setProguardFile(const char* file) { mProguardFile = file; }
|
||||
const android::Vector<const char*>& getResourceSourceDirs() const { return mResourceSourceDirs; }
|
||||
void addResourceSourceDir(const char* dir) { mResourceSourceDirs.insertAt(dir,0); }
|
||||
const char* getAndroidManifestFile() const { return mAndroidManifestFile; }
|
||||
@@ -161,6 +163,7 @@ private:
|
||||
int mCompressionMethod;
|
||||
const char* mOutputAPKFile;
|
||||
const char* mAssetSourceDir;
|
||||
const char* mProguardFile;
|
||||
const char* mAndroidManifestFile;
|
||||
const char* mPublicOutputFile;
|
||||
const char* mRClassDir;
|
||||
|
||||
@@ -233,7 +233,7 @@ static ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static String8 getAttribute(const ResXMLTree& tree, const char* ns,
|
||||
String8 getAttribute(const ResXMLTree& tree, const char* ns,
|
||||
const char* attr, String8* outError)
|
||||
{
|
||||
ssize_t idx = tree.indexOfAttribute(ns, attr);
|
||||
@@ -1158,6 +1158,12 @@ int doPackage(Bundle* bundle)
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the ProGuard file
|
||||
err = writeProguardFile(bundle, assets);
|
||||
if (err < 0) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
// Write the apk
|
||||
if (outputAPKFile) {
|
||||
err = writeAPK(bundle, assets, String8(outputAPKFile));
|
||||
|
||||
@@ -59,9 +59,9 @@ void usage(void)
|
||||
" [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
|
||||
" [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
|
||||
" [--max-sdk-version VAL] [--app-version VAL] \\\n"
|
||||
" [--app-version-name TEXT] \\\n"
|
||||
" [--app-version-name TEXT]\\\n"
|
||||
" [-I base-package [-I base-package ...]] \\\n"
|
||||
" [-A asset-source-dir] [-P public-definitions-file] \\\n"
|
||||
" [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n"
|
||||
" [-S resource-sources [-S resource-sources ...]] "
|
||||
" [-F apk-file] [-J R-file-dir] \\\n"
|
||||
" [raw-files-dir [raw-files-dir] ...]\n"
|
||||
@@ -109,6 +109,7 @@ void usage(void)
|
||||
" -z require localization of resource attributes marked with\n"
|
||||
" localization=\"suggested\"\n"
|
||||
" -A additional directory in which to find raw asset files\n"
|
||||
" -G A file to output proguard options 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"
|
||||
@@ -274,6 +275,17 @@ int main(int argc, char* const argv[])
|
||||
convertPath(argv[0]);
|
||||
bundle.setAssetSourceDir(argv[0]);
|
||||
break;
|
||||
case 'G':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-G' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setProguardFile(argv[0]);
|
||||
break;
|
||||
case 'I':
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
@@ -33,6 +33,8 @@ extern android::status_t buildResources(Bundle* bundle,
|
||||
extern android::status_t writeResourceSymbols(Bundle* bundle,
|
||||
const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate);
|
||||
|
||||
extern android::status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets);
|
||||
|
||||
extern bool isValidResourceType(const String8& type);
|
||||
|
||||
ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
|
||||
@@ -41,4 +43,7 @@ extern status_t filterResources(Bundle* bundle, const sp<AaptAssets>& assets);
|
||||
|
||||
int dumpResources(Bundle* bundle);
|
||||
|
||||
String8 getAttribute(const ResXMLTree& tree, const char* ns,
|
||||
const char* attr, String8* outError);
|
||||
|
||||
#endif // __MAIN_H
|
||||
|
||||
@@ -1630,3 +1630,230 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ProguardKeepSet
|
||||
{
|
||||
public:
|
||||
// { rule --> { file locations } }
|
||||
KeyedVector<String8, SortedVector<String8> > rules;
|
||||
|
||||
void add(const String8& rule, const String8& where);
|
||||
};
|
||||
|
||||
void ProguardKeepSet::add(const String8& rule, const String8& where)
|
||||
{
|
||||
ssize_t index = rules.indexOfKey(rule);
|
||||
if (index < 0) {
|
||||
index = rules.add(rule, SortedVector<String8>());
|
||||
}
|
||||
rules.editValueAt(index).add(where);
|
||||
}
|
||||
|
||||
status_t
|
||||
writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
|
||||
{
|
||||
status_t err;
|
||||
ResXMLTree tree;
|
||||
size_t len;
|
||||
ResXMLTree::event_code_t code;
|
||||
int depth = 0;
|
||||
bool inApplication = false;
|
||||
String8 error;
|
||||
sp<AaptGroup> assGroup;
|
||||
sp<AaptFile> assFile;
|
||||
String8 pkg;
|
||||
|
||||
// First, look for a package file to parse. This is required to
|
||||
// be able to generate the resource information.
|
||||
assGroup = assets->getFiles().valueFor(String8("AndroidManifest.xml"));
|
||||
if (assGroup == NULL) {
|
||||
fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (assGroup->getFiles().size() != 1) {
|
||||
fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
|
||||
assGroup->getFiles().valueAt(0)->getPrintableSource().string());
|
||||
}
|
||||
|
||||
assFile = assGroup->getFiles().valueAt(0);
|
||||
|
||||
err = parseXMLResource(assFile, &tree);
|
||||
if (err != NO_ERROR) {
|
||||
return err;
|
||||
}
|
||||
|
||||
tree.restart();
|
||||
|
||||
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
|
||||
if (code == ResXMLTree::END_TAG) {
|
||||
if (/* name == "Application" && */ depth == 2) {
|
||||
inApplication = false;
|
||||
}
|
||||
depth--;
|
||||
continue;
|
||||
}
|
||||
if (code != ResXMLTree::START_TAG) {
|
||||
continue;
|
||||
}
|
||||
depth++;
|
||||
String8 tag(tree.getElementName(&len));
|
||||
// printf("Depth %d tag %s\n", depth, tag.string());
|
||||
if (depth == 1) {
|
||||
if (tag != "manifest") {
|
||||
fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
|
||||
return -1;
|
||||
}
|
||||
pkg = getAttribute(tree, NULL, "package", NULL);
|
||||
} else if (depth == 2 && tag == "application") {
|
||||
inApplication = true;
|
||||
}
|
||||
if (depth == 3 && inApplication) {
|
||||
if (tag == "application" || tag == "activity" || tag == "service" || tag == "receiver"
|
||||
|| tag == "provider") {
|
||||
String8 name = getAttribute(tree, "http://schemas.android.com/apk/res/android",
|
||||
"name", &error);
|
||||
if (error != "") {
|
||||
fprintf(stderr, "ERROR: %s\n", error.string());
|
||||
return -1;
|
||||
}
|
||||
// asdf --> package.asdf
|
||||
// .asdf .a.b --> package.asdf package.a.b
|
||||
// asdf.adsf --> asdf.asdf
|
||||
String8 rule("-keep class ");
|
||||
const char* p = name.string();
|
||||
const char* q = strchr(p, '.');
|
||||
if (p == q) {
|
||||
rule += pkg;
|
||||
rule += name;
|
||||
} else if (q == NULL) {
|
||||
rule += pkg;
|
||||
rule += ".";
|
||||
rule += name;
|
||||
} else {
|
||||
rule += name;
|
||||
}
|
||||
|
||||
String8 location = tag;
|
||||
location += " ";
|
||||
location += assFile->getSourceFile();
|
||||
char lineno[20];
|
||||
sprintf(lineno, ":%d", tree.getLineNumber());
|
||||
location += lineno;
|
||||
|
||||
keep->add(rule, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t
|
||||
writeProguardForLayout(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile)
|
||||
{
|
||||
status_t err;
|
||||
ResXMLTree tree;
|
||||
size_t len;
|
||||
ResXMLTree::event_code_t code;
|
||||
|
||||
err = parseXMLResource(layoutFile, &tree);
|
||||
if (err != NO_ERROR) {
|
||||
return err;
|
||||
}
|
||||
|
||||
tree.restart();
|
||||
|
||||
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
|
||||
if (code != ResXMLTree::START_TAG) {
|
||||
continue;
|
||||
}
|
||||
String8 tag(tree.getElementName(&len));
|
||||
|
||||
// If there is no '.', we'll assume that it's one of the built in names.
|
||||
if (strchr(tag.string(), '.')) {
|
||||
String8 rule("-keep class ");
|
||||
rule += tag;
|
||||
rule += " { <init>(...); }";
|
||||
|
||||
String8 location("view ");
|
||||
location += layoutFile->getSourceFile();
|
||||
char lineno[20];
|
||||
sprintf(lineno, ":%d", tree.getLineNumber());
|
||||
location += lineno;
|
||||
|
||||
keep->add(rule, location);
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t
|
||||
writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
|
||||
{
|
||||
status_t err;
|
||||
sp<AaptDir> layout = assets->resDir(String8("layout"));
|
||||
|
||||
if (layout != NULL) {
|
||||
const KeyedVector<String8,sp<AaptGroup> > groups = layout->getFiles();
|
||||
const size_t N = groups.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
const sp<AaptGroup>& group = groups.valueAt(i);
|
||||
const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
|
||||
const size_t M = files.size();
|
||||
for (size_t j=0; j<M; j++) {
|
||||
err = writeProguardForLayout(keep, files.valueAt(j));
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t
|
||||
writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets)
|
||||
{
|
||||
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+");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "ERROR: Unable to open class file %s: %s\n",
|
||||
bundle->getProguardFile(), strerror(errno));
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
const KeyedVector<String8, SortedVector<String8> >& rules = keep.rules;
|
||||
const size_t N = rules.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
const SortedVector<String8>& locations = rules.valueAt(i);
|
||||
const size_t M = locations.size();
|
||||
for (size_t j=0; j<M; j++) {
|
||||
fprintf(fp, "# %s\n", locations.itemAt(j).string());
|
||||
}
|
||||
fprintf(fp, "%s\n\n", rules.keyAt(i).string());
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user