Android与NativeC传递数据不正确问题
来源:互联网 发布:js div display none 编辑:程序博客网 时间:2024/05/23 13:33
从Java传递数组到JNI层
JNI层接收Java层传递过来的 byte[] 数组,一般有两个函数来获取它的值,一个是通过 GetByteArrayRegin,另一个就是 GetByteArrayElements,前者是进行拷贝操作,将Java端虚拟机托管的内存数组拷贝到本地系统的数组中,后者是通过指针引用的方式,将本地系统的数组指针直接指向Java端虚拟机托管的数组对象的堆地址。由于是在移动设备上开发,出于性能的考虑选择 GetByteArrayElements 来完成任务。
获取字节数组地址函数原型:
jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy) { return functions->GetByteArrayElements(this, array, isCopy); }
Java调用测试代码如下:
public native void heitaoFilter(byte[] buffer); private void test() { byte[] buffer = {0x01, 0x02, 0x03, 0x04}; heitaoFilter(buffer); Log.d("heitaoflower", Arrays.toString(buffer)); }
NativeC具体使用的测试代码如下:
JNIEXPORT void JNICALLJava_io_heitao_Test_Filter( JNIEnv *env, jobject, jbyteArray buffer){ int32_t buffer_size = env->GetArrayLength(buffer); int8_t *pBuffer = env->GetByteArrayElements(buffer, NULL); if (pBuffer != NULL) { for (int32_t i = 0; i < buffer_size; i++) { pBuffer[i] = 0; } }}
调用的输出结果如图所示:
可以观测到 Output byte[] 数组依然为之前的 0x01, 0x02, 0x03, 0x04 。这是为什么呢?命名通过指针引用进行了修改,可是结果没有变化。
通过查阅资料在 Android Official Website 关于 JNI TIPS 有一段话给出了解释,大概意思是根据不同的JVM实现 GetByteArrayElements 在运行时可能返回指针,也可能返回一份本地拷贝的指针,之前的测试程序就是因为返回了拷贝的指针。
FAQ: How do I share raw data with native code?You may find yourself in a situation where you need to access a large buffer of raw data from both managed and native code. Common examples include manipulation of bitmaps or sound samples. There are two basic approaches.You can store the data in a byte[]. This allows very fast access from managed code. On the native side, however, you're not guaranteed to be able to access the data without having to copy it.
In some implementations, GetByteArrayElements and GetPrimitiveArrayCritical will return actual pointers to the raw data in the managed heap, but in others it will allocate a buffer on the native heap and copy the data over.The alternative is to store the data in a direct byte buffer. These can be created with java.nio.ByteBuffer.allocateDirect, or the JNI NewDirectByteBuffer function.
Unlike regular byte buffers, the storage is not allocated on the managed heap, and can always be accessed directly from native code (get the address with GetDirectBufferAddress).
Depending on how direct byte buffer access is implemented, accessing the data from managed code can be very slow.The choice of which to use depends on two factors:Will most of the data accesses happen from code written in Java or in C/C++?If the data is eventually being passed to a system API, what form must it be in? (For example, if the data is eventually passed to a function that takes a byte[], doing processing in a direct ByteBuffer might be unwise.)If there's no clear winner, use a direct byte buffer. Support for them is built directly into JNI, and performance should improve in future releases.
解决问题
该问题解决思路仍然是性能放在第一位,避免内存的拷贝操作,根据Android JNI 官方给出的建议使用Java的 Direct ByteBuffer 配合GetDirectBufferAddress 来解决问题。所谓 Direct ByteBuffer 简单说就是从操作系统直接分配物理内存,而不是从JVM获取托管的内存,如此就可以通过NativeC的代码修改系统的内存数据了,相关的函数及修改后代码如下:
获取 Direct Buffer 容量函数原型:
jlong GetDirectBufferCapacity(jobject buf) { return functions->GetDirectBufferCapacity(this, buf); }
获取 Direct Buffer 地址函数原型:
void* GetDirectBufferAddress(jobject buf) { return functions->GetDirectBufferAddress(this, buf); }
修改后的Java代码如下:
public native void heitaoFilter(ByteBuffer buffer); private void test() { byte[] data = {0x01, 0x02, 0x03, 0x04}; ByteBuffer buffer = ByteBuffer.allocateDirect(data.length); buffer.put(data); heitaoFilter(buffer); buffer.flip(); buffer.get(data); Log.d("heitaoflower", Arrays.toString(data)); }
修改后的NativeC代码如下:
JNIEXPORT void JNICALLJava_io_heitao_Test_Filter( JNIEnv *env, jobject, jobject buffer){ int32_t buffer_size = (int32_t)env->GetDirectBufferCapacity(buffer); int8_t *pBuffer = (int8_t *)(env->GetDirectBufferAddress(buffer)); if (pBuffer != NULL) { for (int32_t i = 0; i < buffer_size; i++) { pBuffer[i] = 0; } }}
可以观测到 Output ByteBuffer内部系统分配的直接内存数据修改为 0x00, 0x00, 0x00, 0x00,成功修改。
- Android与NativeC传递数据不正确问题
- python与mysql传递数据乱码问题
- android 关于Notification传递数据问题
- Android中AyncTask数据同步传递问题
- Android界面跳转与数据传递
- Android-Activity与Fragment之间传递数据
- Android activity与service传递数据
- android Activity数据传递onActivityResult与setResut
- Android 与 H5 数据的传递
- 关于android与php传递数据,引号显示"的问题
- 【android】通过User-Agent,解决httppost从服务器上获取的数据不正确的问题
- android的调试技巧,尤其是nativec等底层程序
- Android的调试技巧,尤其是nativec等底层程序
- android的调试技巧,尤其是nativec等底层程序
- 【Android】intent传递数据时,数据大小的限制问题
- 【Android】intent传递数据时,数据大小的限制问题
- Android问题—定义全局数据代替Intent传递数据
- Android 数据传递出现的android.os.TransactionTooLargeException问题
- 文章标题
- 目前自身欠缺的技能
- 日历和EWS在Exchange
- 盘点:U盘损坏后如何修复的五种状况和解决方法
- with open使用方法
- Android与NativeC传递数据不正确问题
- babel从入门到入门
- Linux命令学习
- JVM源码分析之javaagent原理完全解读
- Pingback漏洞利用技术
- 在 centos上安装ceph与openstack集成
- 【华为】删数
- 数据结构——B-tree(多路搜索树)
- 周星驰,你别这么贬低自己好嘛,你已经很努力了!