Android C++ Parcel
作者:互联网
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::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。
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) { // 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代表进程拥有该文件描述符,接着判断是不是有效的匿名文件描述符,如果是,就关闭该进程打开的文件。
向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-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(),这个前面也讲过,扩容成功之后,再重新放置数据。
从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位的整数,这块将其读出来进行验证。如果写入和读出来的不一致,会返回错误状态。
标签:status,return,Parcel,C++,binder,obj,Android,size 来源: https://blog.csdn.net/q1165328963/article/details/122805489