一次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怎么来的就没法找到对端进行通信。搞清楚了,就完全清了。就像你找什么东西,怎么找到才是重点,找到了一切好办。