Skip to content

Commit f43f5c7

Browse files
author
Xavier Ducrohet
committed
Add --output-text-symbols option to aapt. do not merge.
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). Chery-picked from f5de650 Change-Id: I0e08ceb6e4ceb3feb169ce17df21dd35a2505e7f
1 parent edf0ba6 commit f43f5c7

File tree

3 files changed

+205
-14
lines changed

3 files changed

+205
-14
lines changed

tools/aapt/Bundle.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ class Bundle {
6262
mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
6363
mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), mExtraPackages(NULL),
6464
mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false), mProduct(NULL),
65-
mUseCrunchCache(false), mArgc(0), mArgv(NULL)
65+
mUseCrunchCache(false), mOutputTextSymbols(NULL),
66+
mArgc(0), mArgv(NULL)
6667
{}
6768
~Bundle(void) {}
6869

@@ -174,6 +175,8 @@ class Bundle {
174175
void setProduct(const char * val) { mProduct = val; }
175176
void setUseCrunchCache(bool val) { mUseCrunchCache = val; }
176177
bool getUseCrunchCache() const { return mUseCrunchCache; }
178+
const char* getOutputTextSymbols() const { return mOutputTextSymbols; }
179+
void setOutputTextSymbols(const char* val) { mOutputTextSymbols = val; }
177180

178181
/*
179182
* Set and get the file specification.
@@ -280,6 +283,7 @@ class Bundle {
280283
bool mNonConstantId;
281284
const char* mProduct;
282285
bool mUseCrunchCache;
286+
const char* mOutputTextSymbols;
283287

284288
/* file specification */
285289
int mArgc;

tools/aapt/Main.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ void usage(void)
7070
" [--product product1,product2,...] \\\n"
7171
" [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
7272
" [-o] \\\n"
73-
" [raw-files-dir [raw-files-dir] ...]\n"
73+
" [raw-files-dir [raw-files-dir] ...] \\\n"
74+
" [--output-text-symbols DIR]\n"
7475
"\n"
7576
" Package the android resources. It will read assets and resources that are\n"
7677
" supplied with the -M -A -S or raw-files-dir arguments. The -J -P -F and -R\n"
@@ -179,6 +180,9 @@ void usage(void)
179180
" Make the resources ID non constant. This is required to make an R java class\n"
180181
" that does not contain the final value but is used to make reusable compiled\n"
181182
" libraries that need to access resources.\n"
183+
" --output-text-symbols\n"
184+
" Generates a text file containing the resource symbols of the R class in the\n"
185+
" specified folder.\n"
182186
" --ignore-assets\n"
183187
" Assets to be ignored. Default pattern is:\n"
184188
" %s\n",
@@ -547,6 +551,15 @@ int main(int argc, char* const argv[])
547551
bundle.setInstrumentationPackageNameOverride(argv[0]);
548552
} else if (strcmp(cp, "-auto-add-overlay") == 0) {
549553
bundle.setAutoAddOverlay(true);
554+
} else if (strcmp(cp, "-output-text-symbols") == 0) {
555+
argc--;
556+
argv++;
557+
if (!argc) {
558+
fprintf(stderr, "ERROR: No argument supplied for '-output-text-symbols' option\n");
559+
wantUsage = true;
560+
goto bail;
561+
}
562+
bundle.setOutputTextSymbols(argv[0]);
550563
} else if (strcmp(cp, "-product") == 0) {
551564
argc--;
552565
argv++;

tools/aapt/Resource.cpp

Lines changed: 186 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,6 +1821,110 @@ static status_t writeLayoutClasses(
18211821
return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
18221822
}
18231823

1824+
static status_t writeTextLayoutClasses(
1825+
FILE* fp, const sp<AaptAssets>& assets,
1826+
const sp<AaptSymbols>& symbols, bool includePrivate)
1827+
{
1828+
String16 attr16("attr");
1829+
String16 package16(assets->getPackage());
1830+
1831+
bool hasErrors = false;
1832+
1833+
size_t i;
1834+
size_t N = symbols->getNestedSymbols().size();
1835+
for (i=0; i<N; i++) {
1836+
sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i);
1837+
String16 nclassName16(symbols->getNestedSymbols().keyAt(i));
1838+
String8 realClassName(nclassName16);
1839+
if (fixupSymbol(&nclassName16) != NO_ERROR) {
1840+
hasErrors = true;
1841+
}
1842+
String8 nclassName(nclassName16);
1843+
1844+
SortedVector<uint32_t> idents;
1845+
Vector<uint32_t> origOrder;
1846+
Vector<bool> publicFlags;
1847+
1848+
size_t a;
1849+
size_t NA = nsymbols->getSymbols().size();
1850+
for (a=0; a<NA; a++) {
1851+
const AaptSymbolEntry& sym(nsymbols->getSymbols().valueAt(a));
1852+
int32_t code = sym.typeCode == AaptSymbolEntry::TYPE_INT32
1853+
? sym.int32Val : 0;
1854+
bool isPublic = true;
1855+
if (code == 0) {
1856+
String16 name16(sym.name);
1857+
uint32_t typeSpecFlags;
1858+
code = assets->getIncludedResources().identifierForName(
1859+
name16.string(), name16.size(),
1860+
attr16.string(), attr16.size(),
1861+
package16.string(), package16.size(), &typeSpecFlags);
1862+
if (code == 0) {
1863+
fprintf(stderr, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n",
1864+
nclassName.string(), sym.name.string());
1865+
hasErrors = true;
1866+
}
1867+
isPublic = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
1868+
}
1869+
idents.add(code);
1870+
origOrder.add(code);
1871+
publicFlags.add(isPublic);
1872+
}
1873+
1874+
NA = idents.size();
1875+
1876+
fprintf(fp, "int[] styleable %s {", nclassName.string());
1877+
1878+
for (a=0; a<NA; a++) {
1879+
if (a != 0) {
1880+
fprintf(fp, ",");
1881+
}
1882+
fprintf(fp, " 0x%08x", idents[a]);
1883+
}
1884+
1885+
fprintf(fp, " }\n");
1886+
1887+
for (a=0; a<NA; a++) {
1888+
ssize_t pos = idents.indexOf(origOrder.itemAt(a));
1889+
if (pos >= 0) {
1890+
const AaptSymbolEntry& sym = nsymbols->getSymbols().valueAt(a);
1891+
if (!publicFlags.itemAt(a) && !includePrivate) {
1892+
continue;
1893+
}
1894+
String8 name8(sym.name);
1895+
String16 comment(sym.comment);
1896+
String16 typeComment;
1897+
if (comment.size() <= 0) {
1898+
comment = getAttributeComment(assets, name8, &typeComment);
1899+
} else {
1900+
getAttributeComment(assets, name8, &typeComment);
1901+
}
1902+
String16 name(name8);
1903+
if (fixupSymbol(&name) != NO_ERROR) {
1904+
hasErrors = true;
1905+
}
1906+
1907+
uint32_t typeSpecFlags = 0;
1908+
String16 name16(sym.name);
1909+
assets->getIncludedResources().identifierForName(
1910+
name16.string(), name16.size(),
1911+
attr16.string(), attr16.size(),
1912+
package16.string(), package16.size(), &typeSpecFlags);
1913+
//printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
1914+
// String8(attr16).string(), String8(name16).string(), typeSpecFlags);
1915+
const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
1916+
1917+
fprintf(fp,
1918+
"int styleable.%s_%s %d\n",
1919+
nclassName.string(),
1920+
String8(name).string(), (int)pos);
1921+
}
1922+
}
1923+
}
1924+
1925+
return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
1926+
}
1927+
18241928
static status_t writeSymbolClass(
18251929
FILE* fp, const sp<AaptAssets>& assets, bool includePrivate,
18261930
const sp<AaptSymbols>& symbols, const String8& className, int indent,
@@ -1848,7 +1952,6 @@ static status_t writeSymbolClass(
18481952
continue;
18491953
}
18501954
String16 name(sym.name);
1851-
String8 realName(name);
18521955
if (fixupSymbol(&name) != NO_ERROR) {
18531956
return UNKNOWN_ERROR;
18541957
}
@@ -1960,18 +2063,67 @@ static status_t writeSymbolClass(
19602063
return NO_ERROR;
19612064
}
19622065

2066+
static status_t writeTextSymbolClass(
2067+
FILE* fp, const sp<AaptAssets>& assets, bool includePrivate,
2068+
const sp<AaptSymbols>& symbols, const String8& className)
2069+
{
2070+
size_t i;
2071+
status_t err = NO_ERROR;
2072+
2073+
size_t N = symbols->getSymbols().size();
2074+
for (i=0; i<N; i++) {
2075+
const AaptSymbolEntry& sym = symbols->getSymbols().valueAt(i);
2076+
if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) {
2077+
continue;
2078+
}
2079+
2080+
if (!assets->isJavaSymbol(sym, includePrivate)) {
2081+
continue;
2082+
}
2083+
2084+
String16 name(sym.name);
2085+
if (fixupSymbol(&name) != NO_ERROR) {
2086+
return UNKNOWN_ERROR;
2087+
}
2088+
2089+
fprintf(fp, "int %s %s 0x%08x\n",
2090+
className.string(),
2091+
String8(name).string(), (int)sym.int32Val);
2092+
}
2093+
2094+
N = symbols->getNestedSymbols().size();
2095+
for (i=0; i<N; i++) {
2096+
sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i);
2097+
String8 nclassName(symbols->getNestedSymbols().keyAt(i));
2098+
if (nclassName == "styleable") {
2099+
err = writeTextLayoutClasses(fp, assets, nsymbols, includePrivate);
2100+
} else {
2101+
err = writeTextSymbolClass(fp, assets, includePrivate, nsymbols, nclassName);
2102+
}
2103+
if (err != NO_ERROR) {
2104+
return err;
2105+
}
2106+
}
2107+
2108+
return NO_ERROR;
2109+
}
2110+
19632111
status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
19642112
const String8& package, bool includePrivate)
19652113
{
19662114
if (!bundle->getRClassDir()) {
19672115
return NO_ERROR;
19682116
}
19692117

2118+
const char* textSymbolsDest = bundle->getOutputTextSymbols();
2119+
2120+
String8 R("R");
19702121
const size_t N = assets->getSymbols().size();
19712122
for (size_t i=0; i<N; i++) {
19722123
sp<AaptSymbols> symbols = assets->getSymbols().valueAt(i);
19732124
String8 className(assets->getSymbols().keyAt(i));
19742125
String8 dest(bundle->getRClassDir());
2126+
19752127
if (bundle->getMakePackageDirs()) {
19762128
String8 pkg(package);
19772129
const char* last = pkg.string();
@@ -2003,14 +2155,14 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
20032155
}
20042156

20052157
fprintf(fp,
2006-
"/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
2007-
" *\n"
2008-
" * This class was automatically generated by the\n"
2009-
" * aapt tool from the resource data it found. It\n"
2010-
" * should not be modified by hand.\n"
2011-
" */\n"
2012-
"\n"
2013-
"package %s;\n\n", package.string());
2158+
"/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
2159+
" *\n"
2160+
" * This class was automatically generated by the\n"
2161+
" * aapt tool from the resource data it found. It\n"
2162+
" * should not be modified by hand.\n"
2163+
" */\n"
2164+
"\n"
2165+
"package %s;\n\n", package.string());
20142166

20152167
status_t err = writeSymbolClass(fp, assets, includePrivate, symbols,
20162168
className, 0, bundle->getNonConstantId());
@@ -2019,14 +2171,37 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
20192171
}
20202172
fclose(fp);
20212173

2174+
if (textSymbolsDest != NULL && R == className) {
2175+
String8 textDest(textSymbolsDest);
2176+
textDest.appendPath(className);
2177+
textDest.append(".txt");
2178+
2179+
FILE* fp = fopen(textDest.string(), "w+");
2180+
if (fp == NULL) {
2181+
fprintf(stderr, "ERROR: Unable to open text symbol file %s: %s\n",
2182+
textDest.string(), strerror(errno));
2183+
return UNKNOWN_ERROR;
2184+
}
2185+
if (bundle->getVerbose()) {
2186+
printf(" Writing text symbols for class %s.\n", className.string());
2187+
}
2188+
2189+
status_t err = writeTextSymbolClass(fp, assets, includePrivate, symbols,
2190+
className);
2191+
if (err != NO_ERROR) {
2192+
return err;
2193+
}
2194+
fclose(fp);
2195+
}
2196+
20222197
// If we were asked to generate a dependency file, we'll go ahead and add this R.java
20232198
// as a target in the dependency file right next to it.
2024-
if (bundle->getGenDependencies()) {
2199+
if (bundle->getGenDependencies() && R == className) {
20252200
// Add this R.java to the dependency file
20262201
String8 dependencyFile(bundle->getRClassDir());
20272202
dependencyFile.appendPath("R.java.d");
20282203

2029-
fp = fopen(dependencyFile.string(), "a");
2204+
FILE *fp = fopen(dependencyFile.string(), "a");
20302205
fprintf(fp,"%s \\\n", dest.string());
20312206
fclose(fp);
20322207
}
@@ -2036,7 +2211,6 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
20362211
}
20372212

20382213

2039-
20402214
class ProguardKeepSet
20412215
{
20422216
public:

0 commit comments

Comments
 (0)