请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

老师问一下GBP传递的问题

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

正在回答

2回答

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

0 回复 有任何疑惑可以回复我~
  • 提问者 慕村9285654 #1
    老师谢谢,我知道哪里错了,它模板方法里专门判断了如果参数是指针就当成出参,不进行传递
    // 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 <typename T>
        struct IsPointerIfDecayed {
        private:
            using Decayed = typename std::decay<T>::type;
        public:
            static constexpr bool value = std::is_pointer<Decayed>::value;
        };
    回复 有任何疑惑可以回复我~ 2019-06-23 07:10:03
提问者 慕村9285654 2019-06-22 23:02:28
下面是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 回复 有任何疑惑可以回复我~
  • 风语 #1
    看样子是关于binder传输有疑问,建议看一下7.4,里面会讲到。
    回复 有任何疑惑可以回复我~ 2019-06-22 23:35:19
  • 提问者 慕村9285654 回复 风语 #2
    传输没有疑问 主要是不明白gbp传递参数的问题 createSurface传入的是空sp ,这个sp里面的gbp还没有赋值,但是作为跨进程传递的参数,sp被写入parcel的是里面的gbp,而这个gbp是空的 源码把这个空的binder 作为binder_type_binder给传进了驱动,那另一头读出来的不就是bpbinder了吗?
    回复 有任何疑惑可以回复我~ 2019-06-23 00:11:46
  • 风语 回复 提问者 慕村9285654 #3
    一、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<IGraphicBufferProducer>(reply.readStrongBinder());
    回复 有任何疑惑可以回复我~ 2019-06-23 01:10:51
问题已解决,确定采纳
还有疑问,暂不采纳
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号