此次不贴Android.mk代码了,直接沿用以前写的便可,传送门 http://www.javashuo.com/article/p-soutduzp-eg.htmlhtml
a. 服务端mybinderserver.cpp代码以下:java
#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代码以下:android
#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来传输数组等大块数据,传一次就行,听的我面红耳赤,post
看来平时研究的少确实会影响代码的执行效率啊。测试
a. 突破口 writeByteArrayui
在 framework 代码中搜索 cpp 文件,执行命令:spa
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 传输数据有大小限制,分不一样状况限制不一样,总之一次性仍是不能传无限大的数据,传个
小图片足够就好了。具体限制多少能够参考网上其它的博客。
但愿你们多多吐槽,你们一块儿共同进步!!