我是靠谱客的博主 飘逸白昼,最近开发中收集的这篇文章主要介绍Android native进程间通信实例-binder篇之——用parcel传输数组,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

 和之前稍微不同,这次要稍微分析一下 Parce.cpp 和 android_os_Parcel.cp p的源码,为的是能够掌握调试技巧,后续传输其它类型数据就能举一反三了!
 
1. 代码共享

这次不贴Android.mk代码了,直接沿用之前写的即可,传送门 https://www.cnblogs.com/songsongman/p/11097196.html

a. 服务端mybinderserver.cpp代码如下:

#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/IInterface.h>
#include<stdio.h>
#define LOG_TAG "binderserver"
using namespace android;
class MyBinderService : public BBinder{
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
printf("MyBinderService onTransact code = %dn", code);
int readLen = 0;
float *readPencilData = NULL;
if(code == 123)
{
readLen = data.readInt32();
readPencilData = (float *)malloc(readLen*sizeof(float));
readPencilData = (float *)data.readInplace(readLen);
for(int i = 0; i < readLen; i++)
{
printf("readPencilData[%d] = %f n", i, readPencilData[i]);
}
free(readPencilData);
readPencilData = NULL;
}
printf("return NO_ERRORn");
return NO_ERROR;
}
};
int main(int argc, char** argv)
{
sp<IBinder> serverBinder = new MyBinderService();
defaultServiceManager()->addService(String16("mybindertag"), serverBinder);
printf("main addService n");
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
printf("never return!!! n");
return 0;
}

 

b. 客户端mybinderclient.cpp代码如下:

#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/IInterface.h>
#include<stdio.h>
#define LOG_TAG "binderclient"
using namespace android;
#define WRITESARRYSIZE 10
int main(int argc, char** argv)
{
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->checkService(String16("mybindertag"));
float writeArry[WRITESARRYSIZE] = {123.123, 234.234, 345.345, 456.456, 567.567,
678.678, 789.789, 890.890, 901.901, 012.012};
if (binder == 0)
{
printf("service is not found !n");
return 0;
}
else
{
sp<IBinder> binder = defaultServiceManager()->getService(String16("mybindertag"));
}
while(1)
{
Parcel data, reply;
int transCode = 0;
int writeInt = 0;
int replyInt = 0;
printf("please input transCode : n");
scanf("%d", &transCode);
getchar();
if(123 == transCode)
{
data.writeInt32(WRITESARRYSIZE);
status_t ret = 0;
ret = data.write((void *)writeArry, WRITESARRYSIZE*sizeof(float));
if(ret != NO_ERROR)
perror("trans failed!!");
}
binder->transact(transCode, data, &reply);
replyInt = reply.readInt32();
printf("get reply data = %dn", replyInt);
}
return 0;
}

  

测试效果:

 

 

 

 2. 源码分析

首先讲一个故事,我之前不知道binder能直接传数据块,一直都是用客户端一个个数据写,然后服务端一个个数据读的低效率模式。

后来android系统层的一位同事告诉我,java层binder可以直接用 writeByteArray来传输数组等大块数据,传一次就行,听的我面红耳赤,

看来平时研究的少确实会影响代码的执行效率啊。

 

a. 突破口 writeByteArray

在 framework 代码中搜索 cpp 文件,执行命令:

grep -rn "writeByteArray" --include "*.cpp" ./frameworks/

发现在/frameworks/native/libs/binder/Parcel.cpp 有这个函数的实现,但是进去看以后大失所望,因为没有readByteArray的实现,在native层

我总不能只会写不会读吧。

 

b. 不卖关子了,直接打开所有相关源码,一目了然

./frameworks/base/core/java/android/os/Parcel.java

./frameworks/base/core/jni/android_os_Parcel.cpp

./frameworks/native/libs/binder/Parcel.cpp

可以很清晰的知道调用过程,由于代码量比较小就不画流程框图了:

writeByteArray:Parcel.java(writeByteArray) -> android_os_Parcel.cpp(android_os_Parcel_writeNative) -> Parcel.cpp(writeInt32) -> Parcel.cpp(writeInplace)

readByteArray:Parcel.java(readByteArray) -> android_os_Parcel.cpp(android_os_Parcel_createByteArray) -> Parcel.cpp(readInplace

 

c. 选取native层可以用的函数直接用上

在 android_os_Parcel_writeNative 中,写数组数据,先要用 writeInt32 要写入的数据大小,然后再 writeInplace 返回一个地址,接着把要传输的数据 memcpy 到这个地址上,好奇的我发现

 writeInplace + memcpy 的操作其实就是在Parcel.cpp源码 status_t Parcel::write(const void* data, size_t len)的操作,所以后续写数组,直接用 Parcel::write 即可

至于 readInplace 就没啥好说的了,直接传入要读的数据块大小,返回一个地址,取数据就行了。

 

大概分析思路就是这样子了,后续要传输别的数据类型,直接参考这个模式即可。但是binder 传输数据有大小限制,分不同情况限制不同,总之一次性还是不能传无限大的数据,传个

小图片足够就行了。具体限制多少可以参考网上其它的博客。

 

希望大家多多吐槽,大家一起共同进步!!

 

 

 

转载于:https://www.cnblogs.com/songsongman/p/11097216.html

最后

以上就是飘逸白昼为你收集整理的Android native进程间通信实例-binder篇之——用parcel传输数组的全部内容,希望文章能够帮你解决Android native进程间通信实例-binder篇之——用parcel传输数组所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部