深入解析Binder源码

Linux鼻祖LinusTorvalds曾说过的一句话:Read The Fucking Source Code。

注:以下记录需对照着源码看

目录

一、Binder核心方法:

二、Binder通信协议:

三、Binder启动ServiceManager:

四、获取ServiceManager

五、注册服务addService

六、获取服务getService()

七、Framework层分析


一、Binder核心方法:

java 复制代码
binder_init()驱动设备的初始化
	misc_register()注册misc设备
binder_open()打开binder驱动设备
	binder_proc对象 管理IPC所需的各种信息,并拥有其他结构体的根结构体
	filp->private_data = proc;  把binder_proc对象保存到文件指针filp
binder_mmap() 用户空间的Buffer和内核空间的Buffer映射
	area=get_vm_area() 分配一个连续的内核虚拟空间,与用户虚拟空间大小一致
	binder_update_page_range() 分配物理页面,同时映射到内核空间和用户空间
		alloc_page() 分配一个page的物理内存
		ret=map_kernel_range_noflush() 物理空间映射到虚拟内核空间
		ret=vm_insert_page() 物理空间映射到虚拟用户空间
	//binder_alloc_buf() 用于分配内存
 binder_ioctl() 数据操作( ioctl(文件描述符,ioctl命令,数据类型))
	binder_get_thread() 获取binder_thread
		 //根据当前进程的pid,从binder_proc中查找相应的binder_thread
		 //如果不存在则创建binderthread,并将当前线程添加到当前的proc
	binder_ioctl_write_read() 进行binder读写操作
		copy_from_user() 把用户空间的数据ubuf拷贝到内核空间bwr
			if(bwr.write_size>0即bwr写缓存有数据) 
				ret=binder_thread_write() 执行binder写操作
				if(ret<0写失败)
					copy_to_user将bwr数据写回用户空间
			if(bwr.read_size>0读缓存中有数据)
				ret=binder_thread_read() 执行binder读操作
				if(ret<0读失败)
					copy_to_user将bwr数据写回用户空间
			if(copy_to_user()) 将内核数据bwr拷贝到用户空间ubuf

二、Binder通信协议:

java 复制代码
binder_thread_write() 处理Binder协议中的请求码。
	请求码为BC_TRANSACTION或BC_REPLY
		copy_from_user()//拷贝用户空间tr到内核
		binder_transaction()
			分配两个结构体内存
			从target_proc分配一块buffer
			向目标进程的target_list添加BINDER_WORK_TRANSACTION事务
			向当前线程的todo队列添加BINDER_WORK_TRANSACTION_COMPLETE事务
binder_thread_read() 根据不同的binder_work->type以及不同状态,生成相应的响应码。
	根据wait_for_proc_work来决定wait在当前线程还是进程的等待队列

三、Binder启动ServiceManager:

java 复制代码
1.打开bndier驱动,binder_open
2.注册成为binder服务的大管家:binder_beome_context_manager
3.启动无限循环,处理client端发来的binder
service_manager.c中的main() service_manager 的入口函数
	binder_open() 打开binder驱动,申请内存
		open() 通过系统调用陷入内核,打开Binder设备驱动
		通过系统调用,ioctl获取binder版本信息
		mmap()通过系统调用,mmap内存映射,mmap必须是page的整数倍
	成为上下文管理者
	if(selinux_enabled>0)
		if(sehandle==null)
			abort()无法获取
		if(getcon(&service_manager_context)!=0)
			abort()无法获取service_manager上下文
	binder_loop() 进入无限循环,处理client端发来的请求
		binder_write() 将BC_ENTER_LOOPER命令发送给binder驱动,让service manager进入循环
			根据传进来的参数,初始化bwr
			return ioctl() 通过ioctl将bwr数据发送给binder驱动
		ioctl()进入循环,不断地binder读写过程
			binder.get_thread() 获取binder_thread
			binder_ioctl_write_read()
				copy_from_user()把用户空间数据拷贝到bwr
				binder_thread_write() 主要是设置当前线程的looper状态为BINDER_LOOPER_STATE_ENTERED
				copy_to_user()将内核数据bwr拷贝到用户空间
		binder_parse()解析binder信息	
			bio_init()
			bio_init_from_txn()
			func(bs,txn,&msg,&reply);//svcmgr_handler()
				bio_get_string16()服务名
				do_find_service() 根据名称查找相应的服务
					find_svc() 查询相应的服务
						服务存在,返回相应服务名,否则返回null		
					检查服务是否允许孤立于进程而单独存在
					服务是否满足查询条件
				bio_put_ref() 
					if(handle) bio_alloc_obj()
						bio_alloc()
					else bio_alloc()
				bio_get_string16()服务名
				bio_get_ref()
				do_add_service()注册指定服务	
					svc_can_register()权限检查
						check_mac_perms_form_lookup()检查selinux权限是否满足
					find_svc()服务检索
					svcinfo_death()服务已注册时,释放相应的服务	
					binder_acquire()
					binder_link_to death()	
						binder_write()	
			binder_send_reply()
				binder_write() 这个
binder_become_context_manager() 通 知 binder 驱 动 使 其 成 为 守 护 进 程
	return ioctl(bs->fd,BINDER_SET_CONTEXT_MGR,0)通过ioctl,传递BINDER_SET_CONTEXT_MGR指令
		binder_ioctl_set_ctx_mgr()里面调用的这个方法
			binder_new_node()创建service实体
				kzallor给新建的binder_node分配内核空间
				rb_linko_node() 将新建的node对象添加到proc红黑树

四、获取ServiceManager

java 复制代码
defaultServiceManager()
gDefaultServiceManager的创建过程:
	1.ProcessState::self() 获取ProcessState对象(单例),一个进程一个,存在则返回,否则创建
		new ProcessState 实例化ProcessState
		初始化ProcessState
		open_driver()
			open("/dev/binder",o_RDWR);打开/dev/binder设备,建立与内核的Binder驱动的交互通道
	2.getContextObject() 获取BpBinder对象
		getStrongProxyForHandle(0) 获取handle=0的IBinder
			lookupHandleLocked(handle) 查找handle对应的资源项
				根据handle查找对应的handle_entry
				当handle大于mHandleToObject的Vector长度时
					mHandleToObject.insertAt() 则向该Vector添加(handle+1-N)个结构体,
				然后再返回handle向对应位置的handle_entry结构体指针
			new BpBinder(handle) 当handle值对应的IBinder不存在或弱引用无效,则创建BpBinder对象()
			针对handle=0特殊情况,通过PING_TRANSACTION来判断是否准备就绪
	3.interface_cast<IServiceManager>() 获取BpServiceManager对象
		INTERFACE::asInterface()
		DECLARE_META_INTERFACE(ServiceManager) 
			声明asInterface(),getInterfaceDesciptor()
		IMPLEMENT_META_INTERDACE(ServiceManager,"android.os.IServiceManager")
		BpServiceManager实例化<-BpInterface<-BpRefBase //BpRefBase的mRemote指向new BpBinder(0)

五、注册服务addService

java 复制代码
media服务注册
main_mediaserver.cpp的main() 入口函数
	sp<ProcessState> proc(ProcessState::self())获得ProcessState实例
		new ProcessState 单例,保证一个进程一个ProcessState对象
			open_driver() 打开Binder驱动
				open("/dev/binder",O_RDWR) 打开/dev/binder设备,建立与内核的Binder驱动的交互通道
				ioctl() 设置binder驱动,能支持的最大线程数
			mmap() 采用内存映射函数,给binder分配一块虚拟地址空间
			close() 没有足够空间分配,关闭驱动
	defaultServiceManager() 获取BpServiceManager对象
	注册多媒体服务
	startThreadPool() 启动Binder线程池
	joinThreadPool() 当前线程加入到线程池
服务注册MediaPlayerService::instantiate()
	addService()注册服务
		Parcelle data ,reply; Parcel数据通道
		data.writeInterfaveToken(IServiceManager::getInterfaceDescriptor()) 写入头信息
		data.writeString16(name) 
		data.writeStrongBinder(service) MediaPlayerService对象
			flatten_binder()
				localBinder()
				finish_flatten_binder()
		remote()->transact() //remote()指向BpBinder对象
	BpBinder::transact	
		IPCThreadState::self()->transact() Binder代理类调用transact(),真正工作还是交给IPCThreadSate进行transact工作
			new IPCThreadState;  初始IPCThreadState
			pthread_key_creat() 创建线程的TLS
	IPC::transact
		errorCheck() 数据检查错误
		writeTransactionData() 传输数据
		waitForResponse() 等待相应
			talkWithDriver() 
				ioctl() 通过ioctl不停读写,跟Binder Driver进行通信
			executeCommand()
Binder Driver		
binder_ioctl_write_read()
	copy_from_user() 将用户空间bwr结构体拷贝到内核空间
	binder_thread_write() 将数据放入目标进程
	binder_thread_read() 读取自己队列的数据
	copy_to_user() 将内核空间bwr结构体拷贝到用户空间
binder_thread_write()
	getUser() 拷贝用户空间的cmd命令
	copy_from_user() 拷贝用户空间的binder_transaction_data
	binder_transaction() 
		binder_get_node() //从binder_proc来根据binder指针ptr指,查询相应的binder_node
		binder_new_node() 服务所在进程 创建binder_node实体
			kzaalloc() 给新创建的binder_node分配内核空间
			rb_link_node() 将新创建的node添加到proc红黑树
		binder_get_ref_for_node() servicemanager进程binder_ref
ServiceManager:
启动ServiceManager,循环在binder_loop()过程,会调用binder_parse()
binder_parse()
	bio_init_from_txn() 从txn解析出binder_io信息
	func() 收到binder事务
	binder_send_reply() 发送reply事件
svcmgr_handler()
	do_add_service() 注册指定服务
		权限检查
		服务检索
binder_rend_reply()
	binder_write() 向Binder驱动通信

六、获取服务getService()

java 复制代码
getMediaPlayService()
	defaultServiceManager() 获取驱动Service
	getService("media.player") 获取名为"media.player"的服务
		checkService() 检索服务,存在即返回,否则sleep(1)再检索,循环5次
			data.writeInterfaceToken()写入RPC头
			data.writeString16()写入服务名
			remote()->transact() remote()为BpBinder
				IPCThreadState::self()->transact() 真正工作交给IPCThreadState来进行transact
					errorCheck() 数据错误检查
					writeTransactionData() 数据传输
					waitForResponse() 等待响应
						talkWithDriver() 
							ioctl() 通过ioctl不停的读写操作,跟Binder Driver进行通信
							binder_transaction()
							binder_thread_read()
			readStrongBinder() 功能:flat_binder_object解析并创建BpBinder对象
				unflatten_binder()
					reinterpret_cast() 当请求服务的进程和服务属于同一进程
					getStrongProxyForHandle() 请求服务的进程与服务属于不同进程
						lookupHandleLocked() 查找handle对应的资源项

	linkToDeath() 将死亡通知连接到binder

七、Framework层分析

java 复制代码
1.初始化
AndroidRuntime::startReg() //完成jni方法的注册
	register_jni_procs(gRegJNI, NELEM(gRegJNI),env) //注册jni(), gRegJNI是数组,记录所有需要注册的jni(),比如REG_JNI(register_android_os_Binder)
register_android_os_Binder()
	int_register_android_os_Binder() //注册Binder类的jni()
		gBinderOffsets //是全局静态结构体,保存了类本身及成员方法,execTransat(),mObject属性。
		gBinderMethodsOrDie //将gBinderMethods数组完成映射关系,从而为Java层访问JNI层提供通道
	int_register_android_os_BinderInternal() //注册BinderInternal类的jni()
		gBinderInternalOffsetd() //保存了BinderInternal的forceBinderIGc()
	int_register_android_os_BinderProxy() //注册BinderProxy类的jni()
		gBinderProxyOffsets //保存了BinderProxy的构造方法,sendDeayhNotice(),mObject,mySelf,mOrgue
2.注册服务(有点乱)
ServiceManager.addService()
	getIServiceManager() //先获取SMP对象,则执行注册服务操作
		getContextObject() //等价于new BinderProxy()
			getContextObject() //等价于new BpBinder(0)
			javaObjectForIBinder() //创建BinderProxy对象,并存到BinderProxy.mObject成员变量            
ServiceManagerNative.asInterface()
	new ServiceManagerProxy() //SMP初始化
ServiceManagerProxy.addService()
	writeStrongBinder()
		nativewriteStrongBinder()//此处为native调用
			android_os_Parcel_writeStrongBinder()
				reinterpret_cast() //将Java层Parcel转换为native
				ibinderForJavaObject() //创建JavaBBinderHolder对象,并把地址保存到Binder.mObject成员变量
					JavaBBinderHolder.get()
						new JavaBinder() //首次进来,创建JavaBBinder对象
	mRemote.transact()	
BinderProxy.transact
	checkParcel() //用于检测Parcel大小
	transactNative()
		 //最终交由Native层的BpBinder::transact()完成	
3.获取服务
ServiceManager.getService()
	sCache.get() //先从缓存中查看
	getIServiceManager().getService() //getIServiceManager()等价于ServiceManagerProxy(new BinderProxy())
		ServiceManagerProxy.getService()
			mRemote.transact() //mRemote为BinderProxy:
				android_os_BinderProxy_transact()
					parcelForJavaObject() //Java Parcel转为native parcel
					gBinderProxyOffsets.mObject()// 保存的是new BpBinder(0)对象
					transact() //此处便是BpBinder::transact(),经过native层
						IPCThreadState::transact()
							errorCheck() //数据错误检查
							writeTransactionData() //传输数据
							waitForResponse() //等待回应事件
								//当reply对象回收时,则会调用freeBuffer来回收内存。
								//reply来源:binder_send_reply
			reply.readStrongBinder() //从reply里面解析出获取的IBinder对象,基本是writeStrongBinder逆过程
				readStrongBinder()
					unflatten_binder()
						getStrongProxyForHandle()
							lookupHandleLocked()//查找handle对应的资源项
							new BpBinder() //当handle值所对应的IBinder不存在或弱引用无效,则创建BpBinder对象
相关推荐
朴拙数科1 小时前
mysql报错解决 `1525 - Incorrect DATETIME value: ‘0000-00-00 00:00:00‘`
android·数据库·mysql
1登峰造极2 小时前
scroll-view 实现滑动显示,确保超出正常显示,小程序app,h5兼容
android·小程序
刘争Stanley2 小时前
Android 15(V)新功能适配,雕琢移动细节之美
android·kotlin·android 15·android v
qq_214670353 小时前
android 聊天界面键盘、表情切换丝滑
android·gitee
韩家老大3 小时前
MTK Android12 隐藏顶部状态栏
android
JhonKI5 小时前
【MySQL】复合查询
android·数据库·mysql
Yawesh_best5 小时前
MySQL(9)【内置函数】
android·数据库·mysql
小小unicorn13 小时前
[MySQL基础](三)SQL--图形化界面+DML
android·sql·mysql
魑魅魍魉952715 小时前
android NumberPicker隐藏分割线或修改颜色
android