英文:
ByteBuddy - unable to intercept static method from superclass
问题
我正在为 Android 开发命令行工具(类似于 am),尝试利用 ByteBuddy 的功能来桩化 android.security.KeyStore 中定义的静态方法 getApplicationContext。
然而,当我在子类化 android.security.KeyStore 并使用 ByteBuddy 的 getDeclaredMethods 时,该方法似乎对 ByteBuddy 不可见,因此无法进行拦截。
当我使用反射 API 中的 getMethods 时,我能够列出该方法。
Class AndroidKeyStore = Class.forName("android.security.KeyStore");
Method[] keyStoreMethods = new ByteBuddy()
.with(TypeValidation.DISABLED)
.subclass(AndroidKeyStore, ConstructorStrategy.Default.IMITATE_SUPER_CLASS)
.name("KeyStoreMasker")
.method(ElementMatchers.named("getApplicationContext"))
.intercept(SuperMethodCall.INSTANCE)
.make()
.load(getClass().getClassLoader(),
new AndroidClassLoadingStrategy
.Injecting(new File("/data/app/cmdutil")))
.getLoaded()
.getDeclaredMethods();
for(i = 0; i < keyStoreMethods.length; i++) {
System.out.println("method = " + keyStoreMethods[i].toString());
}
当运行上述代码时,我预期在子类中应该有一个方法 - getApplicationContext。然而,子类中却没有任何方法。
如果将对 getDeclaredMethods 的调用替换为 getMethods,我能够列出超类的所有公共方法。
将拦截的方法替换为非静态方法(例如 "state"),我能够使用 ByteBuddy 的 getDeclaredMethods 函数列出该方法:
>在 keyStoreMethods 中声明的方法数量:2
>
>method = public android.security.KeyStore$State AndroidKeyStoreMasker.state()
>
>method = public android.security.KeyStore$State AndroidKeyStoreMasker.state(int)
因此,我的最终结论是 ByteBuddy(或我使用 ByteBuddy 的情况)在处理静态方法可见性方面存在一些问题。
android.security.KeyStore.java 的参考链接:
<https://android.googlesource.com/platform/frameworks/base/+/master/keystore/java/android/security/KeyStore.java>
非常感谢任何提供帮助的支持。
英文:
I'm working on command line tool for Android (think of am), trying to utilize the power of ByteBuddy to stub the static method getApplicationContext defined in android.security.KeyStore
However - the method seem to be invisible to ByteBuddy getDeclaredMethods when subclassing the android.security.KeyStore and hence it is unable to intercept it.
When using getMethods from the reflection API i'm able to list the method.
Class AndroidKeyStore = Class.forName("android.security.KeyStore");
Method[] keyStoreMethods = new ByteBuddy()
.with(TypeValidation.DISABLED)
.subclass(AndroidKeyStore, ConstructorStrategy.Default.IMITATE_SUPER_CLASS)
.name("KeyStoreMasker")
.method(ElementMatchers.named("getApplicationContext"))
.intercept(SuperMethodCall.INSTANCE)
.make()
.load(getClass().getClassLoader(),
new AndroidClassLoadingStrategy
.Injecting(new File("/data/app/cmdutil")))
.getLoaded()
.getDeclaredMethods();
for(i = 0; i < keyStoreMethods .length; i++) {
System.out.println("method = " + keyStoreMethods[i].toString());
}
When running the above, I was expecting to have a single method - getApplicationContext in the subclass. However the subclass doesn't contain any methods.
Replacing the call to getDeclaredMethods by getMethods I'm able to list all public method of the superclass.
By replacing the intercepted method to a non-static one (for example "state"), i'm able to list the method using ByteBuddy's getDeclaredMethods function:
>Number of declared methods in keyStoreMethods: 2
>
>method = public android.security.KeyStore$State AndroidKeyStoreMasker.state()
>
>method = public android.security.KeyStore$State AndroidKeyStoreMasker.state(int)
So my final conclusion is that ByteBuddy (or my usage case with ByteBuddy) has some issue with static method visibility.
Reference to android.security.KeyStore.java:
<https://android.googlesource.com/platform/frameworks/base/+/master/keystore/java/android/security/KeyStore.java>
Any help would be much appreaciated.
答案1
得分: 2
创建subclass
时,Byte Buddy只能拦截由子类直接声明的方法或超类的虚方法。这是JVM的工作原理,static
方法会直接在接收器上分派。
Byte Buddy还能够重新定义和重新转换现有类,但这需要一个Java代理,在Android上不可用。因此,恐怕您需要找到一个非静态的挂钩点来实现您的目标。或者,您可以查看MemberSubstitution
,您可以从您的代码中重定向这些调用。这也需要重新转换,但由于它发生在您的代码中,您可以使用Byte Buddy的构建插件。
英文:
When creating a subclass
, Byte Buddy is only able to intercept methods directly declared by a subclass or virtual methods of super classes. This is how the JVM works, static
methods are dispatched directly on the receiver.
Byte Buddy is capable of redefining and retransforming existing classes, too, but this requires a Java agent which is not available on Android. Therefore, I am afraid that you need to find a non-static hook point to accomplish what you are trying. Alternatively, have a look at the MemberSubstitution
where you can redirect such calls from your code. This also requires a retransformation but since it happens in your code, you can use Byte Buddy's build plugin.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论