zoukankan      html  css  js  c++  java
  • android10Binder(四)一次binder请求的来回:bootanimation-->surfaceflinger

    一次binder请求的来回:bootanimation-->surfaceflinger

    一、boot->run()

    上篇文章我们在waitForSurfaceFlinger里getService操作,拿到了sf的代理对象BpBinder,现在进行下一步动作,利用sf进行开机动画的显示。

    frameworks/base/cmds/bootanimation

     36 int main()
     47         // create the boot animation object (may take up to 200ms for 2MB zip)
     48         sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
     50         waitForSurfaceFlinger();
     52         boot->run("BootAnimation", PRIORITY_DISPLAY);
    

    frameworks/base/cmds/bootanimation/BootAnimation.h

    40 class BootAnimation : public Thread, public IBinder::DeathRecipient
    

    BootAnimation类是一个线程类,继承了Thread,run的调用发生了什么可以参考:关于C++层Thread的threadLoop的问题。简单来说就是run()->readyToRun()->threadLoop()。

    另外48行还有一个值得关注的就是智能指针sp的初始化,onFirstRef,可以参考老罗的博客Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

    在我们bootanimation这里,这个sp初始化的调用流程是onFirstRef()->linkToComposerDeath()。本文我们不探讨binder的死亡通知机制。

    现在开始看readyToRun

    frameworks/base/cmds/bootanimation/BootAnimation.cpp

     274 status_t BootAnimation::readyToRun() {
     275     mAssets.addDefaultAssets();
     276
     277     mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
     281     DisplayInfo dinfo;
     282     status_t status = SurfaceComposerClient::getDisplayInfo(mDisplayToken, &dinfo);
     285
     286     // create the native surface
     287     sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
     288             dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
     289
     290     SurfaceComposerClient::Transaction t;
     291     t.setLayer(control, 0x40000000)
     292         .apply();
     293
     294     sp<Surface> s = control->getSurface();
    

    看277行,我们只关注这一个ipc调用。

    1.1 SurfaceComposerClient::getInternalDisplayToken()

    frameworks/native/libs/gui/SurfaceComposerClient.cpp

     536 sp<IBinder> SurfaceComposerClient::getInternalDisplayToken() {
     537     return ComposerService::getComposerService()->getInternalDisplayToken();
     538 }
    

    537行的getComposerService方法返回的是谁?

    frameworks/native/libs/gui/SurfaceComposerClient.cpp

      90 /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
      91     ComposerService& instance = ComposerService::getInstance();
      98     return instance.mComposerService;
      99 }
    

    ComposerService类是单例模式,继承了Singleton类,所以getInstance方法会调用其构造函数,返回一个ComposerService实例。

    frameworks/native/libs/gui/include/private/gui/ComposerService.h

     41 class ComposerService : public Singleton<ComposerService> {
     43     sp<ISurfaceComposer> mComposerService;
     47     ComposerService();
     48     void connectLocked();
    

    frameworks/native/libs/gui/SurfaceComposerClient.cpp

    61 ComposerService::ComposerService()
    62 : Singleton<ComposerService>() {
    64     connectLocked();
    65 }
    67 void ComposerService::connectLocked() {
    68     const String16 name("SurfaceFlinger");
    69     while (getService(name, &mComposerService) != NO_ERROR) {
    70         usleep(250000);
    71     }
    88 }
    

    我们看一下构造函数的实现,即connectLocked方法。69行的getService方法我们分析过了,是linbinder库里通过binder跨进程调用sm,然后返回的"SurfaceFlinger"的代理对象new BpBinder(handle)经过asinterface的转换变成实例:new BpSurfaceComposer(new BpBinder(handle))。这个转换过程我们在SM分析过,忘记的同学跳转回去,再回顾一下。

    frameworks/native/libs/binder/include/binder/IInterface.h

     97     ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              
     98             const ::android::sp<::android::IBinder>& obj)               
     99     {                                                                   
    100         ::android::sp<I##INTERFACE> intr;                               
    101         if (obj != nullptr) {                                           
    102             intr = static_cast<I##INTERFACE*>(                          
    103                 obj->queryLocalInterface(                               
    104                         I##INTERFACE::descriptor).get());               
    105             if (intr == nullptr) {                                      
    106                 intr = new Bp##INTERFACE(obj);                          
    107             }                                                           
    108         }                                                               
    109         return intr;                                                    
    110     }                                                 
    

    mComposerService装的是什么现在清楚了,是一个BpSurfaceComposer的对象。

    继续追踪

    frameworks/native/libs/gui/include/gui/ISurfaceComposer.h

    129     sp<IBinder> getInternalDisplayToken() const {
    130         const auto displayId = getInternalDisplayId();
    131         return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
    132     }
    //----------------------------------------------------------------------------------------
    118     std::optional<PhysicalDisplayId> getInternalDisplayId() const {
    119         const auto displayIds = getPhysicalDisplayIds();
    120         return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front());
    121     }
    //----------------------------------------------------------------------------------------
    115     virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
    

    130-->118-->119。getPhysicalDisplayIds的实现在ISurfaceComposer.cpp里,是binder跨进程调用

    frameworks/native/libs/gui/ISurfaceComposer.cpp

     321     virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const {
     322         Parcel data, reply;
     323         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
     324         if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
     325             NO_ERROR) {
     326             std::vector<PhysicalDisplayId> displayIds;
     327             if (reply.readUint64Vector(&displayIds) == NO_ERROR) {
     328                 return displayIds;
     329             }
     330         }
     332         return {};
     333     }
    

    眼熟吗?有没有发现规律或者说叫套路。是的,作为一个binder的服务端,想给别的进程提供服务那就要实现一个继承IInterface接口的工具类,作为一个库吧让客户端来用,目前这些都是在客户端进程里的。

     62 /*
     63  * This class defines the Binder IPC interface for accessing various
     64  * SurfaceFlinger features.
     65  */
     66 class ISurfaceComposer: public IInterface {
     67 public:
     68     DECLARE_META_INTERFACE(SurfaceComposer)
    115     virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
    下面有众多接口的定义,标志着surfaceflinger服务端的能力
    ......
    

    思考一下这样设计的考虑是什么?

    可以这样理解,作为服务端,提供服务的一方,是服务提供者,而客户端呢?自然是顾客。我们要提供尽可能方便的用户接口。所以我们把杂七杂八的事情都做好,封装在so里库里,用户只需要传我们的名字,传数据参数即可。

    你能想象每个客户都写一大堆同binder驱动交互的重复代码么?这显然是糟糕透顶的编程工作。

    所以封装是个好东西,重复的东西让他变成include或import即可使用的接口。

    现在回到ISurfaceComposer.cpp#getPhysicalDisplayIds方法324行。remote()->transact是不是又是很眼熟,但是,有点想不起来这俩东东的内涵了?我们在SM篇里分析过,可以回顾下。这里为了流畅,直接再梳理一遍。

    找remote()的流程就是回溯父类,这也是有继承的语言,代码追踪特点。我们看下BpSurfaceComposer类的继承关系。

    frameworks/native/libs/gui/ISurfaceComposer.cpp
    49 class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
    //----------------------------------------------------------------------------------------
    frameworks/native/libs/binder/include/binder/IInterface.h
    64 class BpInterface : public INTERFACE, public BpRefBase
    //----------------------------------------------------------------------------------------
    frameworks/native/libs/binder/include/binder/Binder.h
     90 class BpRefBase : public virtual RefBase{
     92 protected:
     99     inline  IBinder*        remote()                { return mRemote; }
    100     inline  IBinder*        remote() const          { return mRemote; }
    102 private:
    106     IBinder* const          mRemote;
    109 };
    //----------------------------------------------------------------------------------------
    frameworks/native/libs/binder/Binder.cpp
    315 BpRefBase::BpRefBase(const sp<IBinder>& o)
    316     : mRemote(o.get()), mRefs(nullptr), mState(0){
    318     extendObjectLifetime(OBJECT_LIFETIME_WEAK);
    320     if (mRemote) {
    321         mRemote->incStrong(this);           // Removed on first IncStrong().
    322         mRefs = mRemote->createWeak(this);  // Held for our entire lifetime.
    

    看316行,mRemote就是我们传进来的new BpBinder(handle)对象,这个对象怎么得来的还记得吗?是通过SM#getService得来的。我们再回顾下getService的流程。

    IServiceManager.h
    getService(,)
    //----------------------------------------------------------------------------------------
    IServiceManager.cpp
    getService(){
       sp<IBinder> svc = checkService(name); 
        if (svc != nullptr) return svc;
    }
    

    简单滴说就是我们最初通过sm拿到的是BpBinder(handle)对象,经过asInterface的转换封装,又变成一个BpSurfaceComposer对象。

    现在remote()的问题又回顾了一遍,是不是印象更深刻了?现在跳到他的transact方法,开启跨进程之旅。

    1.3 bootanimation-->驱动-->surfaceflinger

    重复的流程就不再赘述,给出调用链。

    • bootanimation进程向binder驱动发消息

    这些都是libbinder库的方法,就不贴路径了

    BpBinder::transact --> IPCThreadState::transact --> IPCThreadState::waitForResponse --> IPCThreadState::talkWithDriver --> ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)

    • 陷入内核。

      路径大家也很熟了就俩文件驱动里binder.c 和 binder_alloc.c

    binder_ioctl --> case BINDER_WRITE_READ: binder_ioctl_write_read --> binder_thread_write --> case BC_TRANSACTION: binder_transaction -->

    binder_alloc_new_buf、binder_alloc_copy_user_to_buffer、wake_up_interruptible_sync

    现在驱动里的处理也结束了,bootanimation的数据被copy到了内核空间分配的物理内存,这个物理内存谁用呢?自然是发起端的对端,我们的sf。sf通过一个地址偏移offset可以直接使用这个物理内存。

    • surfaceflinger收到数据的处理

    现在让我们转换视角,从bootanimation进程,跳转到surfaceflinger进程。要时刻有这个意识:我是谁(现在是哪个进程线程);我在哪(用户空间?内核空间?)

    服务端的唤醒流程我们前文也分析过,现在只分析没走过的流程。

    所有的使用binder机制的线程,空闲的时候都会卡在waitForResponse 方法里,也就是卡在ioctl-->>binder_ioctl-->binder_ioctl_write_read,卡在休眠里wait_event_interruptible

    现在唤醒sf的binder线程,开始处理数据。现在是sf进程的IPCThreadState.cpp#waitForResponse方法

    frameworks/native/libs/binder/IPCThreadState.cpp

     831 status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
     832 {
     836     while (1) {
     837         if ((err=talkWithDriver()) < NO_ERROR) break;
     849         switch (cmd) {
     905         default:
     906             err = executeCommand(cmd);
    

    返回的cmd是啥,你猜?是BR_TRANSACTION。BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS。

    frameworks/native/libs/binder/IPCThreadState.cpp

    1068 status_t IPCThreadState::executeCommand(int32_t cmd)
    1069 {
    1074     switch ((uint32_t)cmd) {
    1148     case BR_TRANSACTION:
    1149         {
    1150             binder_transaction_data_secctx tr_secctx;
    1151             binder_transaction_data& tr = tr_secctx.transaction_data;
    1208             if (tr.target.ptr) {
    1211                 if (reinterpret_cast<RefBase::weakref_type*>(
    1212                         tr.target.ptr)->attemptIncStrong(this)) {
    1213                     error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
    1214                             &reply, tr.flags);
    1215                     reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
    1216                 }
    1220             } 
    1224             mIPCThreadStateBase->popCurrentState();
    1228             if ((tr.flags & TF_ONE_WAY) == 0) {
    1229                 LOG_ONEWAY("Sending reply to %d!", mCallingPid);
    1230                 if (error < NO_ERROR) reply.setError(error);
    1231                 sendReply(reply, 0);
    

    废话不多说,看1213行,tr.cookie是一个指针,要么是BpBinder要么是BBinder。这里是client传给我们的,所以这里就是sf的BBinder对象。与之相对的,如果我们sendReply那么这里就会走到BpBinder.cpp里了。

    frameworks/native/libs/binder/Binder.cpp

    123 status_t BBinder::transact(
    124     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
    126     data.setDataPosition(0);
    129     switch (code) {
    133         default:
    134             err = onTransact(code, data, reply, flags);
    135             break;
    136     }
    142     return err;
    143 }
    

    onTranact方法的实现在哪?

    frameworks/native/libs/gui/ISurfaceComposer.cpp

     989 status_t BnSurfaceComposer::onTransact(
     990     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
     991 {
     992     switch(code) {
    1497         case GET_PHYSICAL_DISPLAY_IDS: {
    1498             CHECK_INTERFACE(ISurfaceComposer, data, reply);
    1499             return reply->writeUint64Vector(getPhysicalDisplayIds());
    1500         }
    

    看到没,兜兜转转又回到了ISurfaceComposer.cpp文件,不过这次不在Bp类里了,而是Bn类里,这里面不再是接口,而是接口的实现。

    这个getPhysicalDisplayIds方法的实现在哪?在BnSurfaceComposer的子类

    frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

     480 std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const {
     483     const auto internalDisplayId = getInternalDisplayIdLocked();
     488     std::vector<PhysicalDisplayId> displayIds;
     489     displayIds.reserve(mPhysicalDisplayTokens.size());
     490     displayIds.push_back(internalDisplayId->value);
     491
     492     for (const auto& [id, token] : mPhysicalDisplayTokens) {
     493         if (id != *internalDisplayId) {
     494             displayIds.push_back(id.value);
     495         }
     496     }
     498     return displayIds;
     499 }
    

    至于这个displayIds内容是啥我们就不关心啦,我们只关心通信的流程。知道这一次的ipc是拿到一个vector数组就行。

    现在开始return的流程,sf作为发起者,bootanimation作为接受者。

    1.4 surfaceflinger -- send reply --> bootanimation

    现在回到IPCThreadState::executeCommand,我们的进程还是sf,现在这里就是起点,开始第二次binder ipc,将上面拿到的动态数组vector传给bootanimation。

    frameworks/native/libs/binder/IPCThreadState.cpp

     821 status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags){
     825     err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
     828     return waitForResponse(nullptr, nullptr);
     829 }
    

    又是waitForResponse,看的次数越多,越能记住他。后面的流程我们就不细说了,又是talkwithdriver啊,binder_ioctl,write_read然后cp数据到bootanimation的内核空间映射的物理内存上,这个内存同样的bootanimation在用户空间通过偏移地址可以直接操作。

    我们回去看bootanimation,他也同样的卡在哪里?卡在驱动的binder_write_read,现在唤醒后通过binder_thread_read将数据的包装拿到用户空间。

    同样的又回到了waitForResponse-->talkWithDriver。只是这次不是去执行命令了,而是BR_REPLY

    frameworks/native/libs/binder/IPCThreadState.cpp

     871         case BR_REPLY:
     872             {
     873                 binder_transaction_data tr;
     874                 err = mIn.read(&tr, sizeof(tr));
     878                 if (reply) {
     879                     if ((tr.flags & TF_STATUS_CODE) == 0) {
     880                         reply->ipcSetDataReference(
     881                             reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
     882                             tr.data_size,
     883                             reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
     884                             tr.offsets_size/sizeof(binder_size_t),
     885                             freeBuffer, this);
     886                     } else {
     903             goto finish;
     919     return err;
     920 }
    //-------------------------------------------------------------------------------
    2557 void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
    2558     const binder_size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie){
    2563     mData = const_cast<uint8_t*>(data);
    2564     mDataSize = mDataCapacity = dataSize;
    
    

    880行,bootanimation拿到sf返回的数据放到parcel对象的mData里,这样waitForResponse方法就返回了。直接回到梦开始的地方。ISurfaceComposer.cpp 的324行。

    frameworks/native/libs/gui/ISurfaceComposer.cpp

     321     virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const {
     322         Parcel data, reply;
     323         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
     324         if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) ==
     325             NO_ERROR) {
     326             std::vector<PhysicalDisplayId> displayIds;
     327             if (reply.readUint64Vector(&displayIds) == NO_ERROR) {
     328                 return displayIds;
    

    上面的ipcSetDataReference方法将返回数据放在parcel对象里,也就是324行的入参reply

    现在我们返回来后,327行将parcel数据读出来,放到动态数组中。终结。这就是一次完整的ipc发起和ipc返回流程。

    O(∩_∩)O哈哈~,差一点回不来了。写完啦回家吃饭。

    二、总结

    还是拿到handle和binder_ref的问题,如果搞不清楚handle怎么来的就没法找到对端进行通信。搞清楚了,就完全清了。就像你找什么东西,怎么找到才是重点,找到了一切好办。

    作者:秋城 | 博客:https://www.cnblogs.com/houser0323 | 转载请注明作者出处
  • 相关阅读:
    Android学习之adb异常处理
    Android学习之多触点滑动
    RN animated帧动画
    RN animated组动画
    RN animated缩放动画
    RN Animated透明度动画
    Eclipse ADT中的logcat不显示解决方法
    RadioButton使用
    PropTypes使用
    SegmentedControlIOS使用
  • 原文地址:https://www.cnblogs.com/houser0323/p/14562194.html
Copyright © 2011-2022 走看看