专注河南网站建设,成都网站建设哪个好,公司备案证查询网站查询网站,网站建设要准备些什么文章大纲引言一、Binder线程池的启动1、ProcessState#startThreadPool函数来启动线程池2、IPCThreadState#joinThreadPool 将当前线程进入到线程池中去等待和处理IPC请求二、Service 代理对象的获取1、获取Service Manager 代理对象BpServiceManager2、调用BpServiceManager#ge…
文章大纲引言一、Binder线程池的启动1、ProcessState#startThreadPool函数来启动线程池2、IPCThreadState#joinThreadPool 将当前线程进入到线程池中去等待和处理IPC请求二、Service 代理对象的获取1、获取Service Manager 代理对象BpServiceManager2、调用BpServiceManager#getService2.1、Service Manager 处理CHECK_SERVICE_TRANSACTION2.2、Binder 驱动为Client进程创建对应的Service组件的Binder引用对象2.3、Binder库为Client进程创建Binder代理对象3、asInterface 转换引言
我们都知道Binder IPC可以支持并发访问和响应但是你知道是为什么么
一、Binder线程池的启动
Binder线程池的启动主要就是依赖以下两个函数。一个进程通过调用其内部的ProcessState对象的成员startThreadPool函数来启动线程池通过IPCThreadState对象的成员函数joinThreadPool将启动的线程加入到Binder线程池并注册成为一个Binder线程。当线程启动之后会不断与binder驱动进行通信读取本线程和本进程中待处理的事务如果接受到Binder驱动的请求则处理之。而当进程繁忙时 Binder驱动会向目标进程发送一个BR_SPAWN_LOOPER命令申请一个新的进程。 ProcessState::self()-startThreadPool();IPCThreadState::self()-joinThreadPool();当Binder驱动接到Server发来的IPC请求时就会回复一个BR_SPAWN_LOOPER通知创建Binder线程用于处理这个请求当threadLoop函数返回false时则会被回收相应的对象。
1、ProcessState#startThreadPool函数来启动线程池 ProcessState在同一进程内是唯一的主要用于初始化Binder设备而IPCThreadState 用于与Binder驱动通信。 通常Service组件注册完毕之后对应的进程就会自动开启一个Binder线程池来处理Client进程发送过来的IPC请求。通常进程是通过调用其内部的ProcessState对象的startThreadPool函数来启动的。 \frameworks\native\libs\binder\ProcessState.cpp void ProcessState::startThreadPool()
{AutoMutex _l(mLock);if (!mThreadPoolStarted) {//防止重复启动线程池mThreadPoolStarted true;spawnPooledThread(true);}
}从上面我们可以得知一个进程中有且只有一个Binder线程池且只启动一次接着是真正通过ProcessState#spawnPooledThread来启动线程池的。 isMain为true表示是线程是进程主动创建并加入到它Binder线程池的对应的是BC_ENTER_LOOPER协议而Binder驱动请求进程创建的线程则isMain为false对应的是BC_REGISTER_LOOPER。 void ProcessState::spawnPooledThread(bool isMain)
{if (mThreadPoolStarted) {String8 name makeBinderThreadName();//Binder线程的名称spThread t new PoolThread(isMain);t-run(name.string());}
}String8 ProcessState::makeBinderThreadName() {int32_t s android_atomic_add(1, mThreadPoolSeq);pid_t pid getpid();String8 name;name.appendFormat(Binder:%d_%X, pid, s);return name;
} 主要就是创建PoolThread对象并调用其run函数启动一个新线程而PoolThread 继承Thread并重写了线程入口函数threadLoop
class PoolThread : public Thread
{
public:PoolThread(bool isMain): mIsMain(isMain){}protected:virtual bool threadLoop(){IPCThreadState::self()-joinThreadPool(mIsMain);return false;}const bool mIsMain;
};接着IPCThreadState#joinThreadPool 将当前线程进入到线程池中去等待和处理IPC请求。 Binder驱动接到IPC 请求的时候就会发一个 BR_SPAWN_LOOPE 然后Server 端就创建一个线程来处理但是一个fd 最多绑定15线程。 2、IPCThreadState#joinThreadPool 将当前线程进入到线程池中去等待和处理IPC请求
IPCThreadState#joinThreadPool 函数将当前线程注册到Binder驱动中成为一个Binder线程以便Binder驱动可以分发IPC请求给它处理在进入Binder驱动前talkWithDriver会自动检测IPCThreadState内部的协议输出缓冲区是否还有协议有则发给BInder驱动处理处理完成返回后Binder驱动回复返回协议保存至IPCThreadState内部的协议输入缓冲区中函数getAndExecuteCommand将会去处理。
void IPCThreadState::joinThreadPool(bool isMain)
{//将协议写入到IPCThreadState的输出缓冲区mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);set_sched_policy(mMyThreadId, SP_FOREGROUND);status_t result;do {processPendingDerefs();// now get the next command to be processed, waiting if necessaryresult getAndExecuteCommand();if (result NO_ERROR result ! TIMED_OUT result ! -ECONNREFUSED result ! -EBADF) {abort();}if(result TIMED_OUT !isMain) {break;}} while (result ! -ECONNREFUSED result ! -EBADF);LOG_THREADPOOL(**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err%p\n,(void*)pthread_self(), getpid(), (void*)result);mOut.writeInt32(BC_EXIT_LOOPER);talkWithDriver(false);
}
若talkWithDriver函数长期没有等到IPC请求或者getAndExecuteCommand函数执行超时且isMain为false时就跳出循环并向Binder驱动发送BC_EXIT_LOOPER协议告知Binder驱动前面创建的这个线程它要退出Binder线程池了。
二、Service 代理对象的获取
Server进程和Client进程的通信要依靠Binder驱动来进行。 Service组件在启动时会将自己注册到ServiceManager组件中以便Client组件通过ServiceManager来找到这个Service组件。 在Binder IPC机制中Client要与Server通信Client组件必须要先获取Service组件的代理对象使用的时候很方便直接通过Service Manager代理对象的getService接口就可以获取前面分析了ServiceManager 自身代理对象的获取普通Service 组件代理对象获取的流程也大同小异虽然说要与Binder驱动沟通但是对于我们开发者来说这一部分的工作被Service Manager 帮忙承担了。
spIServiceManager sm defaultServiceManager();
spIBinder binder sm-getService(String16(DETECT_SERVICE_NAME));
spIDetectService bpDetectService interface_cast IDetectService(binder);总结起来在Client进程本例中名称为DetectClient获取一个普通Service 代理对象三部曲为
1、获取Service Manager 代理对象BpServiceManager
主要就是通过IServiceManager#defaultServiceManager函数获取预知详情参见前文。
2、调用BpServiceManager#getService
BpServiceManager继承自BpInterface而BpInterface是一个继承BpRefsBase的模板类在getService函数中最多会尝试100次来尝试获取名称对应的Service组件代理对象
class BpServiceManager : public BpInterfaceIServiceManager
{
public:BpServiceManager(const spIBinder impl): BpInterfaceIServiceManager(impl){}virtual spIBinder getService(const String16 name) const{unsigned n;for (n 0; n 100; n){if (n 0) {ALOGI(Waiting for service %s..., String8(name).string());usleep(50000);}spIBinder svc checkService(name);if (svc ! NULL) return svc;}return NULL;}...
};在checkService函数来真正去尝试获取Service组件代理对象对比前文addService的核心流程大同小异通过Service Manager代理对象请求Service Manager进程执行ADD_SERVICE_TRANSACTION把协议换为CHECK_SERVICE_TRANSACTION协议即可。 virtual spIBinder checkService( const String16 name) const{Parcel data, reply;//执行writeInterfaceToken函数拼装Binder协议头data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());data.writeString16(name);//remote()即0号引用remote()-transact(CHECK_SERVICE_TRANSACTION, data, reply);return reply.readStrongBinder();}换言之getService 的实现就一个标准的Binder IPC 五部曲
步骤说明1DetectClient将DetectService代理对象对应的名称封装为Parcel对象并传递到Binder驱动。2DetectClient向Binder驱动发送BC_TRANSACTION_COMPLETE协议Binder驱动根据协议内容找到目标Service Manager进程后回复一个BR_TRANSACTION_COMPLETE告知DetectClient其通信请求已被接受Client接到BR_TRANSACTION_COMPLETE并处理后会再次进入到Binder驱动程序中等待Server Manager进程的返回它想要的代理对象的句柄。3Binder驱动在给DetectClient回复一个BR_TRANSACTION_COMPLETE的同时向Service Manager进程发送一个BR_TRANSACTION返回协议请求目标Server Manager 进程执行CHECK_SERVICE_TRANSACTION指令。4Service Manager进程接收BR_TRANSACTION并处理CHECK_SERVICE_TRANSACTION后给驱动回复一个BC_REPLY协议包含了DetectClient申请Service组件的信息驱动根据协议内容为DetectClient进程创建一个对应的Binder引用对象给Service Manager进程发送一个BR_TRANSACTION_COMPLETE返回协议告知Service Manager它返回的目标Service 组件信息已经收到了已接到返回的相应结果Service Manager接到并处理了BR_TRANSACTION_COMPLETE协议后一次IPC流程就结束了接着会重新进入到驱动程序中等待下一次IPC请求。5Binder驱动在给Service Manager进程发送BR_TRANSACTION_COMPLETE的同时也会向DetectClient进程发送一个BR_REPLY返回协议内容包含了前面所创建的Binder引用对象的举止值DetectClient进程就可以拿着这个句柄来创建一个目标Binder代理对象同时也代表Service Manager进程已经处理完成IPC请求了并将结果返回给Client
通过这样子就可以拿到了Service 代理对象简而言之Client进程通过Service Manager进程拿到目标Service代理对象的引用对象的句柄值再根据这个句柄值创建对应的Service 代理对象。
2.1、Service Manager 处理CHECK_SERVICE_TRANSACTION
前面说过Service Manager是在svcmgr_handle函数中统一处理Client进程的IPC请求。 \frameworks\native\cmds\servicemanager\service_manager.c int svcmgr_handler(struct binder_state *bs,struct binder_transaction_data *txn,struct binder_io *msg,struct binder_io *reply)
{struct svcinfo *si;uint16_t *s;size_t len;uint32_t handle;uint32_t strict_policy;int allow_isolated;...switch(txn-code) {case SVC_MGR_GET_SERVICE:case SVC_MGR_CHECK_SERVICE://从binder_io结构体中的msg数据缓冲区得到代理对象的名称s bio_get_string16(msg, len);if (s NULL) {return -1;}//获取目标Binder引用对象的句柄handle do_find_service(s, len, txn-sender_euid, txn-sender_pid);if (!handle)break;//传入目标引用对象的句柄到Binder驱动,并封装为一个对应的binder_object结构体并下入reply中Binder驱动拿到的返回值就是replybio_put_ref(reply, handle);return 0;case SVC_MGR_ADD_SERVICE:...break;case SVC_MGR_LIST_SERVICES: {...}bio_put_uint32(reply, 0);return 0;
}从binder_io结构体中的msg数据缓冲区还原出代理对象的名称后通过do_find_service函数从已注册的Service组件列表svclist中查找与之对应的一个svcinfo结构体并返回Service 组件的句柄。 在Service Manager中每一个被注册了的Service组件对应一个svcinfo 结构并保存在一个全局队列svclist中其中svcinfo的成员next指向下一个svcinfo结构体、prt是一个Service组件Binder引用对象的句柄值、name是Service组件名称death指向一个用于描述死亡接收通知的结构体binder_death。 uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{// 查找与字符串s对应一个svcinfo结构体struct svcinfo *si find_svc(s, len);...if (!svc_can_find(s, len, spid, uid)) {return 0;}return si-handle;
}2.2、Binder 驱动为Client进程创建对应的Service组件的Binder引用对象
找到Service组件结构体后就得到了其他Binder引用对象的句柄返回到svcmgr_handler函数中Service Manager接着通过bio_put_ref函数把句柄传给Binder驱动Binder驱动就根据它找到对应的Binder引用对象进而找到该引用对象所指向引用的Binder实体对象最后Binder驱动就在请求该Service组件的代理对象时创建另一个Binder引用对象了。 \frameworks\native\cmds\servicemanager\binder.c void bio_put_ref(struct binder_io *bio, uint32_t handle)
{struct flat_binder_object *obj;if (handle)//非0位trueobj bio_alloc_obj(bio);elseobj bio_alloc(bio, sizeof(*obj));if (!obj)return;obj-flags 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;obj-type BINDER_TYPE_HANDLE;obj-handle handle;obj-cookie 0;
}bio_alloc函数在binder_io结构体的数据缓冲区分配一个未初始化的binder_object结构体并赋值给obj保存了位置后返回到bio_put_ref函数继续对创建的结构体进行初始化后
static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio)
{struct flat_binder_object *obj;obj bio_alloc(bio, sizeof(*obj));//在binder_io结构体的数据缓冲区分配一个未初始化的binder_object结构体//在binder_io的bio偏移数组中分配一个元素来保存binder_object结构体在数据缓冲区的位置方便Binder驱动获知Service Manager给它返回的IPC结果中包含了一个Binder对象if (obj bio-offs_avail) {bio-offs_avail--;*bio-offs ((char*) obj) - ((char*) bio-data0);return obj;}bio-flags | BIO_F_OVERFLOW;return NULL;
}再回到svcmgr_handler函数中将Binder驱动IPC结果保存到binder_io类型结构体reply中了接着回到binder_parse中最后调用binder_send_reply函数将reply的内容返回给Binder驱动即向Binder驱动发送BC_REPLY协议。 Binder驱动是在binder_transaction函数中处理Service Manager 发来的协议 Service Manager进程返回给Binder驱动的IPC结果中包含了BINDER_TYPE_WEAK_HANDLE类型的binder_object结构体即flat_binder_object 结构体Binder驱动就对这个结构体进行解包并从其中找到Binder引用对象ref即指向的是运行在Server进程中的DetectService组件然后查找是否存在对应的Binder引用对象存在则直接返回给调用者不存在则为Client进程创建一个新的Binder引用对象再返回再经过Binder驱动一系列的处理之后
static void binder_transaction(struct binder_proc *proc,struct binder_thread *thread,struct binder_transaction_data *tr, int reply,binder_size_t extra_buffers_size)
{int ret;struct binder_transaction *t;struct binder_work *tcomplete;struct binder_proc *target_proc NULL;struct binder_thread *target_thread NULL;struct binder_node *target_node NULL;struct binder_transaction *in_reply_to NULL;struct binder_buffer_object *last_fixup_obj NULL;struct binder_context *context proc-context;.../* TODO: reuse incoming transaction for reply */t kzalloc(sizeof(*t), GFP_KERNEL);binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);...for (; offp off_end; offp) {struct binder_object_header *hdr;switch (hdr-type) {case BINDER_TYPE_BINDER:case BINDER_TYPE_WEAK_BINDER: {...}break;case BINDER_TYPE_HANDLE:case BINDER_TYPE_WEAK_HANDLE: {struct flat_binder_object *fp;...} break;}
}
2.3、Binder库为Client进程创建Binder代理对象
最终目标线程target_thread返回到用户空间之后再次进去到IPCThreadState#waitForResponse函数处理从Binder驱动读取回来的BR_REPLY协议将Binder 驱动IPC结果封装为Parcel的对象reply中再次返回到Service Manager代理对象的成员函数checkService中最后通过Parcel的readStrongBinder函数得到Binder的代理对象。
status_t Parcel::readStrongBinder(spIBinder* val) const
{return unflatten_binder(ProcessState::self(), *this, val);
}status_t unflatten_binder(const spProcessState proc,const Parcel in, spIBinder* out)
{const flat_binder_object* flat in.readObject(false);if (flat) {switch (flat-type) {case BINDER_TYPE_BINDER:*out reinterpret_castIBinder*(flat-cookie);return finish_unflatten_binder(NULL, *flat, in);case BINDER_TYPE_HANDLE:*out proc-getStrongProxyForHandle(flat-handle);return finish_unflatten_binder(static_castBpBinder*(out-get()), *flat, in);}}return BAD_TYPE;
}本质上还是通过ProcessState#getStrongProxyForHandle函数从其内部的Binder代理对象列表中查找是否存在一个与flat_binder_object结构体句柄值handle对应的Binder代理对象存在则返回不存在则根据handle创建相应的BInder代理对象再返回而且flat_binder_object的handle同时是指向了Service组件引用对象因此ProcessState#getStrongProxyForHandle函数返回的Binder代理对象也指向了Service组件的引用对象。
3、asInterface “转换”
当BpServiceManager#checkService 函数执行完成之后就将一个Binder代理对象的IBinder接口返回到DetectClient进程的入口函数main接着最差最后一步——转换为具体的Binder代理对象。 interface_cast并不是指针转换而是利用BpBinder指针构建出一个新的BpServiceManager对象。宏函数实现的。 android::spIDetectService IDetectService::asInterface( const android::spandroid::IBinder obj) { android::spIDetectService intr; if (obj ! NULL) { intr static_castIDetectService*( obj-queryLocalInterface(IDetectService::descriptor).get()); if (intr NULL) { intr new BpIDetectService(obj); } } return intr; }