Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3aa60760 authored by Adam Lesinski's avatar Adam Lesinski Committed by Android (Google) Code Review
Browse files

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

parents 5c1b42e4 1e466385
Loading
Loading
Loading
Loading
+20 −74
Original line number Diff line number Diff line
@@ -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);
                            }
            callback = rClazz.getMethod("onResourcesLoaded", int.class);
        } catch (NoSuchMethodException e) {
            // No rewriting to be done.
            return;
        }

                    } else {
                        for (Field field : clazz.getDeclaredFields()) {
                            rewriteIntField(field, id);
                        }
                    }
                } catch (Exception e) {
                    throw new IllegalArgumentException("Failed to rewrite R values for " +
                            clazz.getName(), e);
                }
        Throwable cause;
        try {
            callback.invoke(null, id);
            return;
        } catch (IllegalAccessException e) {
            cause = e;
        } catch (InvocationTargetException e) {
            cause = e.getCause();
        }

        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to rewrite R values", e);
        }
        throw new RuntimeException("Failed to rewrite resource references for " + packageName,
                cause);
    }

    public void removeContextRegistrations(Context context,
+7 −5
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
#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
+2 −1
Original line number Diff line number Diff line
@@ -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);

+122 −12
Original line number Diff line number Diff line
@@ -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;