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是释放内存的方法,可能设置,也可能不设置。
Android C++ Parcel

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 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, 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) { // 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位的整数,这块将其读出来进行验证。如果写入和读出来的不一致,会返回错误状态。

上一篇:Android程序异常退出,本地保存错误信息到文件中


下一篇:如何学习数学建模