Java.lang.NoSuchFieldError:否“;我";“字段”;“价值”;“课堂上”;Ljava/lang/Integer&引用;或者它的超类Android 10

Java.lang.NoSuchFieldError:否“;我";“字段”;“价值”;“课堂上”;Ljava/lang/Integer&引用;或者它的超类Android 10,java,android,java-native-interface,Java,Android,Java Native Interface,我从一个客户端收到了一个.so android库,我必须将它集成到我的Xamarin表单项目中。该库帮助应用程序连接到物联网设备。由于库方法具有以下特征,我决定编写一个java包装器来简化参数并创建一个aar文件。之后,我以本机方式绑定aar,并将其用作项目中的dll 需要注意的是,Xamarin中的问题只有在编译目标大于10时才会出现。否则,它可以正常工作。我猜是这样的 库标题: public static native int ReadParams(String token, StringB

我从一个客户端收到了一个.so android库,我必须将它集成到我的Xamarin表单项目中。该库帮助应用程序连接到物联网设备。由于库方法具有以下特征,我决定编写一个java包装器来简化参数并创建一个aar文件。之后,我以本机方式绑定aar,并将其用作项目中的dll

需要注意的是,Xamarin中的问题只有在编译目标大于10时才会出现。否则,它可以正常工作。我猜是这样的

库标题:

public static native int ReadParams(String token, StringBuilder serial, StringBuilder ssid, StringBuilder password, StringBuilder sensor, Integer keepAlive);
问题是: 当从本机android应用程序中调用该方法时,该方法工作正常,但是由于Xamarin表单中的以下错误而崩溃。崩溃在Java包装器的下面一行

紧急救援线:

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);
堆栈跟踪:

---托管Java.Lang.CompatibileClassChangeError堆栈跟踪的结束---Java.Lang.NoSuchFieldError:类“Ljava/Lang/Integer”中没有“I”字段“value”;或其超类位于 com.esong.lib.EPM002Lib.ReadParams(本机方法)位于 com.sensorwa.config.configdemo.SquareSdkhelper.ReadParams(SquareSdkhelper.java:32)


我知道更多关于EPM002Lib.ReadParams参数内部功能的信息会有所帮助,但是,该库似乎可以与本机android应用程序一起使用(即使是针对android 10编译)。请随时询问更多信息或提供建议。感谢您的帮助您所依赖的是一个不应该依赖的实现细节


现在它坏了,你可以保留这两部分。

我使用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);
}
对于
访问方法

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
int-access\u方法(JNIEnv*env,jobject-obj){
9c:d10103ff子sp,sp,#0x40
a0:a9037bfd stp x29,x30,[sp,#48]
a4:9100c3fd添加x29,sp,#0x30
a8:9000008 adrp x8,0
ac:91000108添加x8,x8,#0x0
b0:9000002 adrp x2,0
b4:91000042添加x2,x2,#0x0
b8:9000003 adrp x3,0
bc:91000063添加x3,x3,#0x0
c0:f81f83a0序列x0,[x29,#-8]
c4:f81f03a1 stur x1[x29,#-16]
jclass cls_Integer=(*env)->FindClass(env,“Ljava/lang/Integer;”);
c8:f85f83a9 ldur x9,[x29,#-8]
抄送: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:F90000BE0 str x0[sp,#16]
return(*env)->CallIntMethod(env、obj、mid_整数值);
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添加sp,sp,#0x40
134:d65f03c0 ret
主要区别在于
ldrx8
调用中使用的偏移量。这些偏移量是
JNIEnv
中函数指针表中的偏移量,更具体地说:

  • GetFieldID
    位于偏移量752处
  • GetIntField
    位于偏移量800处
  • GetMethodID
    位于偏移量264处
  • CallIntMethod
    位于偏移量392处
另一个区别是传递给
GetIntField
GetMethodID
的签名,它在链接器时被注入。我转储的对象文件尚未链接,因此那里有伪指令。这是第四个参数,因此它在寄存器
x3
中传递

因此,总而言之,您需要执行以下操作:

  • 在库中的某个位置查找字符串
    “()I”
    的地址,或将其添加到字符串表中
  • 您需要找到访问
    java.lang.Integer#value
    的所有位置
  • 在调用
    blrx8
    之前,替换
    ldrx8
    中的两个函数指针偏移量(752->264;800->392)
  • 找到更改的代码
    x3
    ,并将其指向
    “()I”

祝你好运!

为什么库需要访问
int
字段呢?这听起来很糟糕。
Integer
s应该是不可变的,所以库不能试图修改值。如果他们只是想读取值,他们应该使用
intValue
方法。是的,我理解。但是,我只是好奇至于它在本机android上是如何工作的:/嗯,不清楚“针对android 10编译”的确切含义。如果你指的是
compileSdkVersion
,那么这在这里并不重要。重要的是
targetSdkVersion
(当然还有你运行应用程序的实际android版本)是的,它确实是compileSdkVersion,我认为它是相关的,因此在sdk 10中引入了对非sdk接口的更改。据我所知,targetSdkVersion是应用程序的目标版本,可能是用户群最多的版本。您似乎误解了
compileSdkVersion
的作用;它只确定了哪些API可在编译时使用。在确定如何应用这些类型的运行时行为更改时,
targetSdkVersion
是最重要的
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