C++的Parcel类位于platform\frameworks\native\libs\binder\Parcel.cpp中

class Parcel {//-----------------------------------------------------------------------------private:status_t            mError;uint8_t*            mData;size_t              mDataSize;size_t              mDataCapacity;mutable size_t      mDataPos;binder_size_t*      mObjects;size_t              mObjectsSize;size_t              mObjectsCapacity;mutable size_t      mNextObjectHint;mutable bool        mObjectsSorted;mutable bool        mRequestHeaderPresent;mutable size_t      mWorkSourceRequestHeaderPosition;mutable bool        mFdsKnown;mutable bool        mHasFds;bool                mAllowFds;// if this parcelable is involved in a secure transaction, force the// data to be overridden with zero when deallocatedmutable bool        mDeallocZero;release_func        mOwner;……………………
};

  成员变量mData指向存储数据的内存位置,mDataSize是数据的大小,mDataCapacity是存储内存的容量,mDataPos是相对于mData位置,数据目前存放到的位置。
  mObjects是为了保存Binder类对象地址使用的(这个地址是相对于mData),mObjectsSize数据里面保存的Binder类对象的数量,mObjectsCapacity是内存中可以保存Binder类对象的大小容量。
  成员变量mOwner是释放内存的方法,可能设置,也可能不设置。

2个Binder对象示意图

Parcel类的初始化

Parcel::Parcel()
{LOG_ALLOC("Parcel %p: constructing", this);initState();
}void Parcel::initState()
{LOG_ALLOC("Parcel %p: initState", this);mError = NO_ERROR;mData = nullptr;mDataSize = 0;mDataCapacity = 0;mDataPos = 0;ALOGV("initState Setting data size of %p to %zu", this, mDataSize);ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);mSession = nullptr;mObjects = nullptr;mObjectsSize = 0;mObjectsCapacity = 0;mNextObjectHint = 0;mObjectsSorted = false;mHasFds = false;mFdsKnown = true;mAllowFds = true;mDeallocZero = false;mOwner = nullptr;mWorkSourceRequestHeaderPosition = 0;mRequestHeaderPresent = false;// racing multiple init leads only to multiple identical writeif (gMaxFds == 0) {struct rlimit result;if (!getrlimit(RLIMIT_NOFILE, &result)) {gMaxFds = (size_t)result.rlim_cur;//ALOGI("parcel fd limit set to %zu", gMaxFds);} else {ALOGW("Unable to getrlimit: %s", strerror(errno));gMaxFds = 1024;}}
}

  可见,构造函数是调用initState()函数,在该函数中,初始化成员变量,指针型成员变量mData、mObjects都为nullptr,整数型成员变量mDataSize、mDataCapacity、mDataPos、mObjectsSize、mObjectsCapacity都赋值为0。gMaxFds是静态全局变量,第一次(值为0)调用的时候,会调用getrlimit(RLIMIT_NOFILE, &result)得到进程的打开文件描述符个数的限制,然后赋值给gMaxFds。

设置容量

status_t Parcel::setDataCapacity(size_t size)
{if (size > INT32_MAX) {// don't accept size_t values which may have come from an// inadvertent conversion from a negative int.return BAD_VALUE;}if (size > mDataCapacity) return continueWrite(size);return NO_ERROR;
}

  如果设置的size大于INT32_MAX,会返回BAD_VALUE。可见Parcel类对象的最大容量也就是INT32_MAX(2^31-1)byte。接着判断,如果当前设置的容量超过原来的容量需要调用continueWrite(size)方法:

status_t Parcel::continueWrite(size_t desired)
{if (desired > INT32_MAX) {// don't accept size_t values which may have come from an// inadvertent conversion from a negative int.return BAD_VALUE;}// 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;}binder_size_t* objects = nullptr;if (objectsSize) {objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t));if (!objects) {free(data);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(binder_size_t));}//ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());mOwner(this, mData, mDataSize, mObjects, mObjectsSize);mOwner = nullptr;LOG_ALLOC("Parcel %p: taking ownership of %zu capacity", this, desired);gParcelGlobalAllocSize += desired;gParcelGlobalAllocCount++;mData = data;mObjects = objects;mDataSize = (mDataSize < desired) ? mDataSize : desired;ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize);mDataCapacity = desired;mObjectsSize = mObjectsCapacity = objectsSize;mNextObjectHint = 0;mObjectsSorted = false;} 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->hdr.type == BINDER_TYPE_FD) {// will need to rescan because we may have lopped off the only FDsmFdsKnown = false;}release_object(proc, *flat, this);}if (objectsSize == 0) {free(mObjects);mObjects = nullptr;mObjectsCapacity = 0;} else {binder_size_t* objects =(binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));if (objects) {mObjects = objects;mObjectsCapacity = objectsSize;}}mObjectsSize = objectsSize;mNextObjectHint = 0;mObjectsSorted = false;}// We own the data, so we can just do a realloc().if (desired > mDataCapacity) {uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero);if (data) {LOG_ALLOC("Parcel %p: continue from %zu to %zu capacity", this, mDataCapacity,desired);gParcelGlobalAllocSize += desired;gParcelGlobalAllocSize -= mDataCapacity;mData = data;mDataCapacity = desired;} else {mError = NO_MEMORY;return NO_MEMORY;}} else {if (mDataSize > desired) {mDataSize = desired;ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize);}if (mDataPos > desired) {mDataPos = desired;ALOGV("continueWrite Setting data pos of %p to %zu", 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 == nullptr&& mObjectsCapacity == 0)) {ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity, mObjects, mObjectsCapacity, desired);}LOG_ALLOC("Parcel %p: allocating with %zu capacity", this, desired);gParcelGlobalAllocSize += desired;gParcelGlobalAllocCount++;mData = data;mDataSize = mDataPos = 0;ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize);ALOGV("continueWrite Setting data pos of %p to %zu", this, mDataPos);mDataCapacity = desired;}return NO_ERROR;
}

  3-7行,首先检查设置容量是否大于最大值,如果大于直接返回BAD_VALUE。
  11-22行,如果设置的容量小于当前Parcel对象里面数据的大小,则从后向前找到其中第一个Binder对象地址小于设置容量序号,
  接着判断mOwner(释放内存的方法)如果设置了,这时候如果设置的大小等于0,就是要释放数据内存,会调用freeData(),然后就返回了。freeData()在后面再讲,接着向下看。申请desired字节内存,临时变量data指向其开始地址。
  接着如果发现变量objectsSize不为0,则申请objectsSize*sizeof(binder_size_t)个字节的内存,并且将objects指向它。然后将mObjectsSize保存到临时变量oldObjectsSize中,再将objectsSize赋值给mObjectsSize,紧接着调用acquireObjects()来将对应的Binder对象的引用计数增加,因为即将新分配了的内存数据会指向它。然后又将mObjectsSize的值还原。
  下面就是调用memcpy()函数,拷贝原来的内存中的数据。当然,数据长度可能发生改变,需要进行调整。然后再调用mOwner函数来释放原来的内存数据。然后就将mOwner赋值为nullptr。最后就是将原来的变量指针都指向新的内存数据。

  看代码80行的分支,这个代表已经分配过内存,并且没有设置mOwner函数的情况。
  如果Binder对象的数量发生了变化,即objectsSize < mObjectsSize。这个时候需要将最后超出调整后内存位置的Binder对象丢弃。从objectsSize到mObjectsSize数量之间的会被丢弃。通过循环调用release_object(proc, flat, this),该函数也在下面进行描述。
  如果调整后的Binder对象数量为0,则释放mObjects。如果不为0,则调用realloc(mObjects, objectsSize
sizeof(binder_size_t))调整内存大小。分配成功,则将mObjects指向objects,将mObjectsCapacity变成objectsSize,接着将mObjectsSize的值也变成objectsSize。
  接着进行判断,如果重新设置的大小超过了原来的容量mDataCapacity,则调用reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero):

static uint8_t* reallocZeroFree(uint8_t* data, size_t oldCapacity, size_t newCapacity, bool zero) {if (!zero) {return (uint8_t*)realloc(data, newCapacity);}uint8_t* newData = (uint8_t*)malloc(newCapacity);if (!newData) {return nullptr;}memcpy(newData, data, std::min(oldCapacity, newCapacity));zeroMemory(data, oldCapacity);free(data);return newData;
}

  可见,如果zero为false,即释放内存的时候不用为0。这个时候,就直接在原来的内存的基础上重新调用realloc()函数进行分配。如果需要释放的内存为0,则重新分配一块内存,并且将原来的数据都拷贝进新分配的内存中。将原来的内存数据都清零,并且释放掉原来的内存。
  处理完这块之后,就将mData赋值为分配的data,将mDataCapacity设置为新的内存大小desired。
  如果新调整的大小小于原来内存的容量大小,这个时候,不用进行重新分配,还是使用原来的内存,只是需要调整成员变量mDataSize、mDataPos的值。如果这俩值都比desired大,则都调整为desired的值。

  continueWrite()代码第136行,是说还没有分配过数据内存呢。这种情况下比较容易,直接分配即可。分配过之后,将mData指向该内存。然后将mDataSize、mDataPos的值设置为0,并且将mDataCapacity设置为desired。

freeData():

void Parcel::freeData()
{freeDataNoInit();initState();
}void Parcel::freeDataNoInit()
{if (mOwner) {LOG_ALLOC("Parcel %p: freeing other owner data", this);//ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());mOwner(this, mData, mDataSize, mObjects, mObjectsSize);} else {LOG_ALLOC("Parcel %p: freeing allocated data", this);releaseObjects();if (mData) {LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity);gParcelGlobalAllocSize -= mDataCapacity;gParcelGlobalAllocCount--;if (mDeallocZero) {zeroMemory(mData, mDataSize);}free(mData);}if (mObjects) free(mObjects);}
}

  看到接着调用freeDataNoInit()和initState()方法,在freeDataNoInit()里面接着判断mOwner如果设置,就会调用该方法释放内存。如果没有设置mOwner,则会先调用releaseObjects()释放Binder对象,然后释放mData,最后释放mObjects。并且如果设置了mDeallocZero为true,则会先将其中数据都设置为0。
  接着看下releaseObjects():

void Parcel::releaseObjects()
{size_t i = mObjectsSize;if (i == 0) {return;}sp<ProcessState> proc(ProcessState::self());uint8_t* const data = mData;binder_size_t* const objects = mObjects;while (i > 0) {i--;const flat_binder_object* flat= reinterpret_cast<flat_binder_object*>(data+objects[i]);release_object(proc, *flat, this, &mOpenAshmemSize);}
}

  取到Binder对象的数量,然后从后向前找到所有的Binder对象(flat_binder_object结构表示),然后调用release_object(proc, *flat, this, &mOpenAshmemSize):

static void release_object(const sp<ProcessState>& proc,const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
{switch (obj.hdr.type) {case BINDER_TYPE_BINDER:if (obj.binder) {LOG_REFS("Parcel %p releasing reference on local %llu", who, obj.cookie);reinterpret_cast<IBinder*>(obj.cookie)->decStrong(who);}return;case BINDER_TYPE_HANDLE: {const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);if (b != nullptr) {LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());b->decStrong(who);}return;}case BINDER_TYPE_FD: {if (obj.cookie != 0) { // ownedif ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {int size = ashmem_get_size_region(obj.handle);if (size > 0) {// ashmem size might have changed since last time it was accounted for, e.g.// in acquire_object(). Value of *outAshmemSize is not critical since we are// releasing the object anyway. Check for integer overflow condition.*outAshmemSize -= std::min(*outAshmemSize, static_cast<size_t>(size));}}close(obj.handle);}return;}}ALOGE("Invalid object type 0x%08x", obj.hdr.type);
}

  如果类型是BINDER_TYPE_BINDER,即是BBinder对象,flat_binder_object结构对象obj的成员cookie即指向BBinder对象的地址,接着调用decStrong(who)方法,减掉一个强、弱引用计数,flat_binder_object结构对象obj的成员binder指向这个BBinder对象的mRefs(weakref_impl类)地址,涉及到智能指针的使用方式,这个地方不展开。
  如果类型是BINDER_TYPE_HANDLE,即代表BpBinder对象,通过调用proc->getStrongProxyForHandle(obj.handle)得到BpBinder对象。然后也是调用decStrong(who)方法,减掉一个强、弱引用计数。
ProcessState类的getStrongProxyForHandle(obj.handle)方法如下:

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{sp<IBinder> result;AutoMutex _l(mLock);handle_entry* e = lookupHandleLocked(handle);if (e != nullptr) {// We need to create a new BpBinder if there isn't currently one, OR we// are unable to acquire a weak reference on this current one.  The// attemptIncWeak() is safe because we know the BpBinder destructor will always// call expungeHandle(), which acquires the same lock we are holding now.// We need to do this because there is a race condition between someone// releasing a reference on this BpBinder, and a new reference on its handle// arriving from the driver.IBinder* b = e->binder;if (b == nullptr || !e->refs->attemptIncWeak(this)) {if (handle == 0) {// Special case for context manager...// The context manager is the only object for which we create// a BpBinder proxy without already holding a reference.// Perform a dummy transaction to ensure the context manager// is registered before we create the first local reference// to it (which will occur when creating the BpBinder).// If a local reference is created for the BpBinder when the// context manager is not present, the driver will fail to// provide a reference to the context manager, but the// driver API does not return status.//// Note that this is not race-free if the context manager// dies while this code runs.//// TODO: add a driver API to wait for context manager, or// stop special casing handle 0 for context manager and add// a driver API to get a handle to the context manager with// proper reference counting.IPCThreadState* ipc = IPCThreadState::self();CallRestriction originalCallRestriction = ipc->getCallRestriction();ipc->setCallRestriction(CallRestriction::NONE);Parcel data;status_t status = ipc->transact(0, IBinder::PING_TRANSACTION, data, nullptr, 0);ipc->setCallRestriction(originalCallRestriction);if (status == DEAD_OBJECT)return nullptr;}sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle);e->binder = b.get();if (b) e->refs = b->getWeakRefs();result = b;} else {// This little bit of nastyness is to allow us to add a primary// reference to the remote proxy when this team doesn't have one// but another team is sending the handle to us.result.force_set(b);e->refs->decWeak(this);}}return result;
}

  ProcessState类对象通过lookupHandleLocked(handle)查找得到handle_entry对象e。handle_entry对象的成员binder即指向对应的BpBinder对象。如果b == nullptr,即还没有创建BpBinder对象。或者!e->refs->attemptIncWeak(this),即不能通过弱引用转换为强引用,这个时候,需要新建一个BpBinder对象。这两种情况下,都是通过BpBinder::PrivateAccessor::create(handle)创建一个BpBinder对象。然后将该对象地址赋值给e->binder,并且将BpBinder对象的引用指针对象赋值给e->refs,最后将新建的引用对象赋值给返回结果result。通过注释看出,还有一种需要特殊处理即handle为0的情况,这个代表对上下文管理者Binder对象的引用。在第一次引用它的时候,需要发送IBinder::PING_TRANSACTION指令进行处理。
  上面说的是需要新建BpBinder对象的情况,其他的情况代表,BpBinder对象存在,则将result.force_set(b),然后减去弱引用计数,最后返回result。
ProcessState类对象通过lookupHandleLocked(handle)实现如下:

ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{const size_t N=mHandleToObject.size();if (N <= (size_t)handle) {handle_entry e;e.binder = nullptr;e.refs = nullptr;status_t err = mHandleToObject.insertAt(e, N, handle+1-N);if (err < NO_ERROR) return nullptr;}return &mHandleToObject.editItemAt(handle);
}

  mHandleToObject是Vector<handle_entry>,ProcessState是根据handle对应Vector的序列位置来维护的。若handle大于等于Vector的size,则向其中加入handle+1-N个对象,这些对象的成员binder和refs均为nullptr。最后取出对应序列位置内容。
  回到 release_object 函数中,如果类型是BINDER_TYPE_FD,说明进程传递的数据中包含文件描述符,这个时候,flat_binder_object类对象的成员handle是文件描述符,cookie的值可能是1或者0,1代表进程拥有该文件描述符,接着判断是不是有效的匿名文件描述符,如果是,就关闭该进程打开的文件。

向Parcel其中写入Binder对象

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{return flattenBinder(val);
}
…………
status_t Parcel::flattenBinder(const sp<IBinder>& binder) {BBinder* local = nullptr;if (binder) local = binder->localBinder();if (local) local->setParceled();if (isForRpc()) {if (binder) {status_t status = writeInt32(1); // non-nullif (status != OK) return status;uint64_t address;// TODO(b/167966510): need to undo this if the Parcel is not sentstatus = mSession->state()->onBinderLeaving(mSession, binder, &address);if (status != OK) return status;status = writeUint64(address);if (status != OK) return status;} else {status_t status = writeInt32(0); // nullif (status != OK) return status;}return finishFlattenBinder(binder);}flat_binder_object obj;obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;int schedBits = 0;if (!IPCThreadState::self()->backgroundSchedulingDisabled()) {schedBits = schedPolicyMask(SCHED_NORMAL, 19);}if (binder != nullptr) {if (!local) {BpBinder *proxy = binder->remoteBinder();if (proxy == nullptr) {ALOGE("null proxy");} else {if (proxy->isRpcBinder()) {ALOGE("Sending a socket binder over kernel binder is prohibited");return INVALID_OPERATION;}}const int32_t handle = proxy ? proxy->getPrivateAccessor().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 {int policy = local->getMinSchedulerPolicy();int priority = local->getMinSchedulerPriority();if (policy != 0 || priority != 0) {// override value, since it is set explicitlyschedBits = schedPolicyMask(policy, priority);}if (local->isRequestingSid()) {obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;}if (local->isInheritRt()) {obj.flags |= FLAT_BINDER_FLAG_INHERIT_RT;}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);if (status != OK) return status;return finishFlattenBinder(binder);
}

  Binder对象在Parcel中,是用flat_binder_object对象来组织的。flattenBinder()函数首先调用参数binder->localBinder()得到BBinder对象,如果参数binder指向BBinder对象,则会得到对应的BBinder对象;如果参数binder指向BpBinder对象,则localBinder()会得到nullptr。
  代码29行,首先设置flags FLAT_BINDER_FLAG_ACCEPTS_FDS,代表接收文件描述符。局部变量是描述线程的调度策略及优先级的。如果没有禁止后台调度,则调用schedPolicyMask(SCHED_NORMAL, 19)得到。
  如果local为nullptr,则binder指向BpBinder对象。然后将obj.hdr.type = BINDER_TYPE_HANDLE,obj.handle = handle;如果binder指向BBinder对象,它明确指定了最小的调度策略及优先级,则调用schedPolicyMask(policy, priority)给schedBits重新赋值。FLAT_BINDER_FLAG_TXN_SECURITY_CTX代表发送方包含他的安全上下文,FLAT_BINDER_FLAG_INHERIT_RT代表BBinder从调用方继承了实时调度策略。后面接着就是设置obj.hdr.type = BINDER_TYPE_BINDER;obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());obj.cookie = reinterpret_cast<uintptr_t>(local);
  后面接着将schedBits的值放入obj.flags中进行传递。然后调用writeObject(obj, false)进行写入操作。最后调用finishFlattenBinder(binder)处理稳定性相关。
  看下writeObject(obj, false)

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;// remember if it's a file descriptorif (val.hdr.type == BINDER_TYPE_FD) {if (!mAllowFds) {// fail before modifying our object indexreturn FDS_NOT_ALLOWED;}mHasFds = mFdsKnown = true;}// Need to write meta-data?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;}if (!enoughObjects) {if (mObjectsSize > SIZE_MAX - 2) return NO_MEMORY; // overflowif ((mObjectsSize + 2) > SIZE_MAX / 3) return NO_MEMORY; // overflowsize_t newSize = ((mObjectsSize+2)*3)/2;if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflowbinder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));if (objects == nullptr) return NO_MEMORY;mObjects = objects;mObjectsCapacity = newSize;}goto restart_write;
}

  变量enoughData代表剩余的空间是否能写入Binder对象,enoughObjects代表Parcel中Binder对象的多少是否还没有超过容量大小。如果都是true,就可以向其中写入Binder对象,如果其中一个不是true,代表需要扩容。
  先看不扩容的情况,代码第7行,直接就在数据的当前位置mDataPos处放置flat_binder_object对象val。如果flat_binder_object对象里是一个文件描述符的话,将变量mHasFds、mFdsKnown都设置为true。接着判断是否向mObjects中写入Binder对象的位置。如果参数nullMetaData为true,就都记录对象位置。但是flattenBinder()函数传过来的参数nullMetaData为false,看其另外一个条件,val.binder != 0,这个情况对应前面的分析,就是指向的是BBinder对象的时候。因为指向的是BBinder对象的情况下,val.binder是0值。如果需要写入数据,则记录其位置mDataPos,并且调用acquire_object()增加相应的强计数次数,再将写入的mObjectsSize的值增加1。然后在调用finishWrite(size_t len)函数修改变量mDataPos、mDataSize的值。
  看一下扩容的情况,enoughData为false,调用growData(sizeof(val))进行扩容。

status_t Parcel::growData(size_t len)
{if (len > INT32_MAX) {// don't accept size_t values which may have come from an// inadvertent conversion from a negative int.return BAD_VALUE;}if (len > SIZE_MAX - mDataSize) return NO_MEMORY; // overflowif (mDataSize + len > SIZE_MAX / 3) return NO_MEMORY; // overflowsize_t newSize = ((mDataSize+len)*3)/2;return (newSize <= mDataSize)? (status_t) NO_MEMORY: continueWrite(std::max(newSize, (size_t) 128));
}

  可以看到如果新增的大小与目前数据大小相加大于SIZE_MAX / 3的情况下,就会报NO_MEMORY。然后,将扩充的容量调整为((mDataSize+len)*3)/2,相当于扩充到增加到的值得1.5倍。如果这个值没有溢出的话,就会接着调用continueWrite(std::max(newSize, (size_t) 128))。这个函数上面说过了。
  回到writeObject()中,接着看enoughObjects为false的情况,如果(mObjectsSize + 2) > SIZE_MAX / 3,就认为内存不足了,返回NO_MEMORY。然后将Binder对象数量扩充为 ((mObjectsSize+2)3)/2,就是原来的数量加上2的1.5倍。但是如果这个数量超过了SIZE_MAX / sizeof(binder_size_t),就返回NO_MEMORY。接着就是调用realloc(mObjects, newSizesizeof(binder_size_t))进行分配内存。然后再设置mObjects、mObjectsCapacity的值。
  扩容都做完了,就又走到代码第6行的标签,重新写入了。

  再看下finishFlattenBinder(binder):

status_t Parcel::finishFlattenBinder(const sp<IBinder>& binder)
{internal::Stability::tryMarkCompilationUnit(binder.get());int16_t rep = internal::Stability::getRepr(binder.get());return writeInt32(rep);
}

  这是写入Binder对象之后,会写入一个32位的整数。tryMarkCompilationUnit(binder.get())根据是否定义宏__ANDROID_VNDK__来决定是否将Level::VENDOR还是Level::SYSTEM设置给Binder对象的成员变量mStability。然后通过getRepr(binder.get())再将它取出,调用writeInt32(rep)将之写入Parcel对象中去。

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;
}

  writeInt32(int32_t val)是调用writeAligned(val),如果mDataPos加上sizeof(val)的值小于mDataCapacity,然后就将val放到mData的mDataPos处,然后调用finishWrite(sizeof(val)),这个函数前面讲过,略。如果容量不够,还是需要扩容,调用growData(),这个前面也讲过,扩容成功之后,再重新放置数据。

从Parcel中读取Binder对象

status_t Parcel::readStrongBinder(sp<IBinder>* val) const
{status_t status = readNullableStrongBinder(val);if (status == OK && !val->get()) {status = UNEXPECTED_NULL;}return status;
}

  调用readNullableStrongBinder(val),读取出来Binder,然后根据返回状态判断最终返回结果。
再看readNullableStrongBinder(val):

status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{return unflattenBinder(val);
}
…………
status_t Parcel::unflattenBinder(sp<IBinder>* out) const
{if (isForRpc()) {LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel");int32_t isPresent;status_t status = readInt32(&isPresent);if (status != OK) return status;sp<IBinder> binder;if (isPresent & 1) {uint64_t addr;if (status_t status = readUint64(&addr); status != OK) return status;if (status_t status = mSession->state()->onBinderEntering(mSession, addr, &binder);status != OK)return status;if (status_t status = mSession->state()->flushExcessBinderRefs(mSession, addr, binder);status != OK)return status;}return finishUnflattenBinder(binder, out);}const flat_binder_object* flat = readObject(false);if (flat) {switch (flat->hdr.type) {case BINDER_TYPE_BINDER: {sp<IBinder> binder =sp<IBinder>::fromExisting(reinterpret_cast<IBinder*>(flat->cookie));return finishUnflattenBinder(binder, out);}case BINDER_TYPE_HANDLE: {sp<IBinder> binder =ProcessState::self()->getStrongProxyForHandle(flat->handle);return finishUnflattenBinder(binder, out);}}}return BAD_TYPE;
}

  首先通过readObject(false)读取出来对象,然后通过类型对象进行处理。如果是BINDER_TYPE_BINDER类型,我们知道flat->cookie指向对应的BBinder对象的地址,我们得到对象的对象,然后调用finishUnflattenBinder(binder, out)方法;如果是BINDER_TYPE_HANDLE类型,通过flat->handle在ProcessState对象中找到对应的BpBinder对象,getStrongProxyForHandle()在前面分析过,最后也是调用finishUnflattenBinder(binder, out)进行最后的处理。
  先来看看readObject(false):

const flat_binder_object* Parcel::readObject(bool nullMetaData) const
{const size_t DPOS = mDataPos;if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {const flat_binder_object* obj= reinterpret_cast<const flat_binder_object*>(mData+DPOS);mDataPos = DPOS + sizeof(flat_binder_object);if (!nullMetaData && (obj->cookie == 0 && obj->binder == 0)) {// When transferring a NULL object, we don't write it into// the object list, so we don't want to check for it when// reading.ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos);return obj;}// Ensure that this object is valid...binder_size_t* const OBJS = mObjects;const size_t N = mObjectsSize;size_t opos = mNextObjectHint;if (N > 0) {ALOGV("Parcel %p looking for obj at %zu, hint=%zu",this, DPOS, opos);// Start at the current hint position, looking for an object at// the current data position.if (opos < N) {while (opos < (N-1) && OBJS[opos] < DPOS) {opos++;}} else {opos = N-1;}if (OBJS[opos] == DPOS) {// Found it!ALOGV("Parcel %p found obj %zu at index %zu with forward search",this, DPOS, opos);mNextObjectHint = opos+1;ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos);return obj;}// Look backwards for it...while (opos > 0 && OBJS[opos] > DPOS) {opos--;}if (OBJS[opos] == DPOS) {// Found it!ALOGV("Parcel %p found obj %zu at index %zu with backward search",this, DPOS, opos);mNextObjectHint = opos+1;ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos);return obj;}}ALOGW("Attempt to read object from Parcel %p at offset %zu that is not in the object list",this, DPOS);}return nullptr;
}

  该方法是从当前位置读取出来flat_binder_object对象,如果当前位置加上flat_binder_object类大小没超过数据范围,就从当前位置将flat_binder_object对象取出。然后将数据的当前位置加上flat_binder_object类大小。
  代码第8行,参数nullMetaData为false,如果obj->cookie == 0 && obj->binder == 0,前面讲writeObject()的时候,BpBinder对象是符合这种情况的,并且这种情况,是没有向mObjects中写入相应位置的,所以在这里就直接返回了。
  剩下的这些操作,是为了确保读出来的Binder对象,是能在mObjects中找到对应位置的。其中mNextObjectHint变量是为了记录之前找到对象的下一个位置。如果能找到对应的相等的位置,认为找到了结果。不然会返回nullptr。
  接着再看finishUnflattenBinder(binder, out):

status_t Parcel::finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const
{int32_t stability;status_t status = readInt32(&stability);if (status != OK) return status;status = internal::Stability::setRepr(binder.get(), static_cast<int16_t>(stability),true /*log*/);if (status != OK) return status;*out = binder;return OK;
}

  前面讲finishFlattenBinder(binder)的时候,在写入Binder对象之后,还写入了一个32位的整数,这块将其读出来进行验证。如果写入和读出来的不一致,会返回错误状态。

Android C++ Parcel相关推荐

  1. Android 数据Parcel序列化过程源码分析

    在Android系统中,所有的服务都必须注册到ServiceManger中,当客户进程需要请求某一服务时,首先从服务管家ServiceManger中查找出该服务,然后通过RPC远程调用的方式使用该服务 ...

  2. Android之Parcel和Parcelable

    总结: Parcel 类是一个容器,能装各种类型的数据,并能在C/CPP底层传输. Parcel 可以在Binder 驱动为不同进程实现数据交互,为什么它能充当这样的角色呢? 系统设计使然.虽然不同进 ...

  3. Android中Parcel的分析以及使用

    简单点来说:Parcel就是一个存放读取数据的容器, android系统中的binder进程间通信(IPC)就使用了Parcel类来进行客户端与服务端数据的交互,而且AIDL的数据也是通过Parcel ...

  4. Android中Parcel的解读

    Parcel,翻译过来是"打包"的意思.打包干什么呢?是为了序列化. 如果要在进程之间传递一个整数,很简单,直接传就是行了:如果要传一个字符串,就稍微复杂了点:需先分配一块可以容纳 ...

  5. android uri parcel,Android ParcelFileDescriptor实现进程间通信

    需求 一个通信通道,实现跨进程的的Socket网络通信. 具体的通信通道的图如下. 需求分析 我们需要一个进程一直做通信通道的事情,业务进程把数据通过进程间通信交给通信进程. 通信进程通过Socket ...

  6. Android中Parcel的分析和使用

    http://www.360doc.com/content/13/0419/12/9171956_279433672.shtml

  7. 探索Android中的Parcel机制(上)

    一.先从Serialize说起 我们都知道JAVA中的Serialize机制,译成串行化.序列化--,其作用是能将数据对象存入字节流其中,在须要时又一次生成对象.主要应用是利用外部存储设备保存对象状态 ...

  8. 探索Android中的Parcel机制(上) .

    一.先从Serialize说起 我们都知道JAVA中的Serialize机制,译成串行化.序列化--,其作用是能将数据对象存入字节流当中,在需要时重新生成对象.主要应用是利用外部存储设备保存对象状态, ...

  9. android 进程间通信数据(一)------parcel的起源

    关于parcel,我们先来讲讲它的"父辈" Serialize. Serialize 是java提供的一套序列化机制.但是为什么要序列化,怎么序列化,序列化是怎么做到的,我们将在本 ...

  10. Android之提示java.lang.RuntimeException: Parcel: unable to marshal value Image问题

    1 问题 使用Intent携带数据(putExtra)跳转activity,提示如下错误 04-18 22:42:49.664 16194 16194 E AndroidRuntime: Proces ...

最新文章

  1. Docker数据卷管理
  2. git报错:remote: warning: Large files detected.
  3. (转载)各Linux发行版本 网络配置文件
  4. 干货 | 神经网络与深度学习精选文章汇总
  5. Oracle ODP.NET数据库访问连接字符串
  6. Cisco ASR1002-X告警处理
  7. android l camera no panorama,Android Camera从App层到framework层到HAL层的初始化过程
  8. php intdiv(),PHP intdiv()函数使用方法
  9. 乾颐堂军哥HCIE9-解决BGP路由黑洞、聚合的各种参数以及RR基础
  10. 差点被开除:一次订单号重复的事故
  11. 04.spring boot配置文件--yml
  12. 韩信点兵python算法_韩信点兵算法流程图
  13. box-sizing属性的理解
  14. 怎么选择靠谱Java培训机构?
  15. 数据结构——邻接表Adjacency List
  16. ERROR 1366 (HY000): Incorrect string value: '\xE8\xB5\xB5\xE9\x9B\xB7' for column 'Sname' at row 1
  17. SDN 交换机迁移1
  18. java web 编辑器_22个所见即所得在线 Web 编辑器
  19. 2021,同城货运战火依旧
  20. Java面试题整理一(反射)

热门文章

  1. 【听】蔡康永的说话之道,说话的技巧方法论
  2. python常见的缩进错误_python常见编译错误:IndentationError缩进错误
  3. 从蚂蚁的觅食过程看团队研发(转载)
  4. 关于MySql中explain结果filtered的理解
  5. 哈霍兰服务器修改WCL记录,魔兽世界:怀旧服哈霍兰服务器再创纪录,最强“刷子”六天刷出420万荣誉...
  6. vue + Electron 制作桌面应用
  7. (边学边练)JAVA基础学习第三天
  8. python爬虫英文单词_利用PYTHON 爬虫爬出自己的英语单词库
  9. 阿里达摩院——算法面经
  10. elasticsearch索引health 健康状态变为yellow,red处理