Closed ddrccw closed 3 years ago
@hui19 麻烦看下整型数精度问题
32位系统下,long、double为8字节,void指针为4字节,值传递过程中造成了精度问题,对32位64位中的long、double进行不同的处理,该问题已修复见 #71
实测代码里还有两处问题,已反馈到 #71
问题未修复,测试设备vivo x9
可以看一下代码里的case
bool resultCall = stub.complexCall("test", 10, 'a', 10.0, 12.0, 1, 2, 10000, false); print('call result:$resultCall');
可以看到输出的日志
2021-10-22 14:29:28.398 25768-25925/com.dartnative.example D/dart_java: tag :test + 10 + a + 2097152.0 + 12.0 + 1 + 2 + 10000 + false
比较诡异 lib/src/android/runtime/jobject.dart 在storeValueToPointer 12.0 过后,再通过loadValueFromPointer可以看到pointers.elementAt(3).value的数据发生变化,从10.0 变成了2097152
@ddrccw 感谢反馈,我们继续查下
问题未修复,测试设备vivo x9 可以看一下代码里的case
bool resultCall = stub.complexCall("test", 10, 'a', 10.0, 12.0, 1, 2, 10000, false); print('call result:$resultCall');
可以看到输出的日志
2021-10-22 14:29:28.398 25768-25925/com.dartnative.example D/dart_java: tag :test + 10 + a + 2097152.0 + 12.0 + 1 + 2 + 10000 + false
比较诡异 lib/src/android/runtime/jobject.dart 在storeValueToPointer 12.0 过后,再通过loadValueFromPointer可以看到pointers.elementAt(3).value的数据发生变化,从10.0 变成了2097152
@ddrccw 是指在dart这边主动调用loadValueFromPointer解析第三个value吗?如果是这样, dart 传递给 native 的数据是保存到指针里面,native 在取指针的值。而 native 传递基本类型给 dart 的值是作为地址值传递的,dart 通过读取地址来还原基本类型值。所以基本类型在 storeValueToPointer 的数据不能直接用 loadValueFromPointer 读出来,可以参考这里
@ddrccw pointers.elementAt(3).cast < Double > ().value 试试这样取值
@hui19
换种取法也是一样的,我用华为手机P40 (ANA-AN00) 也是一样的结果
jobject.dart代码
NativeArguments _parseNativeArguments(List args, {List argsSignature}) {
Pointer<Pointer<Void>> pointers = nullptr.cast();
/// extend a bit for string
Pointer<Pointer<Utf8>> typePointers =
allocate<Pointer<Utf8>>(count: (args?.length ?? 0) + 1);
int stringTypeBitmask = 0;
if (args != null) {
pointers = allocate<Pointer<Void>>(count: args.length);
final bool _is64Bit = sizeOf<IntPtr>() == 8;
var pVoid = sizeOf<Pointer<Void>>();
var pDouble = sizeOf<Pointer<Double>>();
var pFloat = sizeOf<Pointer<Float>>();
for (var i = 0; i < args.length; i++) {
var arg = args[i];
if (arg == null) {
throw 'One of args list is null';
}
Pointer<Utf8> argSignature =
argsSignature == null || !(argsSignature[i] is Pointer<Utf8>)
? null
: argsSignature[i];
if (arg is String) {
stringTypeBitmask |= (0x1 << i);
}
if (i == 4) {
int index = 0;
Pointer<Void> ptr0 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr0 = typePointers.elementAt(index);
var ret0;
Pointer<Uint16> tmp = pointers.elementAt(index).cast<Pointer<Uint16>>().value;
var uint16Ptr = tmp.cast<Void>();
int length = 0;
for (int i = 0; i < 2; i++) {
length += uint16Ptr.cast<Uint16>().elementAt(i).value;
}
Uint16List list = uint16Ptr.cast<Uint16>().asTypedList(length + 3);
//free(uint16Ptr);
final codes = String.fromCharCodes(list.sublist(2, length + 2));
ret0 = codes;
index = 1;
Pointer<Void> ptr1 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr1 = typePointers.elementAt(index);
var ret1 = ptr1.cast<Int32>().value;
index = 2;
Pointer<Void> ptr2 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr2 = typePointers.elementAt(index);
var tmp2 = ptr2.cast<Uint16>().value;
var ret2 = utf8.decode([tmp2]);
// var ret20 = loadValueFromPointer(ptr2, "Ljava/lang/String;", typePtr:typePtr2);
// var ret21 = loadValueFromPointer(ptr2, "Ljava/lang/String;", typePtr:typePtr2);
index = 3;
Pointer<Void> ptr3 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr3 = typePointers.elementAt(index);
var ret = ptr3.cast<Double>().value;
// var ret30 = loadValueFromPointer(ptr3, "D", typePtr:typePtr3);
// var ret31 = loadValueFromPointer(ptr3, "D", typePtr: typePtr3);
print("index 4 before storeValueToPointer," + ret0 + "," + ret1.toString() + "," + ret2 + "," + ret.toString() + ",");
}
storeValueToPointer(arg, pointers.elementAt(i),
typePtr: typePointers.elementAt(i), argSignature: argSignature);
if (arg is double && i == 3) {
int index = 0;
Pointer<Void> ptr0 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr0 = typePointers.elementAt(index);
var ret0;
Pointer<Uint16> tmp = pointers.elementAt(index).cast<Pointer<Uint16>>().value;
var uint16Ptr = tmp.cast<Void>();
int length = 0;
for (int i = 0; i < 2; i++) {
length += uint16Ptr.cast<Uint16>().elementAt(i).value;
}
Uint16List list = uint16Ptr.cast<Uint16>().asTypedList(length + 3);
//free(uint16Ptr);
final codes = String.fromCharCodes(list.sublist(2, length + 2));
ret0 = codes;
index = 1;
Pointer<Void> ptr1 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr1 = typePointers.elementAt(index);
var ret1 = ptr1.cast<Int32>().value;
index = 2;
Pointer<Void> ptr2 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr2 = typePointers.elementAt(index);
var tmp2 = ptr2.cast<Uint16>().value;
var ret2 = utf8.decode([tmp2]);
// var ret20 = loadValueFromPointer(ptr2, "Ljava/lang/String;", typePtr:typePtr2);
// var ret21 = loadValueFromPointer(ptr2, "Ljava/lang/String;", typePtr:typePtr2);
index = 3;
Pointer<Void> ptr3 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr3 = typePointers.elementAt(index);
var ret = ptr3.cast<Double>().value;
var floatValue = 10.0;
// var bytes = Uint8List(4)
// ..buffer.asByteData().setFloat32(0, floatValue, Endian.little);
var bytes = Float32List.fromList([floatValue]).buffer.asUint8List();
print(bytes);
// var ret30 = loadValueFromPointer(ptr3, "D", typePtr:typePtr3);
// var ret31 = loadValueFromPointer(ptr3, "D", typePtr: typePtr3);
print("index 3 after storeValueToPointer," + ret0 + "," + ret1.toString() + "," + ret2 + "," + ret.toString() + ",");
}
if (i == 4) {
int index = 0;
Pointer<Void> ptr0 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr0 = typePointers.elementAt(index);
var ret0;
Pointer<Uint16> tmp = pointers.elementAt(index).cast<Pointer<Uint16>>().value;
var uint16Ptr = tmp.cast<Void>();
int length = 0;
for (int i = 0; i < 2; i++) {
length += uint16Ptr.cast<Uint16>().elementAt(i).value;
}
Uint16List list = uint16Ptr.cast<Uint16>().asTypedList(length + 3);
//free(uint16Ptr);
final codes = String.fromCharCodes(list.sublist(2, length + 2));
ret0 = codes;
index = 1;
Pointer<Void> ptr1 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr1 = typePointers.elementAt(index);
var ret1 = ptr1.cast<Int32>().value;
index = 2;
Pointer<Void> ptr2 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr2 = typePointers.elementAt(index);
var tmp2 = ptr2.cast<Uint16>().value;
var ret2 = utf8.decode([tmp2]);
// var ret20 = loadValueFromPointer(ptr2, "Ljava/lang/String;", typePtr:typePtr2);
// var ret21 = loadValueFromPointer(ptr2, "Ljava/lang/String;", typePtr:typePtr2);
index = 3;
Pointer<Void> ptr3 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr3 = typePointers.elementAt(index);
var ret = ptr3.cast<Double>().value;
var floatValue = ret;
// var bytes = Uint8List(4)
// ..buffer.asByteData().setFloat32(0, floatValue, Endian.little);
var bytes = Float32List.fromList([floatValue]).buffer.asUint8List();
print(bytes);
index = 4;
Pointer<Void> ptr4 = pointers.elementAt(index).cast<Void>();
Pointer<Pointer<Utf8>> typePtr4 = typePointers.elementAt(index);
var ret4 = ptr4.cast<Float>().value;
print("index 4 after storeValueToPointer," + ret0 + "," + ret1.toString() + "," + ret2 + "," + ret.toString() + "," + ret4.toString());
}
}
}
typePointers.elementAt(args?.length ?? 0).value = Utf8.toUtf8("0");
return NativeArguments(pointers, typePointers, stringTypeBitmask);
}
对应日志 2021-10-29 14:35:52.276 26793-31510/com.dartnative.example I/flutter: [0, 0, 32, 65] 2021-10-29 14:35:52.276 26793-31510/com.dartnative.example I/flutter: index 3 after storeValueToPointer,test,10,a,10.0, 2021-10-29 14:35:52.276 26793-31510/com.dartnative.example I/flutter: index 4 before storeValueToPointer,test,10,a,10.0, 2021-10-29 14:35:52.277 26793-31510/com.dartnative.example I/flutter: [0, 0, 0, 74] 2021-10-29 14:35:52.277 26793-31510/com.dartnative.example I/flutter: index 4 after storeValueToPointer,test,10,a,2097152.0,12.0 2021-10-29 14:35:52.277 26793-31510/com.dartnative.example I/flutter: ret 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: invokeNativeMethod methodName=complexCall, returnType=Z 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: _fillArgs index=0, type=L 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: _fillArgs index=1, type=I 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: _fillArgs index=2, type=C 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: _fillArgs index=3, type=D 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: _fillArgs index=4, type=F 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: _fillArgs index=5, type=B 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: _fillArgs index=6, type=S 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: _fillArgs index=7, type=J 2021-10-29 14:35:52.278 26793-31510/com.dartnative.example D/DartNative: _fillArgs index=8, type=Z 2021-10-29 14:35:52.279 26793-31510/com.dartnative.example D/dart_java: tag :test + 10 + a + 2097152.0 + 12.0 + 1 + 2 + 10000 + false
问题
native_basic_type定义的long类型数据,在安卓仅构建armeabi-v7a架构的包时,如果long类型数据值大于2147483647(2^31-1),java侧获取的数据存在转换丢失的情况
double类型数据也不太对
具体案例
Dart_Native 版本:0.3.22
flutter环境 Flutter version 1.22.6 Dart version 2.10.5
修改如下几个文件
example/android/app/build.gradle
example/lib/android/unit_test.dart
NativeArguments _parseNativeArguments(List args, {List argsSignature}) { Pointer<Pointer> pointers = nullptr.cast();
}
2021-09-06 22:19:29.891 15223-16988/com.dartnative.dart_native_example I/flutter: DartNative _parseNativeArguments arg=2147483647, storeValueToPointer value=2147483647, loadValueFromPointer value=2147483647 2021-09-06 22:19:29.891 15223-16988/com.dartnative.dart_native_example D/dart_java: tag :test + 2147483647 + a + 2097152.0 + 12.0 + 1 + 2 + 2147483647 + false 2021-09-06 22:19:29.891 15223-16988/com.dartnative.dart_native_example I/flutter: call result:true 2021-09-06 22:19:29.891 15223-16988/com.dartnative.dart_native_example I/flutter: DartNative _parseNativeArguments arg=2147483648, storeValueToPointer value=2147483648, loadValueFromPointer value=2147483648 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example D/dart_java: tag :test + -2147483648 + a + 2097152.0 + 12.0 + 1 + 2 + -2147483648 + false 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example I/flutter: call result:true 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example I/flutter: DartNative _parseNativeArguments arg=4294967295, storeValueToPointer value=4294967295, loadValueFromPointer value=4294967295 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example D/dart_java: tag :test + -1 + a + 2097152.0 + 12.0 + 1 + 2 + -1 + false 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example I/flutter: call result:true 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example I/flutter: DartNative _parseNativeArguments arg=4294967296, storeValueToPointer value=4294967296, loadValueFromPointer value=0 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example D/dart_java: tag :test + 0 + a + 2097152.0 + 12.0 + 1 + 2 + 0 + false 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example I/flutter: call result:true 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example I/flutter: DartNative _parseNativeArguments arg=42949672960, storeValueToPointer value=42949672960, loadValueFromPointer value=0 2021-09-06 22:19:29.892 15223-16988/com.dartnative.dart_native_example D/dart_java: tag :test + 0 + a + 2097152.0 + 12.0 + 1 + 2 + 0 + false
// java long赋值打印结果 2021-09-06 22:34:20.989 16940-19032/com.dartnative.dart_native_example D/dart_java: java long:2147483647 + 2147483648 + 4294967295 + 4294967295 + 4294967296 + 42949672960