Merge "Have R classes generate their own reference rewrite logic" into lmp-dev

This commit is contained in:
Adam Lesinski
2014-08-26 18:23:56 +00:00
committed by Android (Google) Code Review
5 changed files with 215 additions and 93 deletions

View File

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

View File

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

View 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

View File

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

View File

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