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 deallocated mutable bool mDeallocZero; release_func mOwner; …………………… };
成员变量mData指向存储数据的内存位置,mDataSize是数据的大小,mDataCapacity是存储内存的容量,mDataPos是相对于mData位置,数据目前存放到的位置。
mObjects是为了保存Binder类对象地址使用的(这个地址是相对于mData),mObjectsSize数据里面保存的Binder类对象的数量,mObjectsCapacity是内存中可以保存Binder类对象的大小容量。
成员变量mOwner是释放内存的方法,可能设置,也可能不设置。
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 write if (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 FDs mFdsKnown = 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, objectsSizesizeof(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。
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) { // owned if ((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代表进程拥有该文件描述符,接着判断是不是有效的匿名文件描述符,如果是,就关闭该进程打开的文件。
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-null if (status != OK) return status; uint64_t address; // TODO(b/167966510): need to undo this if the Parcel is not sent status = 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); // null if (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 explicitly schedBits = 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 descriptor if (val.hdr.type == BINDER_TYPE_FD) { if (!mAllowFds) { // fail before modifying our object index return 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; // overflow if ((mObjectsSize + 2) > SIZE_MAX / 3) return NO_MEMORY; // overflow size_t newSize = ((mObjectsSize+2)*3)/2; if (newSize > SIZE_MAX / sizeof(binder_size_t)) return NO_MEMORY; // overflow binder_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; // overflow if (mDataSize + len > SIZE_MAX / 3) return NO_MEMORY; // overflow size_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(),这个前面也讲过,扩容成功之后,再重新放置数据。
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位的整数,这块将其读出来进行验证。如果写入和读出来的不一致,会返回错误状态。