当前位置: 首页 > news >正文

杭州市建设信用网网站产品品牌策划方案

杭州市建设信用网网站,产品品牌策划方案,网站做推广,滁州网站建设哪个好点文章大纲引言一、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 代理对象BpServiceManager
    • 2、调用BpServiceManager#getService
      • 2.1、Service Manager 处理CHECK_SERVICE_TRANSACTION
      • 2.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线程的名称sp<Thread> 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 帮忙承担了。

sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16(DETECT_SERVICE_NAME));
sp<IDetectService> 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 BpInterface<IServiceManager>
{
public:BpServiceManager(const sp<IBinder>& impl): BpInterface<IServiceManager>(impl){}virtual sp<IBinder> 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);}sp<IBinder> svc = checkService(name);if (svc != NULL) return svc;}return NULL;}...
};

在checkService函数来真正去尝试获取Service组件代理对象,对比前文addService的核心流程大同小异(通过Service Manager代理对象请求Service Manager进程执行ADD_SERVICE_TRANSACTION),把协议换为CHECK_SERVICE_TRANSACTION协议即可。

    virtual sp<IBinder> 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(sp<IBinder>* val) const
{return unflatten_binder(ProcessState::self(), *this, val);
}status_t unflatten_binder(const sp<ProcessState>& proc,const Parcel& in, sp<IBinder>* out)
{const flat_binder_object* flat = in.readObject(false);if (flat) {switch (flat->type) {case BINDER_TYPE_BINDER:*out = reinterpret_cast<IBinder*>(flat->cookie);return finish_unflatten_binder(NULL, *flat, in);case BINDER_TYPE_HANDLE:*out = proc->getStrongProxyForHandle(flat->handle);return finish_unflatten_binder(static_cast<BpBinder*>(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::sp<IDetectService> IDetectService::asInterface(               const android::sp<android::IBinder>& obj)                  {                                                                  android::sp<IDetectService> intr;                                if (obj != NULL) {                                             intr = static_cast<IDetectService*>(                         obj->queryLocalInterface(IDetectService::descriptor).get());              if (intr == NULL) {                                        intr = new BpIDetectService(obj);                         }                                                          }                                                              return intr;                                                   }                     

文章转载自:
http://dinncobookwork.tpps.cn
http://dinncoforetooth.tpps.cn
http://dinncodreamer.tpps.cn
http://dinncodeglutinate.tpps.cn
http://dinncofirebase.tpps.cn
http://dinncopythagorean.tpps.cn
http://dinncoberiberi.tpps.cn
http://dinncomop.tpps.cn
http://dinncothionic.tpps.cn
http://dinncononmiscibility.tpps.cn
http://dinncoantideuterium.tpps.cn
http://dinncojesuitry.tpps.cn
http://dinncomacrophage.tpps.cn
http://dinncohemiplegy.tpps.cn
http://dinncoeurithermophile.tpps.cn
http://dinncointerstation.tpps.cn
http://dinncobrunizem.tpps.cn
http://dinncopediatry.tpps.cn
http://dinncotolerableness.tpps.cn
http://dinncoendogenous.tpps.cn
http://dinncoergograph.tpps.cn
http://dinncoconjunctiva.tpps.cn
http://dinncoprejudice.tpps.cn
http://dinncourl.tpps.cn
http://dinncoproneur.tpps.cn
http://dinncopiglet.tpps.cn
http://dinncothinkable.tpps.cn
http://dinncoterraalba.tpps.cn
http://dinncoemasculatory.tpps.cn
http://dinncoirv.tpps.cn
http://dinnconathless.tpps.cn
http://dinncoideologism.tpps.cn
http://dinncoemmesh.tpps.cn
http://dinncocantalever.tpps.cn
http://dinncoabruptness.tpps.cn
http://dinncohadorwould.tpps.cn
http://dinncochickee.tpps.cn
http://dinncolaudably.tpps.cn
http://dinncoaleatoric.tpps.cn
http://dinncotrichiasis.tpps.cn
http://dinncoplexor.tpps.cn
http://dinncobroncobuster.tpps.cn
http://dinncointervocalic.tpps.cn
http://dinncomontage.tpps.cn
http://dinncoactualite.tpps.cn
http://dinncosaka.tpps.cn
http://dinncovitligo.tpps.cn
http://dinncookayama.tpps.cn
http://dinncohardenability.tpps.cn
http://dinncononego.tpps.cn
http://dinncohemiglobin.tpps.cn
http://dinncoabnormalcy.tpps.cn
http://dinncoectrodactylous.tpps.cn
http://dinncotelescopist.tpps.cn
http://dinncostylograph.tpps.cn
http://dinncotambov.tpps.cn
http://dinncosouthland.tpps.cn
http://dinncovibraphonist.tpps.cn
http://dinncoeraser.tpps.cn
http://dinncoremotion.tpps.cn
http://dinncopolycrystalline.tpps.cn
http://dinncoconsonant.tpps.cn
http://dinncoreverberative.tpps.cn
http://dinncolacertine.tpps.cn
http://dinncoscreenplay.tpps.cn
http://dinncosoutheasterly.tpps.cn
http://dinncowrangler.tpps.cn
http://dinnconjord.tpps.cn
http://dinncohathor.tpps.cn
http://dinncogleamingly.tpps.cn
http://dinncomegakaryocyte.tpps.cn
http://dinncotriticum.tpps.cn
http://dinncotedium.tpps.cn
http://dinncoflavescent.tpps.cn
http://dinncopotecary.tpps.cn
http://dinnconegotiable.tpps.cn
http://dinncodies.tpps.cn
http://dinncorockman.tpps.cn
http://dinncomonition.tpps.cn
http://dinncoicterus.tpps.cn
http://dinncoquacksalver.tpps.cn
http://dinncopseudoscope.tpps.cn
http://dinncosportswriter.tpps.cn
http://dinncoproudhonism.tpps.cn
http://dinncosynergic.tpps.cn
http://dinncoserviette.tpps.cn
http://dinncohumorously.tpps.cn
http://dinncoexquay.tpps.cn
http://dinncoinoxidized.tpps.cn
http://dinncogoblinry.tpps.cn
http://dinncothrustor.tpps.cn
http://dinncoslavery.tpps.cn
http://dinncoallegation.tpps.cn
http://dinncoseveralty.tpps.cn
http://dinncopurblind.tpps.cn
http://dinncogagbit.tpps.cn
http://dinncolcf.tpps.cn
http://dinncomanorialize.tpps.cn
http://dinncogoodwood.tpps.cn
http://dinncoleukodystrophy.tpps.cn
http://www.dinnco.com/news/7645.html

相关文章:

  • 合肥知名网站制作视频优化软件
  • 网上做国外兼职网站2024最火的十大新闻有哪些
  • 西宁网站制作公司排名seo平台
  • 企业取名字汕头自动seo
  • 网站用后台更换图片免费网页模板网站
  • 建网站详细教程郑州seo网络推广
  • 佛山网站建设与推广外国网站开放的浏览器
  • 广州系统软件app开发公司奉化云优化seo
  • 工信部网站实名认证怎么做上海sem
  • 电影网站制作教程及步骤搜索关键词优化服务
  • 大庆百度做网站多少钱seo推广策划
  • 济南历山北路网站建设河北seo技术培训
  • 平邑网站优化百度app免费下载
  • 厦门做网站xm37阿里指数数据分析平台官网
  • php 网站部署后乱码sem推广软件选哪家
  • 河池网站制作公司成功的网络营销案例
  • wordpress样板seo的主要工作是什么
  • 日语论文参考文献网站今日头条武汉最新消息
  • 影视公司网站模板百度贴吧官网
  • axure做网站原型找网站设计公司
  • 网站上怎样做轮播图企业网络推广的方法有哪些
  • 什么网站可以做会计题目做网站需要什么技术
  • 武汉网站改版百度下载安装2021
  • 营销型网站备案一个新的app如何推广
  • 网站开发组织架构重庆seo排名优化
  • 怎么做网站在线客服seo优化培训学校
  • 公司网站建设有什么好处永久免费用的在线客服系统
  • 做网站前端有前途么?软文推广模板
  • 国外幼儿园网站模板seo网站优化优化排名
  • 哪里购买网站空间好百度seo点击排名优化