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 | 转载请注明作者出处
原文地址:https://www.cnblogs.com/houser0323/p/14562194.html