此次不貼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 傳輸數據有大小限制,分不一樣狀況限制不一樣,總之一次性仍是不能傳無限大的數據,傳個
小圖片足夠就好了。具體限制多少能夠參考網上其它的博客。
但願你們多多吐槽,你們一塊兒共同進步!!