Binder原理解析

binder通信的特点和原理

Android系统是基于Linux的,那么关于进程间的通信同样我们也可以参考Linux,有以下几种:
管道:需要copy两次数据
共享内存:不需要拷贝数据,但是不安全
socket:需要拷贝两次数据
File:同上
Binder:拷贝一次数据,安全
Binder通信是支持一对多这样的C/S模型的,这样S端就可以对C端进行验证,安全新就有了保障。
在Linux系统中,用户进程是无法直接操作磁盘的物理内存的,必须经过内核才可以操作,Binder的机制就是将物理内存通过mmap方法映射到用户空间,这样用户空间就可以拿到实际的地址进行操作。

Binder Native的启动过程:

在service_manager.c文件中


1589755053(1).png

首先,先打开binder驱动,该驱动位于/dev/binder目录下,同时申请128k的内存空间。


1589806538(1).png

可以看到,首先是打开binder驱动,然后通过mmap函数来内存映射,这里mmap必须是page的整数倍,一般来说page为4K。mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。
参数介绍:

addr: 建立映射区的首地址,由Linux内核指定。使用时,直接传递NULL。

length: 欲创建映射区的大小。

prot: 映射区权限PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE。

flags: 标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区);

MAP_SHARED: 会将映射区所做的操作反映到物理设备(磁盘)上。

MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。

fd: 用来建立映射区的文件描述符。

offset: 映射文件的偏移(4k的整数倍)。
下面我们尝试自己通过mmap函数来在用户空间来写入文件(app需要先申请动态读写权限):

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", "文件创建失败");
}
__android_log_print(ANDROID_LOG_ERROR, "MMap", "write 111");
m_size = getpagesize();
ftruncate(m_fd, m_size);
m_ptr = static_cast(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");

}


1589846320(1).png

你可能感兴趣的:(Binder原理解析)