一、前言
我们在BpServierManager的addService方法中,有一段初始化Parcel的代码,我们借此来分析一下Parcel的结构
二、源码分析
我们看下addService中Parcel的使用:
            
            
              c++
              
              
            
          
          ::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 初始化
mOut是IPCThreadState的成员变量,在IPCThreadState构造函数中设置:
            
            
              c++
              
              
            
          
          mOut.setDataCapacity(256);设定初始大小:
            
            
              c++
              
              
            
          
          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字节内存,将返回的地址存储到mData,mDataSize与mDataPos初始化为0,代表没有任何数据,mDataCapacity代表数据容量,初始化为256。
我们接下来依次看下Parcel被调用的各个方法
2.2 markForBinder
            
            
              c++
              
              
            
          
          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
            
            
              c++
              
              
            
          
          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:
            
            
              c++
              
              
            
          
          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:
            
            
              c++
              
              
            
          
          status_t Parcel::writeString16(const String16& str)
{
    return writeString16(str.string(), str.size());
}与上面的类似,只是写入长度不同,到目前为止,我们写入了三个int32,一个string16。
2.4 writeUtf8AsUtf16
            
            
              c++
              
              
            
          
          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我们不再深究,结果是:写入了一个int32与char16。
2.5 writeStrongBinder
            
            
              c++
              
              
            
          
          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
最后写入一个bool和int32。
我们之前都忽略了容量不足的情况,现在来看一下:
2.6 growData
            
            
              c++
              
              
            
          
          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:
            
            
              c++
              
              
            
          
          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、 mData是Parcel存放数据的内存起始地址
- 
2、 mDataPos是当前数据位置
- 
3、 mDataCapacity是最大数据容量,适时的时候需要进行缩容与扩容
- 
4、 mDataSize指的是当前数据尺寸
- 
5、 mObjects是一个指针,存放的是object在mData中的偏移地址
- 
6、 mObjects可以通过mObject[index]这种形式取不同object的offset,这是C++基础的指针操作,与数组类似
- 
7、 mObjectSize是mData中存储的object数量,我们在writeObject的时候会更新。