Skip to content

Commit f5de650

Browse files
author
Xavier Ducrohet
committed
Add --output-text-symbols option to aapt.
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
1 parent 7714a24 commit f5de650

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
@@ -61,7 +61,8 @@ class Bundle {
6161
mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
6262
mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), mExtraPackages(NULL),
6363
mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false), mProduct(NULL),
64-
mUseCrunchCache(false), mErrorOnFailedInsert(false), mArgc(0), mArgv(NULL)
64+
mUseCrunchCache(false), mErrorOnFailedInsert(false), mOutputTextSymbols(NULL),
65+
mArgc(0), mArgv(NULL)
6566
{}
6667
~Bundle(void) {}
6768

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

177180
/*
178181
* Set and get the file specification.
@@ -279,6 +282,7 @@ class Bundle {
279282
const char* mProduct;
280283
bool mUseCrunchCache;
281284
bool mErrorOnFailedInsert;
285+
const char* mOutputTextSymbols;
282286

283287
/* file specification */
284288
int mArgc;

tools/aapt/Main.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ void usage(void)
6969
" [-F apk-file] [-J R-file-dir] \\\n"
7070
" [--product product1,product2,...] \\\n"
7171
" [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
72-
" [raw-files-dir [raw-files-dir] ...]\n"
72+
" [raw-files-dir [raw-files-dir] ...] \\\n"
73+
" [--output-text-symbols DIR]\n"
7374
"\n"
7475
" Package the android resources. It will read assets and resources that are\n"
7576
" 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)
182183
" with --debug-mode, --min-sdk-version, --target-sdk-version --version-code\n"
183184
" and --version-name.\n"
184185
" Insertion typically fails if the manifest already defines the attribute.\n"
186+
" --output-text-symbols\n"
187+
" Generates a text file containing the resource symbols of the R class in the\n"
188+
" specified folder.\n"
185189
" --ignore-assets\n"
186190
" Assets to be ignored. Default pattern is:\n"
187191
" %s\n",
@@ -549,6 +553,15 @@ int main(int argc, char* const argv[])
549553
bundle.setAutoAddOverlay(true);
550554
} else if (strcmp(cp, "-error-on-failed-insert") == 0) {
551555
bundle.setErrorOnFailedInsert(true);
556+
} else if (strcmp(cp, "-output-text-symbols") == 0) {
557+
argc--;
558+
argv++;
559+
if (!argc) {
560+
fprintf(stderr, "ERROR: No argument supplied for '-output-text-symbols' option\n");
561+
wantUsage = true;
562+
goto bail;
563+
}
564+
bundle.setOutputTextSymbols(argv[0]);
552565
} else if (strcmp(cp, "-product") == 0) {
553566
argc--;
554567
argv++;

tools/aapt/Resource.cpp

Lines changed: 186 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,6 +1852,110 @@ static status_t writeLayoutClasses(
18521852
return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
18531853
}
18541854

1855+
static status_t writeTextLayoutClasses(
1856+
FILE* fp, const sp<AaptAssets>& assets,
1857+
const sp<AaptSymbols>& symbols, bool includePrivate)
1858+
{
1859+
String16 attr16("attr");
1860+
String16 package16(assets->getPackage());
1861+
1862+
bool hasErrors = false;
1863+
1864+
size_t i;
1865+
size_t N = symbols->getNestedSymbols().size();
1866+
for (i=0; i<N; i++) {
1867+
sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i);
1868+
String16 nclassName16(symbols->getNestedSymbols().keyAt(i));
1869+
String8 realClassName(nclassName16);
1870+
if (fixupSymbol(&nclassName16) != NO_ERROR) {
1871+
hasErrors = true;
1872+
}
1873+
String8 nclassName(nclassName16);
1874+
1875+
SortedVector<uint32_t> idents;
1876+
Vector<uint32_t> origOrder;
1877+
Vector<bool> publicFlags;
1878+
1879+
size_t a;
1880+
size_t NA = nsymbols->getSymbols().size();
1881+
for (a=0; a<NA; a++) {
1882+
const AaptSymbolEntry& sym(nsymbols->getSymbols().valueAt(a));
1883+
int32_t code = sym.typeCode == AaptSymbolEntry::TYPE_INT32
1884+
? sym.int32Val : 0;
1885+
bool isPublic = true;
1886+
if (code == 0) {
1887+
String16 name16(sym.name);
1888+
uint32_t typeSpecFlags;
1889+
code = assets->getIncludedResources().identifierForName(
1890+
name16.string(), name16.size(),
1891+
attr16.string(), attr16.size(),
1892+
package16.string(), package16.size(), &typeSpecFlags);
1893+
if (code == 0) {
1894+
fprintf(stderr, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n",
1895+
nclassName.string(), sym.name.string());
1896+
hasErrors = true;
1897+
}
1898+
isPublic = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
1899+
}
1900+
idents.add(code);
1901+
origOrder.add(code);
1902+
publicFlags.add(isPublic);
1903+
}
1904+
1905+
NA = idents.size();
1906+
1907+
fprintf(fp, "int[] styleable %s {", nclassName.string());
1908+
1909+
for (a=0; a<NA; a++) {
1910+
if (a != 0) {
1911+
fprintf(fp, ",");
1912+
}
1913+
fprintf(fp, " 0x%08x", idents[a]);
1914+
}
1915+
1916+
fprintf(fp, " }\n");
1917+
1918+
for (a=0; a<NA; a++) {
1919+
ssize_t pos = idents.indexOf(origOrder.itemAt(a));
1920+
if (pos >= 0) {
1921+
const AaptSymbolEntry& sym = nsymbols->getSymbols().valueAt(a);
1922+
if (!publicFlags.itemAt(a) && !includePrivate) {
1923+
continue;
1924+
}
1925+
String8 name8(sym.name);
1926+
String16 comment(sym.comment);
1927+
String16 typeComment;
1928+
if (comment.size() <= 0) {
1929+
comment = getAttributeComment(assets, name8, &typeComment);
1930+
} else {
1931+
getAttributeComment(assets, name8, &typeComment);
1932+
}
1933+
String16 name(name8);
1934+
if (fixupSymbol(&name) != NO_ERROR) {
1935+
hasErrors = true;
1936+
}
1937+
1938+
uint32_t typeSpecFlags = 0;
1939+
String16 name16(sym.name);
1940+
assets->getIncludedResources().identifierForName(
1941+
name16.string(), name16.size(),
1942+
attr16.string(), attr16.size(),
1943+
package16.string(), package16.size(), &typeSpecFlags);
1944+
//printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
1945+
// String8(attr16).string(), String8(name16).string(), typeSpecFlags);
1946+
const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
1947+
1948+
fprintf(fp,
1949+
"int styleable.%s_%s %d\n",
1950+
nclassName.string(),
1951+
String8(name).string(), (int)pos);
1952+
}
1953+
}
1954+
}
1955+
1956+
return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
1957+
}
1958+
18551959
static status_t writeSymbolClass(
18561960
FILE* fp, const sp<AaptAssets>& assets, bool includePrivate,
18571961
const sp<AaptSymbols>& symbols, const String8& className, int indent,
@@ -1879,7 +1983,6 @@ static status_t writeSymbolClass(
18791983
continue;
18801984
}
18811985
String16 name(sym.name);
1882-
String8 realName(name);
18831986
if (fixupSymbol(&name) != NO_ERROR) {
18841987
return UNKNOWN_ERROR;
18851988
}
@@ -1991,18 +2094,67 @@ static status_t writeSymbolClass(
19912094
return NO_ERROR;
19922095
}
19932096

2097+
static status_t writeTextSymbolClass(
2098+
FILE* fp, const sp<AaptAssets>& assets, bool includePrivate,
2099+
const sp<AaptSymbols>& symbols, const String8& className)
2100+
{
2101+
size_t i;
2102+
status_t err = NO_ERROR;
2103+
2104+
size_t N = symbols->getSymbols().size();
2105+
for (i=0; i<N; i++) {
2106+
const AaptSymbolEntry& sym = symbols->getSymbols().valueAt(i);
2107+
if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) {
2108+
continue;
2109+
}
2110+
2111+
if (!assets->isJavaSymbol(sym, includePrivate)) {
2112+
continue;
2113+
}
2114+
2115+
String16 name(sym.name);
2116+
if (fixupSymbol(&name) != NO_ERROR) {
2117+
return UNKNOWN_ERROR;
2118+
}
2119+
2120+
fprintf(fp, "int %s %s 0x%08x\n",
2121+
className.string(),
2122+
String8(name).string(), (int)sym.int32Val);
2123+
}
2124+
2125+
N = symbols->getNestedSymbols().size();
2126+
for (i=0; i<N; i++) {
2127+
sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i);
2128+
String8 nclassName(symbols->getNestedSymbols().keyAt(i));
2129+
if (nclassName == "styleable") {
2130+
err = writeTextLayoutClasses(fp, assets, nsymbols, includePrivate);
2131+
} else {
2132+
err = writeTextSymbolClass(fp, assets, includePrivate, nsymbols, nclassName);
2133+
}
2134+
if (err != NO_ERROR) {
2135+
return err;
2136+
}
2137+
}
2138+
2139+
return NO_ERROR;
2140+
}
2141+
19942142
status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
19952143
const String8& package, bool includePrivate)
19962144
{
19972145
if (!bundle->getRClassDir()) {
19982146
return NO_ERROR;
19992147
}
20002148

2149+
const char* textSymbolsDest = bundle->getOutputTextSymbols();
2150+
2151+
String8 R("R");
20012152
const size_t N = assets->getSymbols().size();
20022153
for (size_t i=0; i<N; i++) {
20032154
sp<AaptSymbols> symbols = assets->getSymbols().valueAt(i);
20042155
String8 className(assets->getSymbols().keyAt(i));
20052156
String8 dest(bundle->getRClassDir());
2157+
20062158
if (bundle->getMakePackageDirs()) {
20072159
String8 pkg(package);
20082160
const char* last = pkg.string();
@@ -2034,14 +2186,14 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
20342186
}
20352187

20362188
fprintf(fp,
2037-
"/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
2038-
" *\n"
2039-
" * This class was automatically generated by the\n"
2040-
" * aapt tool from the resource data it found. It\n"
2041-
" * should not be modified by hand.\n"
2042-
" */\n"
2043-
"\n"
2044-
"package %s;\n\n", package.string());
2189+
"/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
2190+
" *\n"
2191+
" * This class was automatically generated by the\n"
2192+
" * aapt tool from the resource data it found. It\n"
2193+
" * should not be modified by hand.\n"
2194+
" */\n"
2195+
"\n"
2196+
"package %s;\n\n", package.string());
20452197

20462198
status_t err = writeSymbolClass(fp, assets, includePrivate, symbols,
20472199
className, 0, bundle->getNonConstantId());
@@ -2050,14 +2202,37 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
20502202
}
20512203
fclose(fp);
20522204

2205+
if (textSymbolsDest != NULL && R == className) {
2206+
String8 textDest(textSymbolsDest);
2207+
textDest.appendPath(className);
2208+
textDest.append(".txt");
2209+
2210+
FILE* fp = fopen(textDest.string(), "w+");
2211+
if (fp == NULL) {
2212+
fprintf(stderr, "ERROR: Unable to open text symbol file %s: %s\n",
2213+
textDest.string(), strerror(errno));
2214+
return UNKNOWN_ERROR;
2215+
}
2216+
if (bundle->getVerbose()) {
2217+
printf(" Writing text symbols for class %s.\n", className.string());
2218+
}
2219+
2220+
status_t err = writeTextSymbolClass(fp, assets, includePrivate, symbols,
2221+
className);
2222+
if (err != NO_ERROR) {
2223+
return err;
2224+
}
2225+
fclose(fp);
2226+
}
2227+
20532228
// If we were asked to generate a dependency file, we'll go ahead and add this R.java
20542229
// as a target in the dependency file right next to it.
2055-
if (bundle->getGenDependencies()) {
2230+
if (bundle->getGenDependencies() && R == className) {
20562231
// Add this R.java to the dependency file
20572232
String8 dependencyFile(bundle->getRClassDir());
20582233
dependencyFile.appendPath("R.java.d");
20592234

2060-
fp = fopen(dependencyFile.string(), "a");
2235+
FILE *fp = fopen(dependencyFile.string(), "a");
20612236
fprintf(fp,"%s \\\n", dest.string());
20622237
fclose(fp);
20632238
}
@@ -2067,7 +2242,6 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
20672242
}
20682243

20692244

2070-
20712245
class ProguardKeepSet
20722246
{
20732247
public:

0 commit comments

Comments
 (0)