Java.lang.NoSuchFieldError: no "I" field "value" in class "Ljava/lang/Integer;" or its superclasses Android 10

huangapple go评论90阅读模式
英文:

Java.lang.NoSuchFieldError: no "I" field "value" in class "Ljava/lang/Integer;" or its superclasses Android 10

问题

我收到了一个来自客户的 .so Android 库,我需要将其集成到我的 Xamarin Forms 项目中。这个库帮助应用程序连接到物联网设备。由于库中的方法具有以下签名,我决定编写一个 Java 包装器来简化参数并创建一个 aar 文件。然后,我会原生地绑定这个 aar 并将其作为项目中的 dll 使用。

值得注意的是,在 Xamarin 中,只有在编译目标大于 10 时才会出现问题。否则,它可以正常工作。我猜测是因为 最新的非 SDK 接口更新破坏了应用程序

库的头文件:

public static native int ReadParams(String token, StringBuilder serial, StringBuilder ssid, StringBuilder password, StringBuilder sensor, Integer keepAlive);

问题:
这个方法在从本地 Android 应用程序内部调用时可以正常工作,但在 Xamarin Forms 中调用时会崩溃,并显示以下错误。崩溃发生在 Java 包装器的下面一行。

崩溃行:

StringBuilder strSerial = new StringBuilder();
StringBuilder strssid = new StringBuilder();
StringBuilder strpassword = new StringBuilder();
StringBuilder strsensor = new StringBuilder();
Integer keepAlive = new Integer(0);
// 崩溃发生在下面这行
int response = EPM002Lib.ReadParams(token, strSerial, strssid, strpassword, strsensor, keepAlive);

堆栈跟踪:

--- 管理的 Java.Lang.IncompatibleClassChangeError 堆栈跟踪结束 ---
java.lang.NoSuchFieldError: 在类 "Ljava/lang/Integer;" 或其父类中没有名为 "value" 的 "I" 字段
at com.esong.lib.EPM002Lib.ReadParams(Native Method) at
com.sensorwa.config.configdemo.SquareSdkhelper.ReadParams(SquareSdkhelper.java:32)

我理解获取关于 EPM002Lib.ReadParams 内部功能的更多信息可能会有帮助,然而,这个库似乎可以在本地 Android 应用程序中正常工作(甚至在针对 Android 10 编译时也可以)。请随时要求获取更多信息或提供建议。感谢帮助!🙂

英文:

I have received a .so android library from a client and I have to integrate that in my Xamarin Forms project. The library helps the app connect to an IoT device. 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. Afterwards, I natively bind the aar and use it as a dll in my project.

It is important to note that the problem in Xamarin only occurs when the Compile Target is > 10. Otherwise, it works fine. My guess is that the latest Updates to non-SDK interfaces broke the application.

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. The crash is on the following line in the Java wrapper.

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;" or its superclasses at
> 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). Please feel free to ask for more information or provide suggestions. Thanks for the help 😄

答案1

得分: 1

你依赖了一个本不应该依赖的实现细节。

现在它崩溃了,而你得保留这两个碎片。

英文:

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.

答案2

得分: 1

我使用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);
}

这导致了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
}

以及对于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

<details>
<summary>英文:</summary>

I compiled this file using the Android Aarch64 compiler:

#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`:

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`:

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. These are offsets into the function pointer table inside the `JNIEnv`, more specifically:
- `GetFieldID` is at offset 752
- `GetIntField` is at offset 800
- `GetMethodID` is at offset 264
- `CallIntMethod` is at offset 392.
The other difference is the signature passed to the `GetIntField` or `GetMethodID`, which is injected at linker time. 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`.
So, to summarize, you need to do the following:
- Find the address of the string `&quot;()I&quot;` somewhere in the library or add it to the string table.
- You need to find all places where `java.lang.Integer#value` is accessed.
- Replace the two function pointer offsets (752 -&gt; 264; 800 -&gt; 392) in the `ldr x8` right before the `blr x8` call.
- Find the code that changes `x3` and make it point to `&quot;()I&quot;` instead.
Good luck!
</details>

huangapple
  • 本文由 发表于 2020年10月13日 01:37:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/64322722.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定