Binder – Parcel的结构

一、前言

我们在BpServierManageraddService方法中,有一段初始化Parcel的代码,我们借此来分析一下Parcel的结构

二、源码分析

我们看下addServiceParcel的使用:












::android::Parcel _aidl_data;











_aidl_data.markForBinder(remoteStrong());










::android::Parcel _aidl_reply;










::android::status_t _aidl_ret_status = ::android::OK;









::android::binder::Status _aidl_status;








_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());





_aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);




_aidl_ret_status = _aidl_data.writeStrongBinder(service);



_aidl_ret_status = _aidl_data.writeBool(allowIsolated);




_aidl_ret_status = _aidl_data.writeInt32(dumpPriority);




2.1 初始化

mOutIPCThreadState的成员变量,在IPCThreadState构造函数中设置:












mOut.setDataCapacity(256);











设定初始大小:












status_t Parcel::setDataCapacity(size_t size)











{
















    if (size > mDataCapacity) return continueWrite(size);










    return NO_ERROR;









}








  










status_t Parcel::continueWrite(size_t desired)





{





    // This is the first data.  Easy!




    uint8_t* data = (uint8_t*)malloc(desired);




    gParcelGlobalAllocSize += desired;





    gParcelGlobalAllocCount++;





    mData = data;






    mDataSize = mDataPos = 0;





    mDataCapacity = desired;





    return NO_ERROR;




}



从内存中申请256字节内存,将返回的地址存储到mDatamDataSizemDataPos初始化为0,代表没有任何数据,mDataCapacity代表数据容量,初始化为256。

我们接下来依次看下Parcel被调用的各个方法

2.2 markForBinder












void Parcel::markForBinder(const sp<IBinder>& binder) {











    LOG_ALWAYS_FATAL_IF(mData != nullptr, "format must be set before data is written");










  











    if (binder && binder->remoteBinder() && binder->remoteBinder()->isRpcBinder()) {

        markForRpc(binder->remoteBinder()->getPrivateAccessorForId().rpcSession());




    }





}





  









void Parcel::markForRpc(const sp<RpcSession>& session) {




    LOG_ALWAYS_FATAL_IF(mData != nullptr && mOwner == nullptr,



                        "format must be set before data is written OR on IPC data");


  








    LOG_ALWAYS_FATAL_IF(session == nullptr, "markForRpc requires session");





    mSession = session;





}




这个方法并不涉及主体数据的修改,只是保存mSession

2.3 writeInterfaceToken












status_t Parcel::writeInterfaceToken(const String16& interface)











{
















    return writeInterfaceToken(interface.string(), interface.size());










}












  














status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {





    if (CC_LIKELY(!isForRpc())) {





        const IPCThreadState* threadState = IPCThreadState::self();





        writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);




        updateWorkSourceRequestHeaderPosition();




        writeInt32(threadState->shouldPropagateWorkSource() ? threadState->getCallingWorkSourceUid()





                                                            : IPCThreadState::kUnsetWorkSource);





        writeInt32(kHeader);






    }






  







    // currently the interface identification token is just its name as a string


    return writeString16(str, len);


}


看下writeInt32












status_t Parcel::writeInt32(int32_t val)











{
















    return writeAligned(val);










}












  














template<class T>





status_t Parcel::writeAligned(T val) {





    static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));





    //如果容量够,直接写入




    if ((mDataPos+sizeof(val)) <= mDataCapacity) {




restart_write:





        *reinterpret_cast<T*>(mData+mDataPos) = val;





        return finishWrite(sizeof(val));






    }






    //容量不够的话,先扩容





    status_t err = growData(sizeof(val));




    if (err == NO_ERROR) goto restart_write;



    return err;


}


  




status_t Parcel::finishWrite(size_t len)


{


    //更新mDataPos(与mDataSize)


    mDataPos += len;


    if (mDataPos > mDataSize) {


        mDataSize = mDataPos;


    }


    return NO_ERROR;


}


writeAligned是个模板方法,包含了数据写入与扩容操作,写操作结束之后,更新mDataPos,再看下writeString16












status_t Parcel::writeString16(const String16& str)











{
















    return writeString16(str.string(), str.size());










}












与上面的类似,只是写入长度不同,到目前为止,我们写入了三个int32,一个string16

2.4 writeUtf8AsUtf16












status_t Parcel::writeUtf8AsUtf16(const std::string& str) {











    const uint8_t* strData = (uint8_t*)str.data();










    const size_t strLen= str.length();










    const ssize_t utf16Len = utf8_to_utf16_length(strData, strLen);









    status_t err = writeInt32(utf16Len);








    if (err) {





        return err;




    }



    void* dst = writeInplace((utf16Len + 1) * sizeof(char16_t));




    utf8_to_utf16(strData, strLen, (char16_t*)dst, (size_t) utf16Len + 1);




  








    return NO_ERROR;





}






从名字可以看出来,是将UTF-8的字符串写入为UTF-16的字符串,writeInplace我们不再深究,结果是:写入了一个int32char16

2.5 writeStrongBinder












status_t Parcel::writeStrongBinder(const sp<IBinder>& val)











{
















    return flattenBinder(val);










}












  














status_t Parcel::flattenBinder(const sp<IBinder>& binder)





{





    flat_binder_object obj;





    obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;




    if (binder != nullptr) {




        BBinder *local = binder->localBinder();





        if (!local) {





            BpBinder *proxy = binder->remoteBinder();






            const int32_t handle = proxy ? proxy->getPrivateAccessorForId().binderHandle() : 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;

    }

    obj.flags |= schedBits;

    status_t status = writeObject(obj, false);

    return finishFlattenBinder(binder);

}

  



status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)


{


    const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;


    const bool enoughObjects = mObjectsSize < mObjectsCapacity;


    //容量是否足够


    if (enoughData && enoughObjects) {

restart_write:

        *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;

  


        //给mObjects赋值,值为当前object的offset

        if (nullMetaData || val.binder != 0) {

            mObjects[mObjectsSize] = mDataPos;

            acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);

            mObjectsSize++;

        }

  


        return finishWrite(sizeof(flat_binder_object));

    }

    //容量不够

    if (!enoughData) {

        const status_t err = growData(sizeof(val));

        if (err != NO_ERROR) return err;

    }

    // ... exception

    goto restart_write;

}

  


status_t Parcel::finishFlattenBinder(const sp<IBinder>& binder)

{

    internal::Stability::tryMarkCompilationUnit(binder.get());

    auto category = internal::Stability::getCategory(binder.get());

    return writeInt32(category.repr());

}

将Binder对象“展开”为flat_binder_object,然后将其写入,然后写入一个int32

最后写入一个boolint32

我们之前都忽略了容量不足的情况,现在来看一下:

2.6 growData












status_t Parcel::growData(size_t len)











{
















    size_t newSize = ((mDataSize+len)*3)/2;










    return (newSize <= mDataSize)









            ? (status_t) NO_MEMORY








            : continueWrite(std::max(newSize, (size_t) 128));





}




扩容计算公式为:(旧容量+新增长度) * 3 / 2,举个例子:如果旧容量为256,新增长度为4,那么结果为(256+4) * 3 / 2 = 390,然后执行continueWrite:












status_t Parcel::continueWrite(size_t desired)











{
















    size_t objectsSize = mObjectsSize;










    //缩容逻辑,如果目标小于当前size,则缩容到相应大小









    if (desired < mDataSize) {








        if (desired == 0) {





            objectsSize = 0;




        } else {



            while (objectsSize > 0) {




                if (mObjects[objectsSize-1] < desired)




                    break;



                objectsSize--;


            }


        }

    }

    if (mData) {


        if (objectsSize < mObjectsSize) {


            //缩容之后,对应的Object释放等逻辑


        }


        //容量不够,申请修改内存大小

        if (desired > mDataCapacity) {


            uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero);


            if (data) {


                mData = data;


                mDataCapacity = desired;


            } else {


                mError = NO_MEMORY;


                return NO_MEMORY;


            }


        } else {


            //fix当前offset尺寸与位置

            if (mDataSize > desired) {

                mDataSize = desired;

            }


            if (mDataPos > desired) {


                mDataPos = desired;


            }


        }


  



    }

    return NO_ERROR;

}

三、总结

经过上面这些阶段,我们基本上可以理解Parcel里面一些成员变量的含义,以及Parcel的一些内存布局,及其之间的对应关系,成图之后大概如下所示:

图3.1 – Parcel的基本结构

可以得到以下几个信息:

  • 1、mDataParcel存放数据的内存起始地址

  • 2、mDataPos是当前数据位置

  • 3、mDataCapacity是最大数据容量,适时的时候需要进行缩容与扩容

  • 4、mDataSize指的是当前数据尺寸

  • 5、mObjects是一个指针,存放的是objectmData中的偏移地址

  • 6、mObjects可以通过mObject[index]这种形式取不同objectoffset,这是C++基础的指针操作,与数组类似

  • 7、mObjectSizemData中存储的object数量,我们在writeObject的时候会更新。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYuIWMpS' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片