binder通信的特點和原理
Android系統(tǒng)是基于Linux的世蔗,那么關(guān)于進程間的通信同樣我們也可以參考Linux,有以下幾種:
管道:需要copy兩次數(shù)據(jù)
共享內(nèi)存:不需要拷貝數(shù)據(jù)惹想,但是不安全
socket:需要拷貝兩次數(shù)據(jù)
File:同上
Binder:拷貝一次數(shù)據(jù)片任,安全
Binder通信是支持一對多這樣的C/S模型的稿茉,這樣S端就可以對C端進行驗證裤翩,安全新就有了保障。
在Linux系統(tǒng)中褐缠,用戶進程是無法直接操作磁盤的物理內(nèi)存的政鼠,必須經(jīng)過內(nèi)核才可以操作,Binder的機制就是將物理內(nèi)存通過mmap方法映射到用戶空間队魏,這樣用戶空間就可以拿到實際的地址進行操作公般。
Binder Native的啟動過程:
在service_manager.c文件中
首先,先打開binder驅(qū)動胡桨,該驅(qū)動位于/dev/binder目錄下官帘,同時申請128k的內(nèi)存空間。
可以看到昧谊,首先是打開binder驅(qū)動刽虹,然后通過mmap函數(shù)來內(nèi)存映射,這里mmap必須是page的整數(shù)倍呢诬,一般來說page為4K涌哲。mmap()系統(tǒng)調(diào)用使得進程之間通過映射同一個普通文件實現(xiàn)共享內(nèi)存。
參數(shù)介紹:
addr: 建立映射區(qū)的首地址尚镰,由Linux內(nèi)核指定阀圾。使用時,直接傳遞NULL狗唉。
length: 欲創(chuàng)建映射區(qū)的大小初烘。
prot: 映射區(qū)權(quán)限PROT_READ、PROT_WRITE分俯、PROT_READ|PROT_WRITE肾筐。
flags: 標志位參數(shù)(常用于設定更新物理區(qū)域、設置共享缸剪、創(chuàng)建匿名映射區(qū))吗铐;
MAP_SHARED: 會將映射區(qū)所做的操作反映到物理設備(磁盤)上。
MAP_PRIVATE: 映射區(qū)所做的修改不會反映到物理設備杏节。
fd: 用來建立映射區(qū)的文件描述符抓歼。
offset: 映射文件的偏移(4k的整數(shù)倍)。
下面我們嘗試自己通過mmap函數(shù)來在用戶空間來寫入文件(app需要先申請動態(tài)讀寫權(quán)限):
extern "C"
JNIEXPORT void JNICALL
Java_com_yppcat_test_MainActivity_writeMmap(JNIEnv *env, jobject thiz) {
__android_log_print(ANDROID_LOG_ERROR, "MMap", "write start");
std::string file = "/storage/emulated/0/test.txt";
m_fd = open(file.c_str(), O_RDWR | O_CREAT, S_IRWXU);
if (m_fd == -1){
__android_log_print(ANDROID_LOG_ERROR, "MMap", "文件創(chuàng)建失敗");
}
__android_log_print(ANDROID_LOG_ERROR, "MMap", "write 111");
m_size = getpagesize();
ftruncate(m_fd, m_size);
m_ptr = static_cast<int8_t *>(mmap(0, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0));
if (m_ptr == MAP_FAILED){
__android_log_print(ANDROID_LOG_ERROR, "MMap", "映射位圖失敗");
}
std::string data("大保健 我要去");
memcpy(m_ptr, data.data(), data.size());
msync(m_ptr,m_size,MS_ASYNC);
munmap(m_ptr,m_size);
__android_log_print(ANDROID_LOG_ERROR, "MMap", "write finished");
}