Merge "Have R classes generate their own reference rewrite logic" into lmp-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
3aa6076083
@@ -51,8 +51,8 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -594,55 +594,6 @@ public final class LoadedApk {
|
||||
return app;
|
||||
}
|
||||
|
||||
private void rewriteIntField(Field field, int packageId) throws IllegalAccessException {
|
||||
int requiredModifiers = Modifier.STATIC | Modifier.PUBLIC;
|
||||
int bannedModifiers = Modifier.FINAL;
|
||||
|
||||
int mod = field.getModifiers();
|
||||
if ((mod & requiredModifiers) != requiredModifiers ||
|
||||
(mod & bannedModifiers) != 0) {
|
||||
throw new IllegalArgumentException("Field " + field.getName() +
|
||||
" is not rewritable");
|
||||
}
|
||||
|
||||
if (field.getType() != int.class && field.getType() != Integer.class) {
|
||||
throw new IllegalArgumentException("Field " + field.getName() +
|
||||
" is not an integer");
|
||||
}
|
||||
|
||||
try {
|
||||
int resId = field.getInt(null);
|
||||
field.setInt(null, (resId & 0x00ffffff) | (packageId << 24));
|
||||
} catch (IllegalAccessException e) {
|
||||
// This should not occur (we check above if we can write to it)
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void rewriteIntArrayField(Field field, int packageId) {
|
||||
int requiredModifiers = Modifier.STATIC | Modifier.PUBLIC;
|
||||
|
||||
if ((field.getModifiers() & requiredModifiers) != requiredModifiers) {
|
||||
throw new IllegalArgumentException("Field " + field.getName() +
|
||||
" is not rewritable");
|
||||
}
|
||||
|
||||
if (field.getType() != int[].class) {
|
||||
throw new IllegalArgumentException("Field " + field.getName() +
|
||||
" is not an integer array");
|
||||
}
|
||||
|
||||
try {
|
||||
int[] array = (int[]) field.get(null);
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = (array[i] & 0x00ffffff) | (packageId << 24);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
// This should not occur (we check above if we can write to it)
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void rewriteRValues(ClassLoader cl, String packageName, int id) {
|
||||
final Class<?> rClazz;
|
||||
try {
|
||||
@@ -650,35 +601,30 @@ public final class LoadedApk {
|
||||
} catch (ClassNotFoundException e) {
|
||||
// This is not necessarily an error, as some packages do not ship with resources
|
||||
// (or they do not need rewriting).
|
||||
Log.i(TAG, "Could not find R class for package '" + packageName + "'");
|
||||
Log.i(TAG, "No resource references to update in package " + packageName);
|
||||
return;
|
||||
}
|
||||
|
||||
final Method callback;
|
||||
try {
|
||||
Class<?>[] declaredClasses = rClazz.getDeclaredClasses();
|
||||
for (Class<?> clazz : declaredClasses) {
|
||||
try {
|
||||
if (clazz.getSimpleName().equals("styleable")) {
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getType() == int[].class) {
|
||||
rewriteIntArrayField(field, id);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
rewriteIntField(field, id);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Failed to rewrite R values for " +
|
||||
clazz.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Failed to rewrite R values", e);
|
||||
callback = rClazz.getMethod("onResourcesLoaded", int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// No rewriting to be done.
|
||||
return;
|
||||
}
|
||||
|
||||
Throwable cause;
|
||||
try {
|
||||
callback.invoke(null, id);
|
||||
return;
|
||||
} catch (IllegalAccessException e) {
|
||||
cause = e;
|
||||
} catch (InvocationTargetException e) {
|
||||
cause = e.getCause();
|
||||
}
|
||||
|
||||
throw new RuntimeException("Failed to rewrite resource references for " + packageName,
|
||||
cause);
|
||||
}
|
||||
|
||||
public void removeContextRegistrations(Context context,
|
||||
|
||||
@@ -2488,10 +2488,12 @@ int doPackage(Bundle* bundle)
|
||||
if (bundle->getCustomPackage() == NULL) {
|
||||
// Write the R.java file into the appropriate class directory
|
||||
// e.g. gen/com/foo/app/R.java
|
||||
err = writeResourceSymbols(bundle, assets, assets->getPackage(), true);
|
||||
err = writeResourceSymbols(bundle, assets, assets->getPackage(), true,
|
||||
bundle->getBuildSharedLibrary());
|
||||
} else {
|
||||
const String8 customPkg(bundle->getCustomPackage());
|
||||
err = writeResourceSymbols(bundle, assets, customPkg, true);
|
||||
err = writeResourceSymbols(bundle, assets, customPkg, true,
|
||||
bundle->getBuildSharedLibrary());
|
||||
}
|
||||
if (err < 0) {
|
||||
goto bail;
|
||||
@@ -2505,7 +2507,7 @@ int doPackage(Bundle* bundle)
|
||||
char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
|
||||
while (packageString != NULL) {
|
||||
// Write the R.java file out with the correct package name
|
||||
err = writeResourceSymbols(bundle, assets, String8(packageString), true);
|
||||
err = writeResourceSymbols(bundle, assets, String8(packageString), true, false);
|
||||
if (err < 0) {
|
||||
goto bail;
|
||||
}
|
||||
@@ -2514,11 +2516,11 @@ int doPackage(Bundle* bundle)
|
||||
libs.unlockBuffer();
|
||||
}
|
||||
} else {
|
||||
err = writeResourceSymbols(bundle, assets, assets->getPackage(), false);
|
||||
err = writeResourceSymbols(bundle, assets, assets->getPackage(), false, false);
|
||||
if (err < 0) {
|
||||
goto bail;
|
||||
}
|
||||
err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true);
|
||||
err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true, false);
|
||||
if (err < 0) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
63
tools/aapt/IndentPrinter.h
Normal file
63
tools/aapt/IndentPrinter.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef __INDENT_PRINTER_H
|
||||
#define __INDENT_PRINTER_H
|
||||
|
||||
class IndentPrinter {
|
||||
public:
|
||||
IndentPrinter(FILE* stream, int indentSize=2)
|
||||
: mStream(stream)
|
||||
, mIndentSize(indentSize)
|
||||
, mIndent(0)
|
||||
, mNeedsIndent(true) {
|
||||
}
|
||||
|
||||
void indent(int amount = 1) {
|
||||
mIndent += amount;
|
||||
if (mIndent < 0) {
|
||||
mIndent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void print(const char* fmt, ...) {
|
||||
doIndent();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(mStream, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void println(const char* fmt, ...) {
|
||||
doIndent();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(mStream, fmt, args);
|
||||
va_end(args);
|
||||
fputs("\n", mStream);
|
||||
mNeedsIndent = true;
|
||||
}
|
||||
|
||||
void println() {
|
||||
doIndent();
|
||||
fputs("\n", mStream);
|
||||
mNeedsIndent = true;
|
||||
}
|
||||
|
||||
private:
|
||||
void doIndent() {
|
||||
if (mNeedsIndent) {
|
||||
int numSpaces = mIndent * mIndentSize;
|
||||
while (numSpaces > 0) {
|
||||
fputs(" ", mStream);
|
||||
numSpaces--;
|
||||
}
|
||||
mNeedsIndent = false;
|
||||
}
|
||||
}
|
||||
|
||||
FILE* mStream;
|
||||
const int mIndentSize;
|
||||
int mIndent;
|
||||
bool mNeedsIndent;
|
||||
};
|
||||
|
||||
#endif // __INDENT_PRINTER_H
|
||||
|
||||
@@ -49,7 +49,8 @@ extern android::status_t buildResources(Bundle* bundle,
|
||||
const sp<AaptAssets>& assets, sp<ApkBuilder>& builder);
|
||||
|
||||
extern android::status_t writeResourceSymbols(Bundle* bundle,
|
||||
const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate);
|
||||
const sp<AaptAssets>& assets, const String8& pkgName,
|
||||
bool includePrivate, bool emitCallback);
|
||||
|
||||
extern android::status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets);
|
||||
|
||||
|
||||
@@ -3,18 +3,17 @@
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
#include "Main.h"
|
||||
#include "AaptAssets.h"
|
||||
#include "StringPool.h"
|
||||
#include "XMLNode.h"
|
||||
#include "ResourceTable.h"
|
||||
#include "Images.h"
|
||||
|
||||
#include "CacheUpdater.h"
|
||||
#include "CrunchCache.h"
|
||||
#include "FileFinder.h"
|
||||
#include "CacheUpdater.h"
|
||||
|
||||
#include "Images.h"
|
||||
#include "IndentPrinter.h"
|
||||
#include "Main.h"
|
||||
#include "ResourceTable.h"
|
||||
#include "StringPool.h"
|
||||
#include "WorkQueue.h"
|
||||
#include "XMLNode.h"
|
||||
|
||||
#if HAVE_PRINTF_ZD
|
||||
# define ZD "%zd"
|
||||
@@ -1801,6 +1800,112 @@ static String16 getAttributeComment(const sp<AaptAssets>& assets,
|
||||
return String16();
|
||||
}
|
||||
|
||||
static void writeResourceLoadedCallback(FILE* fp, int indent) {
|
||||
IndentPrinter p(fp, 4);
|
||||
p.indent(indent);
|
||||
p.println("private static void rewriteIntArrayField(java.lang.reflect.Field field, int packageId) throws IllegalAccessException {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("int requiredModifiers = java.lang.reflect.Modifier.STATIC | java.lang.reflect.Modifier.PUBLIC;");
|
||||
p.println("if ((field.getModifiers() & requiredModifiers) != requiredModifiers) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("throw new IllegalArgumentException(\"Field \" + field.getName() + \" is not rewritable\");");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.println("if (field.getType() != int[].class) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("throw new IllegalArgumentException(\"Field \" + field.getName() + \" is not an int array\");");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.println("int[] array = (int[]) field.get(null);");
|
||||
p.println("for (int i = 0; i < array.length; i++) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("array[i] = (array[i] & 0x00ffffff) | (packageId << 24);");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.println();
|
||||
p.println("private static void rewriteIntField(java.lang.reflect.Field field, int packageId) throws IllegalAccessException {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("int requiredModifiers = java.lang.reflect.Modifier.STATIC | java.lang.reflect.Modifier.PUBLIC;");
|
||||
p.println("int bannedModifiers = java.lang.reflect.Modifier.FINAL;");
|
||||
p.println("int mod = field.getModifiers();");
|
||||
p.println("if ((mod & requiredModifiers) != requiredModifiers || (mod & bannedModifiers) != 0) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("throw new IllegalArgumentException(\"Field \" + field.getName() + \" is not rewritable\");");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.println("if (field.getType() != int.class && field.getType() != Integer.class) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("throw new IllegalArgumentException(\"Field \" + field.getName() + \" is not an int\");");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.println("int resId = field.getInt(null);");
|
||||
p.println("field.setInt(null, (resId & 0x00ffffff) | (packageId << 24));");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.println();
|
||||
p.println("public static void onResourcesLoaded(int assignedPackageId) throws Exception {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("Class<?>[] declaredClasses = R.class.getDeclaredClasses();");
|
||||
p.println("for (Class<?> clazz : declaredClasses) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("if (clazz.getSimpleName().equals(\"styleable\")) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("if (field.getType() == int[].class) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("rewriteIntArrayField(field, assignedPackageId);");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("} else {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {");
|
||||
{
|
||||
p.indent();
|
||||
p.println("rewriteIntField(field, assignedPackageId);");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.indent(-1);
|
||||
}
|
||||
p.println("}");
|
||||
p.println();
|
||||
}
|
||||
|
||||
static status_t writeLayoutClasses(
|
||||
FILE* fp, const sp<AaptAssets>& assets,
|
||||
const sp<AaptSymbols>& symbols, int indent, bool includePrivate, bool nonConstantId)
|
||||
@@ -2138,7 +2243,7 @@ static status_t writeTextLayoutClasses(
|
||||
static status_t writeSymbolClass(
|
||||
FILE* fp, const sp<AaptAssets>& assets, bool includePrivate,
|
||||
const sp<AaptSymbols>& symbols, const String8& className, int indent,
|
||||
bool nonConstantId)
|
||||
bool nonConstantId, bool emitCallback)
|
||||
{
|
||||
fprintf(fp, "%spublic %sfinal class %s {\n",
|
||||
getIndentSpace(indent),
|
||||
@@ -2238,7 +2343,8 @@ static status_t writeSymbolClass(
|
||||
if (nclassName == "styleable") {
|
||||
styleableSymbols = nsymbols;
|
||||
} else {
|
||||
err = writeSymbolClass(fp, assets, includePrivate, nsymbols, nclassName, indent, nonConstantId);
|
||||
err = writeSymbolClass(fp, assets, includePrivate, nsymbols, nclassName,
|
||||
indent, nonConstantId, false);
|
||||
}
|
||||
if (err != NO_ERROR) {
|
||||
return err;
|
||||
@@ -2252,6 +2358,10 @@ static status_t writeSymbolClass(
|
||||
}
|
||||
}
|
||||
|
||||
if (emitCallback) {
|
||||
writeResourceLoadedCallback(fp, indent);
|
||||
}
|
||||
|
||||
indent--;
|
||||
fprintf(fp, "%s}\n", getIndentSpace(indent));
|
||||
return NO_ERROR;
|
||||
@@ -2299,7 +2409,7 @@ static status_t writeTextSymbolClass(
|
||||
}
|
||||
|
||||
status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
|
||||
const String8& package, bool includePrivate)
|
||||
const String8& package, bool includePrivate, bool emitCallback)
|
||||
{
|
||||
if (!bundle->getRClassDir()) {
|
||||
return NO_ERROR;
|
||||
@@ -2355,7 +2465,7 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
|
||||
"package %s;\n\n", package.string());
|
||||
|
||||
status_t err = writeSymbolClass(fp, assets, includePrivate, symbols,
|
||||
className, 0, bundle->getNonConstantId());
|
||||
className, 0, bundle->getNonConstantId(), emitCallback);
|
||||
fclose(fp);
|
||||
if (err != NO_ERROR) {
|
||||
return err;
|
||||
|
||||
Reference in New Issue
Block a user