[英]Java.lang.NoSuchFieldError: no "I" field "value" in class "Ljava/lang/Integer;" or its superclasses Android 10
I have received a .so android library from a client and I have to integrate that in my Xamarin Forms project.我从客户端收到了一个 .so android 库,我必须将它集成到我的 Xamarin Forms 项目中。 The library helps the app connect to an IoT device.
该库可帮助应用程序连接到 IoT 设备。 As the library methods are of the following signature, I decided to write a java wrapper to simplify the parameters and create an aar file.
由于库方法具有以下签名,我决定编写一个 java 包装器来简化参数并创建一个 aar 文件。 Afterwards, I natively bind the aar and use it as a dll in my project.
之后,我本地绑定了 aar 并将其用作我的项目中的 dll。
It is important to note that the problem in Xamarin only occurs when the Compile Target is > 10. Otherwise, it works fine.需要注意的是,Xamarin 中的问题仅在 Compile Target > 10 时出现。否则,它工作正常。 My guess is that the latest Updates to non-SDK interfaces broke the application .
我的猜测是非 SDK 接口的最新更新破坏了应用程序。
Library header:库头:
public static native int ReadParams(String token, StringBuilder serial, StringBuilder ssid, StringBuilder password, StringBuilder sensor, Integer keepAlive);
The problem: The method works fine when called from within a native android application however crashes with the following error from Xamarin Forms.问题:该方法在从本机 android 应用程序中调用时工作正常,但因 Xamarin Forms 的以下错误而崩溃。 The crash is on the following line in the Java wrapper.
崩溃发生在 Java 包装器的下一行。
Crash line:崩溃线:
StringBuilder strSerial = new StringBuilder();
StringBuilder strssid = new StringBuilder();
StringBuilder strpassword = new StringBuilder();
StringBuilder strsensor = new StringBuilder();
Integer keepAlive = new Integer(0);
//Crash on below line
int response = EPM002Lib.ReadParams(token, strSerial, strssid, strpassword, strsensor, keepAlive);
The stacktrace:堆栈跟踪:
--- End of managed Java.Lang.IncompatibleClassChangeError stack trace --- java.lang.NoSuchFieldError: no "I" field "value" in class "Ljava/lang/Integer;"
--- 托管 Java.Lang.IncompatibleClassChangeError 堆栈跟踪结束 --- java.lang.NoSuchFieldError:在类“Ljava/lang/Integer;”中没有“I”字段“value”; or its superclasses at com.esong.lib.EPM002Lib.ReadParams(Native Method) at com.sensorwa.config.configdemo.SquareSdkhelper.ReadParams(SquareSdkhelper.java:32)
或其超类 com.esong.lib.EPM002Lib.ReadParams(Native Method) at com.sensorwa.config.configdemo.SquareSdkhelper.ReadParams(SquareSdkhelper.java:32)
I understand that more information regarding the internal functionality of the EPM002Lib.ReadParams params would help, however, the library seems to work with a native android application (even when compiled against Android 10).我知道有关 EPM002Lib.ReadParams 参数的内部功能的更多信息会有所帮助,但是,该库似乎适用于本机 Android 应用程序(即使针对 Android 10 进行编译)。 Please feel free to ask for more information or provide suggestions.
请随时询问更多信息或提供建议。 Thanks for the help 😄
谢谢帮忙😄
You're relying on an implementation detail that was not supposed to be relied on.您正在依赖不应该依赖的实现细节。
Now it broke and you get to keep both pieces.现在它坏了,你可以保留这两部分。
I compiled this file using the Android Aarch64 compiler:我使用 Android Aarch64 编译器编译了这个文件:
#include <jni.h>
int access_field(JNIEnv *env, jobject obj) {
jclass cls_Integer = (*env)->FindClass(env, "Ljava/lang/Integer;");
jfieldID fid_Integer_value = (*env)->GetFieldID(env, cls_Integer, "value", "I");
return (*env)->GetIntField(env, obj, fid_Integer_value);
}
int access_method(JNIEnv *env, jobject obj) {
jclass cls_Integer = (*env)->FindClass(env, "Ljava/lang/Integer;");
jmethodID mid_Integer_value = (*env)->GetMethodID(env, cls_Integer, "intValue", "()I");
return (*env)->CallIntMethod(env, obj, mid_Integer_value);
}
which results in the following code for access_field
:这导致
access_field
的以下代码:
int access_field(JNIEnv *env, jobject obj) {
0: d10103ff sub sp, sp, #0x40
4: a9037bfd stp x29, x30, [sp,#48]
8: 9100c3fd add x29, sp, #0x30
c: 90000008 adrp x8, 0 <access_field>
10: 91000108 add x8, x8, #0x0
14: 90000002 adrp x2, 0 <access_field>
18: 91000042 add x2, x2, #0x0
1c: 90000003 adrp x3, 0 <access_field>
20: 91000063 add x3, x3, #0x0
24: f81f83a0 stur x0, [x29,#-8]
28: f81f03a1 stur x1, [x29,#-16]
jclass cls_Integer = (*env)->FindClass(env, "Ljava/lang/Integer;");
2c: f85f83a9 ldur x9, [x29,#-8]
30: f9400129 ldr x9, [x9]
34: f9401929 ldr x9, [x9,#48]
38: f85f83a0 ldur x0, [x29,#-8]
3c: aa0803e1 mov x1, x8
40: f90007e2 str x2, [sp,#8]
44: f90003e3 str x3, [sp]
48: d63f0120 blr x9
4c: f9000fe0 str x0, [sp,#24]
jfieldID fid_Integer_value = (*env)->GetFieldID(env, cls_Integer, "value", "I");
50: f85f83a8 ldur x8, [x29,#-8]
54: f9400108 ldr x8, [x8]
58: f9417908 ldr x8, [x8,#752]
5c: f85f83a0 ldur x0, [x29,#-8]
60: f9400fe1 ldr x1, [sp,#24]
64: f94007e2 ldr x2, [sp,#8]
68: f94003e3 ldr x3, [sp]
6c: d63f0100 blr x8
70: f9000be0 str x0, [sp,#16]
return (*env)->GetIntField(env, obj, fid_Integer_value);
74: f85f83a8 ldur x8, [x29,#-8]
78: f9400108 ldr x8, [x8]
7c: f9419108 ldr x8, [x8,#800]
80: f85f83a0 ldur x0, [x29,#-8]
84: f85f03a1 ldur x1, [x29,#-16]
88: f9400be2 ldr x2, [sp,#16]
8c: d63f0100 blr x8
90: a9437bfd ldp x29, x30, [sp,#48]
94: 910103ff add sp, sp, #0x40
98: d65f03c0 ret
}
and for access_method
:和
access_method
:
int access_method(JNIEnv *env, jobject obj) {
9c: d10103ff sub sp, sp, #0x40
a0: a9037bfd stp x29, x30, [sp,#48]
a4: 9100c3fd add x29, sp, #0x30
a8: 90000008 adrp x8, 0 <access_field>
ac: 91000108 add x8, x8, #0x0
b0: 90000002 adrp x2, 0 <access_field>
b4: 91000042 add x2, x2, #0x0
b8: 90000003 adrp x3, 0 <access_field>
bc: 91000063 add x3, x3, #0x0
c0: f81f83a0 stur x0, [x29,#-8]
c4: f81f03a1 stur x1, [x29,#-16]
jclass cls_Integer = (*env)->FindClass(env, "Ljava/lang/Integer;");
c8: f85f83a9 ldur x9, [x29,#-8]
cc: f9400129 ldr x9, [x9]
d0: f9401929 ldr x9, [x9,#48]
d4: f85f83a0 ldur x0, [x29,#-8]
d8: aa0803e1 mov x1, x8
dc: f90007e2 str x2, [sp,#8]
e0: f90003e3 str x3, [sp]
e4: d63f0120 blr x9
e8: f9000fe0 str x0, [sp,#24]
jmethodID mid_Integer_value = (*env)->GetMethodID(env, cls_Integer, "intValue", "()I");
ec: f85f83a8 ldur x8, [x29,#-8]
f0: f9400108 ldr x8, [x8]
f4: f9408508 ldr x8, [x8,#264]
f8: f85f83a0 ldur x0, [x29,#-8]
fc: f9400fe1 ldr x1, [sp,#24]
100: f94007e2 ldr x2, [sp,#8]
104: f94003e3 ldr x3, [sp]
108: d63f0100 blr x8
10c: f9000be0 str x0, [sp,#16]
return (*env)->CallIntMethod(env, obj, mid_Integer_value);
110: f85f83a8 ldur x8, [x29,#-8]
114: f9400108 ldr x8, [x8]
118: f940c508 ldr x8, [x8,#392]
11c: f85f83a0 ldur x0, [x29,#-8]
120: f85f03a1 ldur x1, [x29,#-16]
124: f9400be2 ldr x2, [sp,#16]
128: d63f0100 blr x8
12c: a9437bfd ldp x29, x30, [sp,#48]
130: 910103ff add sp, sp, #0x40
134: d65f03c0 ret
The main differences are the offsets used in the ldr x8
calls.主要区别在于
ldr x8
调用中使用的偏移量。 These are offsets into the function pointer table inside the JNIEnv
, more specifically:这些是
JNIEnv
内函数指针表的偏移量,更具体地说:
GetFieldID
is at offset 752 GetFieldID
位于偏移量 752GetIntField
is at offset 800 GetIntField
位于偏移量 800GetMethodID
is at offset 264 GetMethodID
位于偏移量 264CallIntMethod
is at offset 392. CallIntMethod
位于偏移量 392 处。 The other difference is the signature passed to the GetIntField
or GetMethodID
, which is injected at linker time.另一个区别是传递给
GetIntField
或GetMethodID
的签名,它是在链接器时注入的。 The object file I dumped is not linked yet, so there are dummy instructions there.我转储的目标文件还没有链接,所以那里有虚拟指令。 It is the fourth argument so it is passed in register
x3
.它是第四个参数,因此它在寄存器
x3
传递。
So, to summarize, you need to do the following:因此,总而言之,您需要执行以下操作:
"()I"
somewhere in the library or add it to the string table."()I"
的地址或将其添加到字符串表中。java.lang.Integer#value
is accessed.java.lang.Integer#value
地方。ldr x8
right before the blr x8
call.blr x8
调用之前blr x8
ldr x8
的两个函数指针偏移量 (752 -> 264; 800 -> 392)。x3
and make it point to "()I"
instead.x3
的代码并使其指向"()I"
。 Good luck!祝你好运!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.