前文中曾經(jīng)遇到過Parcel,從命名上知道他負(fù)責(zé)數(shù)據(jù)打包。在checkService的請求/響應(yīng)體系中,Parcel只打包了基本數(shù)據(jù)類型,如Int32、String16……后面還要用于打包抽象數(shù)據(jù)類型flat_binder_object,這會稍微復(fù)雜一些,因此有必要拿出來單獨研究。我們從Parcel::writeInterfaceToken(…)追起,它的層層調(diào)用關(guān)系如下,這些函數(shù)都在frameworks/native/libs/binder/Parcel.cpp文件中,行數(shù)和函數(shù)名為:
582 writeInterfaceToken(…)
748 Parcel::writeInt32(int32_t val)
1149 Parcel::writeAligned(val)
所有的基本數(shù)據(jù)類型的打包最后都由writeAligned(…)實現(xiàn)的,其內(nèi)部邏輯也非常簡單,
frameworks/native/libs/binder/Parcel.cpp:1149
template<class T>
status_t Parcel::writeAligned(T val) {
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
*reinterpret_cast<T*>(mData+mDataPos) = val; // 將val追加到mData
return finishWrite(sizeof(val));
}
status_t err = growData(sizeof(val)); // 如果mData空間不夠,則先擴容
if (err == NO_ERROR) goto restart_write;
return err;
}
mData是一塊內(nèi)存棧,writeXXX則把數(shù)據(jù)寫入棧,如果mData空間不夠,先給mData擴容,并把原先的數(shù)據(jù)搬到新的空間,再把新數(shù)據(jù)寫入棧。
Parcel::writeStrongBinder(…)的邏輯更復(fù)雜一些,它的調(diào)用關(guān)系如下:
frameworks/native/libs/binder/Parcel.cpp
872 Parcel::writeStrongBinder(const sp<IBinder>& val)
205 Parcel::flatten_binder(const sp<ProcessState>& /proc/, const sp<IBinder>& binder =val, Parcel* out=this)
來看flatten_binder(…),frameworks/native/libs/binder/Parcel.cpp:205
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) {
IBinder *local = binder->localBinder();
if (!local) { // remote類型的binder封裝邏輯
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else { // local類型的binder封裝邏輯
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
}
return finish_flatten_binder(binder, obj, out);
}
它根據(jù)傳入binder的類型做不同的數(shù)據(jù)封裝,在frameworks/native/include/binder/IBinder.h:139,可以看到IBinder聲明了兩個虛函數(shù):
class IBinder : public virtual RefBase
{
public:
……
virtual BBinder* localBinder();
virtual BpBinder* remoteBinder();
……
};
并在frameworks/native/libs/binder/Binder.cpp:47定義了默認(rèn)實現(xiàn):
BBinder* IBinder::localBinder()
{
return NULL;
}
BpBinder* IBinder::remoteBinder()
{
return NULL;
}
flat_binder_object這個數(shù)據(jù)結(jié)構(gòu)在《Binder學(xué)習(xí)筆記(四)—— ServiceManager如何響應(yīng)checkService請求》研究ServiceManager如何組織reply數(shù)據(jù)時遇到過,它定義在external/kernel-headers/original/uapi/linux/binder.h:57。對于不同的binder封裝成的數(shù)據(jù)示意圖如下:


然后flatten_binder(…)調(diào)用finish_flatten_binder(…),frameworks/native/libs/binder/Parcel.cpp:199
inline static status_t finish_flatten_binder(
const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
{
return out->writeObject(flat, false);
}
繼續(xù)調(diào)用writeObject(…),frameworks/native/libs/binder/Parcel.cpp:1035
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:
// 如果空間足夠,他把前面組裝的flat_binder_object實體追加到mData里
*reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
……
if (nullMetaData || val.binder != 0) {
// mObjects記錄每次向mData追加的flat_binder_object的偏移位置
mObjects[mObjectsSize] = mDataPos;
acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
mObjectsSize++;
}
return finishWrite(sizeof(flat_binder_object));
}
……
}
總結(jié)一下:Parcel的數(shù)據(jù)區(qū)域分兩個部分:mData和mObjects,所有的數(shù)據(jù)不管是基礎(chǔ)數(shù)據(jù)類型還是對象實體,全都追加到mData里,mObjects是一個偏移量數(shù)組,記錄所有存放在mData中的flat_binder_object實體的偏移量。Parcel的數(shù)據(jù)模型如下:
