raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.3k stars 808 forks source link

Android sun.reflect.ReflectionFactory no found #1720

Closed anonyein closed 1 month ago

anonyein commented 1 month ago

@Super(strategy = Super.Instantiation.UNSAFE, proxyType = TargetType.class) could not fit Android and how to get super object. Starting with Android 26 (Oreo, 8.0), Google began to gradually remove access to the internal sun class for reflection because it could cause security and compatibility issues.

raphw commented 1 month ago

That is why this approach is discouraged. Rather use the method as a basis and inject a method handle, for example. What are you trying to achieve? Do you need to invoke any method?

anonyein commented 1 month ago

That is why this approach is discouraged. Rather use the method as a basis and inject a method handle, for example. What are you trying to achieve? Do you need to invoke any method?

@raphw yes, need to invoke any method https://github.com/caoccao/JavetBuddy/blob/main/src/main/java/com/caoccao/javet/buddy/interop/proxy/BaseDynamicObjectHandler.java#L101 https://github.com/caoccao/JavetBuddy/blob/main/src/main/java/com/caoccao/javet/buddy/interop/proxy/DynamicObjectExtendHandler.java#L87

I want to make "intercept" method fit for Android

raphw commented 1 month ago

In this case you might be able to use Super.Instantiation.CONSTRUCTOR? As long as the constructor does not do any method calls on the supplied objects, or any other input checks, this will work.

anonyein commented 1 month ago

In this case you might be able to use Super.Instantiation.CONSTRUCTOR? As long as the constructor does not do any method calls on the supplied objects, or any other input checks, this will work.

  W  java.lang.IllegalStateException: size = 0
2024-10-21 18:28:17.548  9157-19242 System.err                                   W      at net.bytebuddy.matcher.FilterableList$AbstractBase.getOnly(FilterableList.java:139)
2024-10-21 18:28:17.550  9157-19242 System.err                                   W      at net.bytebuddy.implementation.auxiliary.TypeProxy$ForSuperMethodByConstructor.apply(TypeProxy.java:458)
2024-10-21 18:28:17.551  9157-19242 System.err                                   W      at net.bytebuddy.implementation.bind.MethodDelegationBinder$ParameterBinding$Anonymous.apply(MethodDelegationBinder.java:258)
2024-10-21 18:28:17.551  9157-19242 System.err                                   W      at net.bytebuddy.implementation.bytecode.StackManipulation$Compound.apply(StackManipulation.java:243)
2024-10-21 18:28:17.552  9157-19242 System.err                                   W      at net.bytebuddy.implementation.bind.MethodDelegationBinder$MethodBinding$Builder$Build.apply(MethodDelegationBinder.java:564)
2024-10-21 18:28:17.552  9157-19242 System.err                                   W      at net.bytebuddy.implementation.bytecode.StackManipulation$Compound.apply(StackManipulation.java:243)
2024-10-21 18:28:17.553  9157-19242 System.err                                   W      at net.bytebuddy.implementation.MethodDelegation$Appender.apply(MethodDelegation.java:1350)
2024-10-21 18:28:17.553  9157-19242 System.err                                   W      at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:732)
2024-10-21 18:28:17.554  9157-19242 System.err                                   W      at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:717)
2024-10-21 18:28:17.554  9157-19242 System.err                                   W      at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:624)
2024-10-21 18:28:17.555  9157-19242 System.err                                   W      at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:6077)
2024-10-21 18:28:17.555  9157-19242 System.err                                   W      at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:2246)
2024-10-21 18:28:17.555  9157-19242 System.err                                   W      at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$UsingTypeWriter.make(DynamicType.java:4057)
2024-10-21 18:28:17.556  9157-19242 System.err                                   W      at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3741)
2024-10-21 18:28:17.556  9157-19242 System.err                                   W      at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3993)
2024-10-21 18:28:17.557  9157-19242 System.err                                   W      at com.caoccao.javet.buddy.interop.proxy.BaseDynamicObjectAndroidHandler.getObjectClass(BaseDynamicObjectAndroidHandler.java:138)
2024-10-21 18:28:17.557  9157-19242 System.err                                   W      at com.caoccao.javet.buddy.interop.proxy.JavetReflectionObjectAndroidFactory.extend(JavetReflectionObjectAndroidFactory.java:103)
    protected static final AndroidClassLoadingStrategy ANDROID_CLASS_LOADING_STRATEGY;

    static {
        File file = new File(JavetOSUtils.TEMP_DIRECTORY, RandomString.make());
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
        ANDROID_CLASS_LOADING_STRATEGY = new AndroidClassLoadingStrategy.Wrapping(file);
    }
    protected Class<T> getObjectClass() {
        DynamicType.Builder<T> builder = new ByteBuddy().subclass(type, CONSTRUCTOR_STRATEGY);
        if (!AutoCloseable.class.isAssignableFrom(type)) {
            builder = builder.implement(AutoCloseable.class);
        }
        try (DynamicType.Unloaded<T> unloadedType = builder
                .method(ElementMatchers.isPublic())
                .intercept(MethodDelegation.to(this))
                .make()) {
            return (Class<T>) unloadedType.load(getClass().getClassLoader(), ANDROID_CLASS_LOADING_STRATEGY).getLoaded();
        }
    }
raphw commented 1 month ago

You need to set the constructorParameters property on the @Super annotation for this. This property is needed to identify the constructor that you want to call. It needs to resemble the constructor parameter types of the relevant constructor.

anonyein commented 1 month ago

You need to set the constructorParameters property on the @Super annotation for this. This property is needed to identify the constructor that you want to call. It needs to resemble the constructor parameter types of the relevant constructor.

annotation cannot be variable, constructorParameters cannot be set. Are there other way to get super object?

raphw commented 1 month ago

That is right, but the proxy type cannot be variable either. What type do you use before @Super?

anonyein commented 1 month ago

That is right, but the proxy type cannot be variable either. What type do you use before @Super?

https://github.com/caoccao/JavetBuddy/blob/main/src/main/java/com/caoccao/javet/buddy/interop/proxy/DynamicObjectExtendHandler.java#L72 proxyType = TargetType.class

raphw commented 1 month ago

I see. I will have to add a dynamic resolver for this. That is not much work, so I can add it to the next version.

anonyein commented 1 month ago

I see. I will have to add a dynamic resolver for this. That is not much work, so I can add it to the next version.

Thank you for your contribution and effort!

raphw commented 1 month ago

You can now specifiy a constructorResolver property on the annotation to resolve the annotation dynamically.

anonyein commented 1 month ago
java.lang.IllegalStateException: Cannot invoke Android dex file translation method
at net.bytebuddy.android.AndroidClassLoadingStrategy$DexProcessor$ForSdkCompiler$Dispatcher$ForApi26LevelCompatibleVm.translate(AndroidClassLoadingStrategy.java:647)
at net.bytebuddy.android.AndroidClassLoadingStrategy$DexProcessor$ForSdkCompiler$Conversion.register(AndroidClassLoadingStrategy.java:458)
at net.bytebuddy.android.AndroidClassLoadingStrategy.load(AndroidClassLoadingStrategy.java:164)
at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:101)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6367)
    protected static final File Temp_Dir = getCurrentContext().getDir("libs", Context.MODE_PRIVATE);
    protected static final AndroidClassLoadingStrategy ANDROID_CLASS_LOADING_STRATEGY = Temp_Dir.exists() && Temp_Dir.isDirectory() ?
            new AndroidClassLoadingStrategy.Wrapping(Temp_Dir) :
            Temp_Dir.mkdirs() ? new AndroidClassLoadingStrategy.Wrapping(Temp_Dir) : null;
        DynamicType.Builder<T> builder = new ByteBuddy().subclass(type, CONSTRUCTOR_STRATEGY);
        if (!AutoCloseable.class.isAssignableFrom(type)) {
            builder = builder.implement(AutoCloseable.class);
        }
        try (DynamicType.Unloaded<T> unloadedType = builder
                .method(ElementMatchers.isPublic())
                .intercept(MethodDelegation.to(this))
                .make()) {
            return (Class<T>) unloadedType.load(getClass().getClassLoader(), ANDROID_CLASS_LOADING_STRATEGY).getLoaded();
        }

The jar seems cannot be writen into "app_libs/" and only create "app_libs/oat/2QpqXOOB.jar.cur.prof" of 0KB on Android 11

Logcat:

2024-10-23 20:43:33.951  1378-2463  installd                installd                             D  Processing secondary dex path /data/user/0/com.xxxx.xxxx/app_libs/2QpqXOOB.jar
2024-10-23 20:43:33.952  1378-2463  installd                installd                             D  Processed secondary dex file /data/user/0/com.xxxx.xxxx/app_libs/2QpqXOOB.jar result=205
2024-10-23 20:43:33.953  5273-5405  OPDOM                   system_server                        D  performDexOpt secondaryDex end for /data/user/0/com.xxxx.xxxx/app_libs/2QpqXOOB.jar sucessed: true

https://github.com/raphw/byte-buddy/issues/1722