From 1e466385d4a4f1acee080fa0fdf16cc8fd8ce7ca Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Fri, 15 Aug 2014 14:47:28 -0700 Subject: [PATCH] Have R classes generate their own reference rewrite logic Change-Id: I0e5b8311fc3479d966a49f9acf0d4c32a6a024d3 --- core/java/android/app/LoadedApk.java | 94 ++++++------------------ tools/aapt/Command.cpp | 12 ++-- tools/aapt/IndentPrinter.h | 63 ++++++++++++++++ tools/aapt/Main.h | 3 +- tools/aapt/Resource.cpp | 134 +++++++++++++++++++++++++++++++---- 5 files changed, 214 insertions(+), 92 deletions(-) create mode 100644 tools/aapt/IndentPrinter.h diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index e0c7816b78d9..d143b8634531 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -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); - } - } + callback = rClazz.getMethod("onResourcesLoaded", int.class); + } catch (NoSuchMethodException e) { + // No rewriting to be done. + return; + } - } catch (Exception e) { - throw new IllegalArgumentException("Failed to rewrite R values", e); + 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, diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index b3946715c9c0..a0f0a08bf95c 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -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; } diff --git a/tools/aapt/IndentPrinter.h b/tools/aapt/IndentPrinter.h new file mode 100644 index 000000000000..6fc94bc927b8 --- /dev/null +++ b/tools/aapt/IndentPrinter.h @@ -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 + diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h index 34c449687c56..dd40b2011dc8 100644 --- a/tools/aapt/Main.h +++ b/tools/aapt/Main.h @@ -49,7 +49,8 @@ extern android::status_t buildResources(Bundle* bundle, const sp& assets, sp& builder); extern android::status_t writeResourceSymbols(Bundle* bundle, - const sp& assets, const String8& pkgName, bool includePrivate); + const sp& assets, const String8& pkgName, + bool includePrivate, bool emitCallback); extern android::status_t writeProguardFile(Bundle* bundle, const sp& assets); diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 1d93b895409a..7979a1ddf7ae 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -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& 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& assets, const sp& symbols, int indent, bool includePrivate, bool nonConstantId) @@ -2138,7 +2243,7 @@ static status_t writeTextLayoutClasses( static status_t writeSymbolClass( FILE* fp, const sp& assets, bool includePrivate, const sp& 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& 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& 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; -- 2.11.0