diff options
author | 2024-05-02 08:43:05 -0700 | |
---|---|---|
committer | 2024-05-02 09:02:43 -0700 | |
commit | e4a54a8ea7453434ec5c98998cd1d33cc3a9dee0 (patch) | |
tree | deac88cb9b24e13804262e16031b7d5d1d9b320d | |
parent | 56be0b624a493f3e6127ffc4eebb9b110c187595 (diff) |
[Ravenwood] Start using HWUI native methods
Enable Matrix, Path and Interpolator for starters
Bug: 337110712
Bug: 337329128
Test: ./ravenwood/scripts/run-ravenwood-tests.sh
Test: atest CtsGraphicsTestCasesRavenwood
Test: atest CtsGraphicsTestCases
Change-Id: Iefa17f91837c5382067bf17fc148b158133a4de5
9 files changed, 140 insertions, 43 deletions
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 319f115d7427..6d31578ac020 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -465,6 +465,11 @@ public final class Bitmap implements Parcelable { * how pixels are stored. This affects the quality (color depth) as * well as the ability to display transparent/translucent colors. */ + // It's touched by Graphics.cpp, so we need to make this enum usable on Ravenwood. + // Otherwise, all the ctors would throw, which would make the class unloadable + // because the static initializer needs the enum members because of `sConfigs`. + // TODO: Remove it once we expose the outer class. + @android.ravenwood.annotation.RavenwoodKeepWholeClass public enum Config { // these native values must match up with the enum in SkBitmap.h diff --git a/graphics/java/android/graphics/Interpolator.java b/graphics/java/android/graphics/Interpolator.java index 104546454fa9..994fb2dc31bc 100644 --- a/graphics/java/android/graphics/Interpolator.java +++ b/graphics/java/android/graphics/Interpolator.java @@ -18,6 +18,9 @@ package android.graphics; import android.os.SystemClock; +@android.ravenwood.annotation.RavenwoodKeepWholeClass +@android.ravenwood.annotation.RavenwoodClassLoadHook( + android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) public class Interpolator { public Interpolator(int valueCount) { diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java index bc58febc388b..fbb690c0b012 100644 --- a/graphics/java/android/graphics/Matrix.java +++ b/graphics/java/android/graphics/Matrix.java @@ -28,6 +28,9 @@ import java.io.PrintWriter; /** * The Matrix class holds a 3x3 matrix for transforming coordinates. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass +@android.ravenwood.annotation.RavenwoodClassLoadHook( + android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) public class Matrix { public static final int MSCALE_X = 0; //!< use with getValues/setValues @@ -229,7 +232,7 @@ public class Matrix { private static class NoImagePreloadHolder { public static final NativeAllocationRegistry sRegistry = NativeAllocationRegistry.createMalloced( - Matrix.class.getClassLoader(), nGetNativeFinalizer()); + Matrix.class.getClassLoader(), nGetNativeFinalizerWrapper()); } private final long native_instance; @@ -238,7 +241,7 @@ public class Matrix { * Create an identity matrix */ public Matrix() { - native_instance = nCreate(0); + native_instance = nCreateWrapper(0); NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance); } @@ -248,7 +251,7 @@ public class Matrix { * @param src The matrix to copy into this matrix */ public Matrix(Matrix src) { - native_instance = nCreate(src != null ? src.native_instance : 0); + native_instance = nCreateWrapper(src != null ? src.native_instance : 0); NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance); } @@ -846,6 +849,34 @@ public class Matrix { return native_instance; } + /** + * Wrapper method we use to switch to ExtraNatives.nCreate(src) only on Ravenwood. + * + * @see ExtraNatives + */ + @android.ravenwood.annotation.RavenwoodReplace + private static long nCreateWrapper(long src) { + return nCreate(src); + } + + private static long nCreateWrapper$ravenwood(long src) { + return ExtraNatives.nCreate(src); + } + + /** + * Wrapper method we use to switch to ExtraNatives.nGetNativeFinalizer(src) only on Ravenwood. + * + * @see ExtraNatives + */ + @android.ravenwood.annotation.RavenwoodReplace + private static long nGetNativeFinalizerWrapper() { + return nGetNativeFinalizer(); + } + + private static long nGetNativeFinalizerWrapper$ravenwood() { + return ExtraNatives.nGetNativeFinalizer(); + } + // ------------------ Regular JNI ------------------------ private static native long nCreate(long nSrc_or_zero); @@ -943,4 +974,25 @@ public class Matrix { private static native float nMapRadius(long nObject, float radius); @CriticalNative private static native boolean nEquals(long nA, long nB); + + /** + * Due to b/337329128, native methods that are called by the static initializers cannot be + * in the same class when running on a host side JVM (such as on Ravenwood and Android Studio). + * + * There are two methods that are called by the static initializers (either directly or + * indirectly) in this class, namely nCreate() and nGetNativeFinalizer(). On Ravenwood + * these methods can't be on the Matrix class itself, so we use a nested class to host them. + * + * We still keep the original nCreate() method and call it on non-ravenwood environment, + * in order to avoid problems in downstream (such as Android Studio). + * + * @see #nCreateWrapper(long) + * @see #nGetNativeFinalizerWrapper() + * + * TODO(b/337110712) Clean it up somehow. (remove the original nCreate() and unify the code?) + */ + private static class ExtraNatives { + static native long nCreate(long nSrc_or_zero); + static native long nGetNativeFinalizer(); + } } diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java index deb89faf3419..073307c7a2e8 100644 --- a/graphics/java/android/graphics/Path.java +++ b/graphics/java/android/graphics/Path.java @@ -36,11 +36,16 @@ import libcore.util.NativeAllocationRegistry; * (based on the paint's Style), or it can be used for clipping or to draw * text on a path. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass +@android.ravenwood.annotation.RavenwoodClassLoadHook( + android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) public class Path { - - private static final NativeAllocationRegistry sRegistry = - NativeAllocationRegistry.createMalloced( - Path.class.getClassLoader(), nGetFinalizer()); + // See b/337329128 for why we need an inner class here. + private static class NoImagePreloadHolder { + static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + Path.class.getClassLoader(), nGetFinalizer()); + } /** * @hide @@ -52,7 +57,7 @@ public class Path { */ public Path() { mNativePath = nInit(); - sRegistry.registerNativeAllocation(this, mNativePath); + NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePath); } /** @@ -62,7 +67,7 @@ public class Path { */ public Path(@Nullable Path src) { mNativePath = nInit(src != null ? src.mNativePath : 0); - sRegistry.registerNativeAllocation(this, mNativePath); + NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePath); } /** diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp index 8315c4c0dd4d..07e97f85d588 100644 --- a/libs/hwui/jni/Graphics.cpp +++ b/libs/hwui/jni/Graphics.cpp @@ -211,11 +211,7 @@ static jclass gRegion_class; static jfieldID gRegion_nativeInstanceID; static jmethodID gRegion_constructorMethodID; -static jclass gByte_class; -static jobject gVMRuntime; -static jclass gVMRuntime_class; -static jmethodID gVMRuntime_newNonMovableArray; -static jmethodID gVMRuntime_addressOf; +static jclass gByte_class; static jclass gColorSpace_class; static jmethodID gColorSpace_getMethodID; @@ -789,13 +785,6 @@ int register_android_graphics_Graphics(JNIEnv* env) gByte_class = (jclass) env->NewGlobalRef( env->GetStaticObjectField(c, env->GetStaticFieldID(c, "TYPE", "Ljava/lang/Class;"))); - gVMRuntime_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "dalvik/system/VMRuntime")); - m = env->GetStaticMethodID(gVMRuntime_class, "getRuntime", "()Ldalvik/system/VMRuntime;"); - gVMRuntime = env->NewGlobalRef(env->CallStaticObjectMethod(gVMRuntime_class, m)); - gVMRuntime_newNonMovableArray = GetMethodIDOrDie(env, gVMRuntime_class, "newNonMovableArray", - "(Ljava/lang/Class;I)Ljava/lang/Object;"); - gVMRuntime_addressOf = GetMethodIDOrDie(env, gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J"); - gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace")); gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;"); diff --git a/libs/hwui/jni/android_graphics_Matrix.cpp b/libs/hwui/jni/android_graphics_Matrix.cpp index ca667b0d09bc..c0d791a88908 100644 --- a/libs/hwui/jni/android_graphics_Matrix.cpp +++ b/libs/hwui/jni/android_graphics_Matrix.cpp @@ -376,11 +376,24 @@ static const JNINativeMethod methods[] = { {"nEquals", "(JJ)Z", (void*) SkMatrixGlue::equals} }; +static const JNINativeMethod extra_methods[] = { + {"nGetNativeFinalizer", "()J", (void*)SkMatrixGlue::getNativeFinalizer}, + {"nCreate", "(J)J", (void*)SkMatrixGlue::create}, +}; + static jclass sClazz; static jfieldID sNativeInstanceField; static jmethodID sCtor; int register_android_graphics_Matrix(JNIEnv* env) { + // Methods only used on Ravenwood (for now). See the javadoc on Matrix$ExtraNativesx + // for why we need it. + // + // We don't need it on non-ravenwood, but we don't (yet) have a way to detect ravenwood + // environment, so we just always run it. + RegisterMethodsOrDie(env, "android/graphics/Matrix$ExtraNatives", extra_methods, + NELEM(extra_methods)); + int result = RegisterMethodsOrDie(env, "android/graphics/Matrix", methods, NELEM(methods)); jclass clazz = FindClassOrDie(env, "android/graphics/Matrix"); diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodClassLoadHook.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodClassLoadHook.java index 7dc197e6bdfd..7a3142b041d1 100644 --- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodClassLoadHook.java +++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodClassLoadHook.java @@ -28,8 +28,10 @@ import java.lang.annotation.Target; * Add this with a fully-specified method name (e.g. {@code "com.package.Class.methodName"}) * of a callback to get a callback at the class load time. * - * The method must be {@code public static} with a single argument that takes - * {@link Class}. + * The method must be {@code public static} with a single argument that takes {@link Class}. + * + * Typically, this is used with {@link #LIBANDROID_LOADING_HOOK}, which will load the necessary + * native libraries. * * @hide */ @@ -37,4 +39,10 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.CLASS) public @interface RavenwoodClassLoadHook { String value(); + + /** + * Class load hook that loads <code>libandroid_runtime</code>. + */ + public static String LIBANDROID_LOADING_HOOK + = "com.android.platform.test.ravenwood.runtimehelper.ClassLoadHook.onClassLoaded"; } diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java index 9057d163957e..96b7057d25ec 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java @@ -44,6 +44,14 @@ public class ClassLoadHook { public static final String LIBANDROID_RUNTIME_NAME = "android_runtime"; + /** + * Extra strings needed to pass to register_android_graphics_classes(). + * + * `android.graphics.Graphics` is not actually a class, so we can't use the same initialization + * strategy than the "normal" classes. So we just hardcode it here. + */ + public static final String GRAPHICS_EXTRA_INIT_PARAMS = ",android.graphics.Graphics"; + private static String sInitialDir = new File("").getAbsolutePath(); static { @@ -98,7 +106,6 @@ public class ClassLoadHook { private static void loadFrameworkNativeCode() { // This is called from class-initializers, so no synchronization is needed. if (sLoadFrameworkNativeCodeCalled) { - // This method has already been called before.s return; } sLoadFrameworkNativeCodeCalled = true; @@ -112,7 +119,8 @@ public class ClassLoadHook { } if (SKIP_LOADING_LIBANDROID) { - log("Skip loading " + LIBANDROID_RUNTIME_NAME); + log("Skip loading native runtime."); + return; } // Make sure these properties are not set. @@ -121,27 +129,39 @@ public class ClassLoadHook { ensurePropertyNotSet(KEYBOARD_PATHS); ensurePropertyNotSet(GRAPHICS_NATIVE_CLASSES); - // Tell libandroid what JNI to use. - final var jniClasses = getCoreNativeClassesToUse(); - if (jniClasses.isEmpty()) { - log("No classes require JNI methods, skip loading " + LIBANDROID_RUNTIME_NAME); + // Load the libraries, if needed. + final var libanrdoidClasses = getClassesWithNativeMethods(sLibandroidClasses); + final var libhwuiClasses = getClassesWithNativeMethods(sLibhwuiClasses); + if (libanrdoidClasses.isEmpty() && libhwuiClasses.isEmpty()) { + log("No classes require JNI methods, skip loading native runtime."); return; } - setProperty(CORE_NATIVE_CLASSES, jniClasses); - setProperty(GRAPHICS_NATIVE_CLASSES, ""); + setProperty(CORE_NATIVE_CLASSES, libanrdoidClasses); + setProperty(GRAPHICS_NATIVE_CLASSES, libhwuiClasses + GRAPHICS_EXTRA_INIT_PARAMS); + log("Loading " + LIBANDROID_RUNTIME_NAME + " for '" + libanrdoidClasses + "' and '" + + libhwuiClasses + "'"); RavenwoodUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME); } /** - * Classes with native methods that are backed by `libandroid_runtime`. + * Classes with native methods that are backed by libandroid_runtime. * - * At runtime, we check if these classes have any methods, and if so, we'll have - * `libandroid_runtime` register the native functions. + * See frameworks/base/core/jni/platform/host/HostRuntime.cpp */ - private static final Class<?>[] sClassesWithLibandroidNativeMethods = { + private static final Class<?>[] sLibandroidClasses = { android.util.Log.class, - android.os.Parcel.class, + }; + + /** + * Classes with native methods that are backed by libhwui. + * + * See frameworks/base/libs/hwui/apex/LayoutlibLoader.cpp + */ + private static final Class<?>[] sLibhwuiClasses = { + android.graphics.Interpolator.class, + android.graphics.Matrix.class, + android.graphics.Path.class, }; /** @@ -157,17 +177,15 @@ public class ClassLoadHook { } /** - * Create a list of classes as comma-separated that require JNI methods to be set up. - * - * <p>This list is used by frameworks/base/core/jni/LayoutlibLoader.cpp to decide - * what JNI methods to set up. + * Create a list of classes as comma-separated that require JNI methods to be set up from + * a given class list, ignoring classes with no native methods. */ - private static String getCoreNativeClassesToUse() { + private static String getClassesWithNativeMethods(Class<?>[] classes) { final var coreNativeClassesToLoad = new ArrayList<String>(); - for (var clazz : sClassesWithLibandroidNativeMethods) { + for (var clazz : classes) { if (hasNativeMethod(clazz)) { - log("Class %s has native methods", clazz); + log("Class %s has native methods", clazz.getCanonicalName()); coreNativeClassesToLoad.add(clazz.getName()); } } diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt index 243e22457c8e..e452299373f8 100644 --- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt +++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt @@ -236,7 +236,11 @@ android.text.TextUtils$SimpleStringSplitter android.accounts.Account +android.graphics.Bitmap$Config android.graphics.Insets +android.graphics.Interpolator +android.graphics.Matrix +android.graphics.Path android.graphics.Point android.graphics.PointF android.graphics.Rect |