Parcel是android中不同于Java Serialize新的序列化机制。
Java Serialize机制作用是能将数据对象存入字节流中,在需要时重新生成对象。主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等。
而android系统定位内存受限设备,对性能要求更高,而且系统中采用了binder ipc机制,就需要求性能更出色的对象传输方式。Parcel定位就是轻量级高效的对象序列化和反序列化机制。
源码位于
Framework/native/include/binder/parcel.h
Framework/native/libs\binder\Parcel.cpp
我们以MediaPlayer的SeriviceManager的addService为例,解析Parcel
- virtual status_t addService(const String16& name, const sp<IBinder>& service,
- bool allowIsolated)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- data.writeStrongBinder(service);
- data.writeInt32(allowIsolated ? 1 : 0);
- status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
- return err == NO_ERROR ? reply.readExceptionCode() : err;
- }
从代码知,实例化了两个Parcel栈上对象data和reply,data主要是传送给servicemanager程序,而reply是从servicemanager返回的结果。
Data写入的值有InterfaceToken :“android.os.IServiceManager” String16:“media.player”
StrongBinder:MediaPlayerService, Int32: 0
我们跟踪入Parcel,看他形成了什么样的数据格式
- status_t Parcel::writeInterfaceToken(const String16& interface)
- {
- writeInt32(IPCThreadState::self()->getStrictModePolicy() |
- STRICT_MODE_PENALTY_GATHER);
- // currently the interface identification token is just its name as a string
- return writeString16(interface);
- }
- writeInterfaceToken写入int32的IPCThreadState的strictmode policy,还有string16的android.os.IServiceManager字符串
- status_t Parcel::writeInt32(int32_t val)
- {
- return writeAligned(val);
- }
- template<class T>
- status_t Parcel::writeAligned(T val) {
- COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(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;
- }
从代码可以看出writeInt32实际上调用的是writeAligned泛型函数
writeInterfaceToken是parcel第一次被调用的函数,
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
是断言,判断读写时是否为4字节对齐#define PAD_SIZE(s) (((s)+3)&~3)
从代码可以看出,写的数据主要往mData里面,下面为创建Parcel对象时的初始值
- void Parcel::initState()
- {
- mError = NO_ERROR;
- mData = 0;
- mDataSize = 0;
- mDataCapacity = 0;
- mDataPos = 0;
- ALOGV("initState Setting data size of %p to %d\n", this, mDataSize);
- ALOGV("initState Setting data pos of %p to %d\n", this, mDataPos);
- mObjects = NULL;
- mObjectsSize = 0;
- mObjectsCapacity = 0;
- mNextObjectHint = 0;
- mHasFds = false;
- mFdsKnown = true;
- mAllowFds = true;
- mOwner = NULL;
- }<p>再回到<span style="font-family:Times New Roman;">writeAligned</span><span style="font-family:宋体;">函数,此时被</span><span style="font-family:Times New Roman;">goto</span><span style="font-family:宋体;">语句指到了赋值语句,把值赋给了</span><span style="font-family:Times New Roman;">mData</span><span style="font-family:宋体;">,最后调用</span><span style="font-family:Times New Roman;">finishWrite</span></p>
很明显条件是不符合的,所以得去growData函数分配更多的内存空间
- status_t Parcel::growData(size_t len)
- {
- size_t newSize = ((mDataSize+len)*3)/2; //newSize = ((0+4)*3)/2 = 6
- return (newSize <= mDataSize)
- ? (status_t) NO_MEMORY
- : continueWrite(newSize);
- }
可以看到内存的申请是通过continueWrite
- status_t Parcel::continueWrite(size_t desired)
- {
- // If shrinking, first adjust for any objects that appear
- // after the new data size.
- size_t objectsSize = mObjectsSize;
- if (desired < mDataSize) {
- if (desired == 0) {
- objectsSize = 0;
- } else {
- while (objectsSize > 0) {
- if (mObjects[objectsSize-1] < desired)
- break;
- objectsSize--;
- }
- }
- }
- if (mOwner) {
- // If the size is going to zero, just release the owner's data.
- if (desired == 0) {
- freeData();
- return NO_ERROR;
- }
- // If there is a different owner, we need to take
- // posession.
- uint8_t* data = (uint8_t*)malloc(desired);
- if (!data) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
- size_t* objects = NULL;
- if (objectsSize) {
- objects = (size_t*)malloc(objectsSize*sizeof(size_t));
- if (!objects) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
- // Little hack to only acquire references on objects
- // we will be keeping.
- size_t oldObjectsSize = mObjectsSize;
- mObjectsSize = objectsSize;
- acquireObjects();
- mObjectsSize = oldObjectsSize;
- }
- if (mData) {
- memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
- }
- if (objects && mObjects) {
- memcpy(objects, mObjects, objectsSize*sizeof(size_t));
- }
- //ALOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
- mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
- mOwner = NULL;
- mData = data;
- mObjects = objects;
- mDataSize = (mDataSize < desired) ? mDataSize : desired;
- ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
- mDataCapacity = desired;
- mObjectsSize = mObjectsCapacity = objectsSize;
- mNextObjectHint = 0;
- } else if (mData) {
- if (objectsSize < mObjectsSize) {
- // Need to release refs on any objects we are dropping.
- const sp<ProcessState> proc(ProcessState::self());
- for (size_t i=objectsSize; i<mObjectsSize; i++) {
- const flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
- // will need to rescan because we may have lopped off the only FDs
- mFdsKnown = false;
- }
- release_object(proc, *flat, this);
- }
- size_t* objects =
- (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
- if (objects) {
- mObjects = objects;
- }
- mObjectsSize = objectsSize;
- mNextObjectHint = 0;
- }
- // We own the data, so we can just do a realloc().
- if (desired > mDataCapacity) {
- uint8_t* data = (uint8_t*)realloc(mData, desired);
- if (data) {
- mData = data;
- mDataCapacity = desired;
- } else if (desired > mDataCapacity) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
- } else {
- if (mDataSize > desired) {
- mDataSize = desired;
- ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
- }
- if (mDataPos > desired) {
- mDataPos = desired;
- ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
- }
- }
- } else {
- // This is the first data. Easy!
- uint8_t* data = (uint8_t*)malloc(desired);
- if (!data) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
- if(!(mDataCapacity == 0 && mObjects == NULL
- && mObjectsCapacity == 0)) {
- ALOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
- }
- mData = data;
- mDataSize = mDataPos = 0;
- ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
- ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
- mDataCapacity = desired;
- }
- return NO_ERROR;
- }
从代码知道mData存储着普通数据,mObjects则记录着内存块IBinder类型的数据以及FileDescriptor,而后者是通过flatten_binder()和unflatten_binder()实现的。
而我们writeInt32是mData这步,如果mData之前有分配内存走realloc,没分配走malloc,此时mDataCapacity为6,mData为分配出来的内存,mDataSize = mDataPos = 0;
- template<class T>
- status_t Parcel::writeAligned(T val) {
- COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(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;
- }
再回到writeAligned函数,此时被goto语句指到了赋值语句,把值赋给了mData,最后调用finishWrite
- status_t Parcel::finishWrite(size_t len)
- {
- //printf("Finish write of %d\n", len);
- mDataPos += len;
- ALOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos);
- if (mDataPos > mDataSize) {
- mDataSize = mDataPos;
- ALOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize);
- }
- //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);
- return NO_ERROR;
- }
mDataPos = 4, mDataSize = 4;
到这里就完成了writeInt32的操作
接着我们看writeInterfaceToken的writeString16
- status_t Parcel::writeString16(const char16_t* str, size_t len)
- { // str = “android.os.IServiceManager”
- if (str == NULL) return writeInt32(-1);
- status_t err = writeInt32(len);
- if (err == NO_ERROR) {
- len *= sizeof(char16_t); // 104
- uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t)); // 108
- if (data) {
- memcpy(data, str, len);
- *reinterpret_cast<char16_t*>(data+len) = 0;
- return NO_ERROR;
- }
- err = mError;
- }
- return err;
- }
从代码可以看到String是先在前面写了他str的个数大小,然后
- void* Parcel::writeInplace(size_t len)
- {
- const size_t padded = PAD_SIZE(len); // 56 (54内存对齐)
- // sanity check for integer overflow
- if (mDataPos+padded < mDataPos) { //8+56 < 12 ?
- return NULL;
- }
- if ((mDataPos+padded) <= mDataCapacity) { // 8+56 < 12 ?
- restart_write:
- //printf("Writing %ld bytes, padded to %ld\n", len, padded);
- uint8_t* const data = mData+mDataPos; // 指针指向为赋值的地方
- // Need to pad at end?
- if (padded != len) { // 56 != 54
- #if BYTE_ORDER == BIG_ENDIAN
- static const uint32_t mask[4] = {
- 0x00000000, 0xffffff00, 0xffff0000, 0xff000000
- };
- #endif
- #if BYTE_ORDER == LITTLE_ENDIAN
- static const uint32_t mask[4] = {
- 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff
- };
- #endif
- //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len],
- // *reinterpret_cast<void**>(data+padded-4));
- // data + 108 - 4 最后4位字节对齐后数据因大小端需保护是否正常
- *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len];
- }
- finishWrite(padded); // 把大小赋予mDataPos = 56 +8和mDataSize = 56 +8 return data;
- }
- status_t err = growData(padded); // 申请了(mDataSize(8) + 56 )*3/2的内存(96)
- if (err == NO_ERROR) goto restart_write;
- return NULL;
- }
如果数据不够则申请内存,够的话,要考虑对齐后大小端问题,然后通过memcpy把str赋值给data,同时在最后加上结束符
writeInterfaceToken函数就到这,现在Parcel的mData是这样的
- virtual status_t addService(const String16& name, const sp<IBinder>& service,
- bool allowIsolated)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- data.writeStrongBinder(service);
- data.writeInt32(allowIsolated ? 1 : 0);
- status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
- return err == NO_ERROR ? reply.readExceptionCode() : err;
- }
接着是data.writeString16(name); // name = “media.player”
可得出如下结构
接着是data.writeStrongBinder(service);这里的service是MediaplayerService,它是继承于IBinder的,所以写的不止是mData,还有mObject,跟踪下代码
- status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
- {
- return flatten_binder(ProcessState::self(), val, this);
- }
- 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; //接收其他进程发过来的文件形式binder
- if (binder != NULL) {
- IBinder *local = binder->localBinder(); // mediaplayer service这项不为空
- if (!local) {
- // 此处为client端使用
- BpBinder *proxy = binder->remoteBinder();
- if (proxy == NULL) {
- ALOGE("null proxy");
- }
- const int32_t handle = proxy ? proxy->handle() : 0;
- obj.type = BINDER_TYPE_HANDLE;
- obj.handle = handle;
- obj.cookie = NULL;
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = local->getWeakRefs();
- obj.cookie = local;
- }
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = NULL;
- obj.cookie = NULL;
- }
- return finish_flatten_binder(binder, obj, out);
- }
可以看出,这里涉及到flat_binder_object
从代码可以看出,mediaplayer service flat_binder_object 值如下
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; // 8个字节
obj.type = BINDER_TYPE_BINDER; // 8个字节
obj.binder = local->getWeakRefs(); // 8个字节
obj.cookie = local; // 4 个字节
- inline static status_t finish_flatten_binder(
- const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
- {
- return out->writeObject(flat, false);
- }
- status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
- {
- // flat_binder_object本身是28字节已经对齐
- const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity; // 96+28 <= 96
- const bool enoughObjects = mObjectsSize < mObjectsCapacity; // 0 < 0
- if (enoughData && enoughObjects) { // false && false
- restart_write:
- *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
- // Need to write meta-data?
- if (nullMetaData || val.binder != NULL) {
- mObjects[mObjectsSize] = mDataPos; //mObject[0] = 96
- acquire_object(ProcessState::self(), val, this); // 增加引用值
- mObjectsSize++; //mObjectsSize = 1
- }
- // remember if it's a file descriptor
- if (val.type == BINDER_TYPE_FD) {
- if (!mAllowFds) {
- return FDS_NOT_ALLOWED;
- }
- mHasFds = mFdsKnown = true;
- }
- return finishWrite(sizeof(flat_binder_object)); // 28 mDataPos = 96+28 ....
- }
- if (!enoughData) { // false
- const status_t err = growData(sizeof(val)); // ((96+28)*3)/2 =186
- if (err != NO_ERROR) return err;
- }
- if (!enoughObjects) { // false
- size_t newSize = ((mObjectsSize+2)*3)/2; // (0+2)*3/2 = 3
- size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t)); // 3*4 = 12
- if (objects == NULL) return NO_MEMORY;
- mObjects = objects;
- mObjectsCapacity = newSize; // mObjectsCapacity = 12
- }
- goto restart_write;
- }
- void acquire_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who)
- {
- switch (obj.type) {
- case BINDER_TYPE_BINDER:
- if (obj.binder) {
- LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
- static_cast<IBinder*>(obj.cookie)->incStrong(who);
- }
- return;
- case BINDER_TYPE_WEAK_BINDER:
- if (obj.binder)
- static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);
- return;
- case BINDER_TYPE_HANDLE: {
- const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
- if (b != NULL) {
- LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());
- b->incStrong(who);
- }
- return;
- }
- case BINDER_TYPE_WEAK_HANDLE: {
- const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
- if (b != NULL) b.get_refs()->incWeak(who);
- return;
- }
- case BINDER_TYPE_FD: {
- // intentionally blank -- nothing to do to acquire this, but we do
- // recognize it as a legitimate object type.
- return;
- }
- }
- ALOGD("Invalid object type 0x%08lx", obj.type);
- }
通过writeObject函数把flat_binder_object 值 写入了mData,并mObject记录了flat_binder_object的起始位置
mData:
mObject:
最后data.writeInt32(allowIsolated ? 1 : 0);
最后通过remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
BpBinder(0)把Parcel data发送到ServiceManager
我们来看看读出数据,还是用addService的数据,看看怎么读取!
读取数据我们只好到servicemanager里面看下
Data的解析就在这binder_txn 的data(binder_io *msg)里面
- int svcmgr_handler(struct binder_state *bs,
- struct binder_txn *txn,
- struct binder_io *msg, /** 是data */
- struct binder_io *reply)
- {
- struct svcinfo *si;
- uint16_t *s;
- unsigned len;
- void *ptr;
- uint32_t strict_policy;
- int allow_isolated;
- // ALOGI("target=%p code=%d pid=%d uid=%d\n",
- // txn->target, txn->code, txn->sender_pid, txn->sender_euid);
- if (txn->target != svcmgr_handle)
- return -1;
- // Equivalent to Parcel::enforceInterface(), reading the RPC
- // header with the strict mode policy mask and the interface name.
- // Note that we ignore the strict_policy and don't propagate it
- // further (since we do no outbound RPCs anyway).
- strict_policy = bio_get_uint32(msg); // 读出4个字节的strictmode
- s = bio_get_string16(msg, &len); // 读出带字符串长度,并对齐的字符串android.os.IServiceManager
- if ((len != (sizeof(svcmgr_id) / 2)) ||
- memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { // svcmgr_id为android.os.IServiceManager
- fprintf(stderr,"invalid id %s\n", str8(s));
- return -1;
- }
- switch(txn->code) {
- case SVC_MGR_GET_SERVICE:
- case SVC_MGR_CHECK_SERVICE:
- s = bio_get_string16(msg, &len);
- ptr = do_find_service(bs, s, len, txn->sender_euid);
- if (!ptr)
- break;
- // 如果找到则填充ptr入reply
- bio_put_ref(reply, ptr);
- return 0;
- case SVC_MGR_ADD_SERVICE:
- s = bio_get_string16(msg, &len); // 读出带字符串长度,并对齐的字符串media.player
- ptr = bio_get_ref(msg); // 读出flat_binder_obj(带有MediaplayerService)
- allow_isolated = bio_get_uint32(msg) ? 1 : 0; //读出allow_isolated
- if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
- return -1;
- break;
- case SVC_MGR_LIST_SERVICES: {
- unsigned n = bio_get_uint32(msg);
- si = svclist;
- while ((n-- > 0) && si)
- si = si->next;
- if (si) {
- bio_put_string16(reply, si->name);
- return 0;
- }
- return -1;
- }
- default:
- ALOGE("unknown code %d\n", txn->code);
- return -1;
- }
- bio_put_uint32(reply, 0);
- return 0;
- }
其中bio_get_string16,bio_get_uint32这些实际上相当于Parcel里面的readString16,readInt32!
我们把他当做parcel的成员函数来看,从代码看刚刚好是对应的,至于为什么能指向到其他进程的地址空间,那是binder driver做的
至于Java层的Parcel后面再讨论