老师问一下GBP传递的问题

来源:6-3 surface跨进程传递原理

慕村9285654

2019-06-22

我看源码里面ISurfaceComposerClient的createSurface函数里面跨进程传递的是一个GBP的sp,是一个内部GBP指针为空的出参,跟踪发现传给Parcel的是一个NULL,Parcel内部写处理为NULL的IBinder是标记为BINDER_TYPE_BINDER的flat_binder_obj,它里binder和cookie都是0,这时候该怎么理解这个本应该是代理对象却被标记成了本地对象的Binder呢?还是我流程搞错了呢?

写回答

2回答

风语

2019-06-22

您好,建议给代码贴出来,这样会清楚一点。

0
1
慕村9285654
老师谢谢,我知道哪里错了,它模板方法里专门判断了如果参数是指针就当成出参,不进行传递 // Since we assume that pointer arguments are outputs, we can use this template struct to // determine whether or not a given argument is fundamentally a pointer type and thus an output template struct IsPointerIfDecayed { private: using Decayed = typename std::decay::type; public: static constexpr bool value = std::is_pointer::value; };
2019-06-23
共1条回复

慕村9285654

提问者

2019-06-22

下面是SurfaceComposerClient的createSurfaceChecked方法,调用的是内部mClient(ISurfaceComposerClient)代理对象跨进程调用,传入了sp<IGgrapichBufferProducer>.
status_t SurfaceComposerClient::createSurfaceChecked(    
        const String8& name,    
        uint32_t w,    
        uint32_t h,    
        PixelFormat format,    
        sp<SurfaceControl>* outSurface,    
        uint32_t flags,    
        SurfaceControl* parent,    
        int32_t windowType,    
        int32_t ownerUid)    
{    
    sp<SurfaceControl> sur;    
    status_t err = mStatus;    
    if (mStatus == NO_ERROR) {    
        sp<IBinder> handle;    
        sp<IBinder> parentHandle;    
        sp<IGraphicBufferProducer> gbp;    
        if (parent != nullptr) {    
            parentHandle = parent->getHandle();    
        }    
        err = mClient->createSurface(name, w, h, format, flags, parentHandle,    
                windowType, ownerUid, &handle, &gbp);    
        ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));    
        if (err == NO_ERROR) {    
            *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */);    
        }    
    }    
    return err;    
}

这个是代理对象的createSurface具体实现,调用了公共方法callRemote模版方法

class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> {    

public:    

   explicit BpSurfaceComposerClient(const sp<IBinder>& impl)    

         : SafeBpInterface<ISurfaceComposerClient>(impl, "BpSurfaceComposerClient") {}    


   ~BpSurfaceComposerClient() override;    


   status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,    

                          uint32_t flags, const sp<IBinder>& parent, int32_t windowType,    

                          int32_t ownerUid, sp<IBinder>* handle,    

                          sp<IGraphicBufferProducer>* gbp) override {    

       return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,    

                                                                           name, width, height,    

                                                                           format, flags, parent,    

                                                                           windowType, ownerUid,    

                                                                           handle, gbp);    

   }    

}

模版方法如下,主要是调用了writeInputs这个模版方法,用std::forward历遍转发了所有的参数

template <typename Method, typename TagType, typename... Args>    

   status_t callRemote(TagType tag, Args&&... args) const {    

       static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");    


       // Verify that the arguments are compatible with the parameters    

       using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;    

       static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,    

                     "Invalid argument type");    


       // Write the input arguments to the data Parcel    

       Parcel data;    

       data.writeInterfaceToken(this->getInterfaceDescriptor());    


       status_t error = writeInputs(&data, std::forward<Args>(args)...);    

       if (CC_UNLIKELY(error != NO_ERROR)) {    

           // A message will have been logged by writeInputs    

           return error;    

       }    


       // Send the data Parcel to the remote and retrieve the reply parcel    

       Parcel reply;    

       error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply);    

       if (CC_UNLIKELY(error != NO_ERROR)) {    

           ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error);    

#if SI_DUMP_CALLSTACKS    

           CallStack callStack(mLogTag);    

#endif    

           return error;    

       }    

下面是具体的writeInputs模版方法,主要是递归调用达到历遍所有参数的目的.

template <typename T, typename... Remaining>    

   status_t writeInputs(Parcel* data, T&& t, Remaining&&... remaining) const {    

       status_t error = writeIfInput(data, std::forward<T>(t));    

       if (CC_UNLIKELY(error != NO_ERROR)) {    

           // A message will have been logged by writeIfInput    

           return error;    

       }    

       return writeInputs(data, std::forward<Remaining>(remaining)...);    

   }    

   static status_t writeInputs(Parcel* /*data*/) { return NO_ERROR; }    

每一步调用ParcelHandler的一系列模版方法

template <typename T>    

   typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(    

           Parcel* data, T&& t) const {    

       return SafeInterface::ParcelHandler{mLogTag}.write(data, std::forward<T>(t));    

   }    

   template <typename T>    

   typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(    

           Parcel* /*data*/, T&& /*t*/) const {    

       return NO_ERROR;    

   }    

对于sp<IGraphicBufferProducer>这个出参会匹配到下面这个模版方法,这个模版方法又调用了另一个模版方法

template <typename T>    

   typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write(    

           Parcel* parcel, const sp<T>& interface) const {    

       return write(parcel, IInterface::asBinder(interface));    

   }    

下面这个模版方法,是上面那个模版方法调用的

template <typename T>    

   typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type write(    

           Parcel* parcel, const sp<T>& pointer) const {    

       return callParcel("writeStrongBinder",    

                         [&]() { return parcel->writeStrongBinder(pointer); });    

   }    

但是里面的pointer为null,因为IInterface::asBinder(interface)这个函数在开始判断iface == NULL 因为sp重载了 == 操作符 比较的是内部的m_ptr,因为是空的所以直接返回了null

inline bool operator _op_ (const sp<T>& o) const {              \    

   return m_ptr _op_ o.m_ptr;                                  \    

}      

// static    

sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface)    

{    

   if (iface == NULL) return NULL;    

   return iface->onAsBinder();    

}    

最终调用的是parcel->writeStrongBinder(pointer) 来写入,最终调用flatten_binder即下面这个函数来写入flat_binder_object,传递给binder驱动,里面的分支可以看到binder == NULL。往后面走入驱动就没法理解了,一个本来是代理Binder进入驱动变成了本地Binder.我读到这里就懵逼了,反复看了很久,我怀疑中间一定有一步读错了。。。感觉对于native层Binder通讯的出入参的理解有问题

status_t flatten_binder(const sp<ProcessState>& /*proc*/,    

   const sp<IBinder>& binder, Parcel* out)    

{    

   flat_binder_object obj;    

   if (IPCThreadState::self()->backgroundSchedulingDisabled()) {    

       /* minimum priority for all nodes is nice 0 */    

       obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;    

   } else {    

       /* minimum priority for all nodes is MAX_NICE(19) */    

       obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;    

   }    

   if (binder != NULL) {    

       IBinder *local = binder->localBinder();    

       if (!local) {    

           BpBinder *proxy = binder->remoteBinder();    

           if (proxy == NULL) {    

               ALOGE("null proxy");    

           }    

           const int32_t handle = proxy ? proxy->handle() : 0;    

           obj.hdr.type = BINDER_TYPE_HANDLE;    

           obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */    

           obj.handle = handle;    

           obj.cookie = 0;    

       } else {    

           obj.hdr.type = BINDER_TYPE_BINDER;    

           obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());    

           obj.cookie = reinterpret_cast<uintptr_t>(local);    

       }    

   } else {    

       obj.hdr.type = BINDER_TYPE_BINDER;    

       obj.binder = 0;    

       obj.cookie = 0;    

   }    

   return finish_flatten_binder(binder, obj, out);    

}    


1
3
风语
回复
慕村9285654
一、BpSurfaceComposerClient是proxy端,createSurface调用之后,parcel里面读出gbp。 二、BnSurfaceComposerClient是实体端,createSurface之后,gbp就有值了,然后写到parcel里面返回。createSurface具体实现在Client这个类里,Client继承了BnSurfaceComposerClient。 proxy端在发起createSurface调用的时候,没有传sp之类的,只是带了parcel,parcel里面也没有带这个sp,而是调用结束之后,从parcel里读出gbp,然后设置给这个sp。 remote()->transact(CREATE_SURFACE, data, &reply); *gbp = interface_cast(reply.readStrongBinder());
2019-06-23
共3条回复

剖析Framework面试 冲击Android高级职位

一手助力冲刺Android高级职位,一手把握系统底层原理,理清面试思路,提升技术段位

1406 学习 · 187 问题

查看课程