和之前稍微不同,这次要稍微分析一下 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 = %d\n", 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_ERROR\n"); 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 = %d\n", 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 传输数据有大小限制,分不同情况限制不同,总之一次性还是不能传无限大的数据,传个

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

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

Android native进程间通信实例-binder篇之——用parcel传输数组的更多相关文章

  1. Android native进程间通信实例-binder篇之——HAL层访问JAVA层的服务

    有一天在群里聊天的时候,有人提出一个问题,怎样才能做到HAL层访问JAVA层的接口?刚好我不会,所以做了一点研究. 之前的文章末尾部分说过了service call 可以用来调试系统的binder服务 ...

  2. Android native进程间通信实例-binder篇之——简单的单工通信

    网上找了很多binder相关文章,大部分都是在跟踪binder实现源代码,然后再把框架代码贴出来,看着实在费力. 这篇文章从实际出发,直接用一个案例下手,后续想了解binder相关原理的话,可以参考& ...

  3. Android native进程间通信实例-binder篇之——解决实际问题inputreader内建类清楚缓存

    我在实际开发中,遇到一个问题,在电容屏驱动中没有发送input_sync 给上层,导致电容屏有的数据缓存在inputreader 中,会导致系统一系列奇怪问题发生, 至于为什么驱动不发送input_s ...

  4. Android native进程间通信实例-binder结合共享内存

    在android源码的驱动目录下,一般会有共享内存的相关实现源码,目录是:kernel\drivers\staging\android\ashmem.c.但是本篇文章不是讲解android共享内存的功 ...

  5. Android native进程间通信实例-socket本地通信篇之——基本通信功能

    导读: 网上看了很多篇有关socket本地通信的示例,很多都是调通服务端和客户端通信功能后就没有下文了,不太实用,真正开发中遇到的问题以及程序稳定性部分没有涉及,代码健壮性不够,本系列(socket本 ...

  6. Android native进程间通信实例-socket本地通信篇之——服务端进程异常退出解决办法

    导读: 好难受啊,为什么服务端说挂就挂,明明只是客户端关闭而已,服务端怎么能挂呢? 想想,如果手机上使用一个聊天程序的时候,手机端关闭了聊天程序,那么远端服务器程序总不能说挂就挂吧!所以一定要查明真相 ...

  7. 【Android】进程间通信IPC——Binder

    Binder是Android中的跨进程通信方式,bindService的时候,服务端返回Binder对象,通过该对象客户端可以从服务端获取数据.在进程间通信IPC——AIDL中创建了ICustomAi ...

  8. Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了A ...

  9. Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6633311 在上一篇文章中,我 们分析了And ...

随机推荐

  1. 强烈推荐node包colors

    库链接:colors 在你的 node.js 控制台中获取颜色

  2. 一些常用的WebServices

    天气预报Web服务,数据来源于中国气象局 Endpoint  Disco  WSDL IP地址来源搜索 WEB 服务(是目前最完整的IP地址数据) Endpoint  Disco  WSDL 随机英文 ...

  3. 转载:Adb远程连接Android系统(通过网络使用ADB(Connect to android with wifi))

    本文介绍如何通过网络(尤指无线网络)与Android的adbd进行连接.原理:adb server: 计算机上的一个服务进程,进程名为adbadb daemon: Android 手机上的一个服务进程 ...

  4. Win7使用初体验

    作者:朱金灿 来源:http://blog.csdn.net/clever101 最近装了个Win7旗舰版.随着年纪渐大,我对软件使用越来越趋于务实,不再追求最新版本,因为我评价一个好软件的标准是适用 ...

  5. Qt 格式转换问题 记录(好多方法)

    用Qt经常头痛于一些格式不能通用的问题 在此记录备用 1 (20120112)QString转为Char * QString *str; char *a; str="hello word ! ...

  6. Qt 的几个核心机制总结之 布局(QWidget可以设置setSizePolicy,而QSizePolicy有Fixed,minimum,maximum,preferred,expanding,ignore等7个属性,还可以横竖分开)

    1.Qt布局的作用 Qt的布局是通过布局管理器来实现的,布局管理器负责在父类窗口部件区域构建子窗口部件,使得放置在窗体中的每个窗口部件都有一个适合的大小和位置,并且能够随着应用程序本身的变化而变化从而 ...

  7. ubuntu12.04单卡server(mentohust认证)再加上交换机做路由软件共享上网

    最近成立了实验室的网络环境中,通过交换机连接的所有主机实验室.想要一个通过该server(单卡)做网关,使用mentohust认证外网,然后内网中的其它主机通过此网关来连接外网. 1.首先在serve ...

  8. OpenGL(十五) OpenCV+OpenGL实现水面倒影

    有两幅原始图片,一个是景物图像,一个是水面图像,尝试生成景物在水中的倒影: 在OpenGL中,加载并显示这个景物图像可以把这个图像作为纹理载入即可,把图像直接选择180度的效果就相当于是在镜面中倒影的 ...

  9. hdu 4035 可能性DP 成都网络游戏

    http://acm.hdu.edu.cn/showproblem.php?pid=4035 获得: 1.首先推断是不是树.事实上,所有的感觉身影,既看边数==算-1是不成立 2.有时候,我告诉孩子来 ...

  10. apt-spy 软件源更新

    ebian上的apt-get是最快的软件安装方式,不过要用好apt-get,首先得需要找到最快的源,这样安装软件的时候才能获得好的速度,用起来才能得心应手. 有的源在用了一段以后,就会失效,这个时候, ...