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:
Joe Onorato
2009-08-30 17:00:44 -07:00
committed by Android Git Automerger
7 changed files with 271 additions and 4 deletions

View File

@@ -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)
{

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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));

View File

@@ -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++;

View File

@@ -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

View File

@@ -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;
}