首页 > 代码库 > android分析之Parcel

android分析之Parcel

将数据打包,跨进程传输(通过Binder)。看看这货究竟是啥玩意:

Parcel.java :

public final class Parcel {    private static final boolean DEBUG_RECYCLE = false;    private static final String TAG = "Parcel";    @SuppressWarnings({"UnusedDeclaration"})    private int mNativePtr; // used by native code,非static     /**     * Flag indicating if {@link #mNativePtr} was allocated by this object,     * indicating that we‘re responsible for its lifecycle.     */    private boolean mOwnsNativeParcelObject;//非static,从上面解释可以看到,它标识"mNativePtr”是否可用,如果是从NativeCode分配的,则要负责它的生命周期    private RuntimeException mStack;    private static final int POOL_SIZE = 6;    private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];//static,类拥有,下同。作为Parcel的缓冲池使用。    private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];

  下面看调用Parcel的obtain()时的过程:

    static protected final Parcel obtain() {        final Parcel[] pool = sHolderPool;//尝试从sHolderPool这个缓冲池取        synchronized (pool) {            Parcel p;            for (int i=0; i<POOL_SIZE; i++) {//POOL_SIZE为6                p = pool[i];                if (p != null) {                    pool[i] = null;                    if (DEBUG_RECYCLE) {                        p.mStack = new RuntimeException();                    }                    p.init(obj);//找到一个可用的(非null),初始化这个Parcel                    return p;                }            }        }        return new Parcel(0);//如果6个都不可用(即缓冲池空了),则新new一个出来    }    private Parcel(int nativePtr) {        if (DEBUG_RECYCLE) {            mStack = new RuntimeException();        }        //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);        init(nativePtr);//简单调用    }    private void init(int nativePtr) {        if (nativePtr != 0) {            mNativePtr = nativePtr;            mOwnsNativeParcelObject = false;        } else {            mNativePtr = nativeCreate();//调用Native CODE            mOwnsNativeParcelObject = true;//表明,需要负责本Parcel对象的生命周期。后面有几个方法会根据该boolean值决定是否释放Native CODE生成的对象。        }    }

  小结:Parcel(.java)逻辑很简单,从sHolderPool或者sOwnedPool中找不等于null的,取出来重新使用。否则,调用Native Code重新生成一个Parcel。在这里,有mNativePtr和mOwnsNativeParcelObject两个对象的成员变量,用来标识所生成的Native层的Parcel是否需要释放/销毁。

Parcel.h(.cpp)分析:

在Parcel.h中,存在许多字段。实际上,可以将Parcel看作管理一块内存的一个管理者。

    status_t            mError;    uint8_t*            mData;//指针,从字面上看应该是指向数据的指针    size_t              mDataSize;//表明数据大小,已经存储的数据大小    size_t              mDataCapacity;//应该是内存空间的容量    mutable size_t      mDataPos;//mutable修饰,说明这个变量要及时反映出最新值,类比数组中position下标
size_t* mObjects;//指针,可以看作数组。其存储的是每个保存在Parcel对象所申请的内存的大小 size_t mObjectsSize;//与上面数组配合使用 size_t mObjectsCapacity; mutable size_t mNextObjectHint; mutable bool mFdsKnown; mutable bool mHasFds; bool mAllowFds; release_func mOwner; void* mOwnerCookie;

  从上面各个字段来看,还是很经典的内存管理方式,这样一般有:内存起始地址(对应上面mData)、内存总容量(对应mDataCapacity)、内存已用容量(对应mDataSize)、当前可用的内存位置(mDataPos)。在Parcel里还更加细分了,每个存储在内存中的对象大小。粒度更细。

Parcel::Parcel()//构造函数{    initState();}...void Parcel::initState()//简单给各个成员变量赋初值{    mError = NO_ERROR;    mData = http://www.mamicode.com/0;"initState Setting data size of %p to %d\n", this, mDataSize);    ALOGV("initState Setting data pos of %p to %d\n", this, mDataPos);    mObjects = NULL;    mObjectsSize = 0;    mObjectsCapacity = 0;    mNextObjectHint = 0;    mHasFds = false;    mFdsKnown = true;    mAllowFds = true;    mOwner = NULL;}

  在setDataCapacity、setDataSize等函数中,调用到continueWrite,这个函数是真正的申请内存函数:

status_t Parcel::continueWrite(size_t desired){    // If shrinking, first adjust for any objects that appear    // after the new data size.    size_t objectsSize = mObjectsSize;    if (desired < mDataSize) {//表明需要缩小申请的内存容量        if (desired == 0) {            objectsSize = 0;        } else {            while (objectsSize > 0) {                if (mObjects[objectsSize-1] < desired)//找到一个对象的内存大小小于所要申请的内存大小                    break;                objectsSize--;            }        }    }        if (mOwner) {//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 = http://www.mamicode.com/(uint8_t*)malloc(desired);//分配内存"Freeing data ref of %p (pid=%d)\n", this, getpid());        mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);        mOwner = NULL;        mData = http://www.mamicode.com/data;"continueWrite Setting data size of %p to %d\n", this, mDataSize);        mDataCapacity = desired;        mObjectsSize = mObjectsCapacity = objectsSize;        mNextObjectHint = 0;    } else if (mData) {        if (objectsSize < mObjectsSize) {            // Need to release refs on any objects we are dropping.            const sp<ProcessState> proc(ProcessState::self());            for (size_t i=objectsSize; i<mObjectsSize; i++) {                const flat_binder_object* flat                    = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);                if (flat->type == BINDER_TYPE_FD) {                    // will need to rescan because we may have lopped off the only FDs                    mFdsKnown = false;                }                release_object(proc, *flat, this);//尝试释放对象            }            size_t* objects =                (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));            if (objects) {                mObjects = objects;            }            mObjectsSize = objectsSize;            mNextObjectHint = 0;        }        // We own the data, so we can just do a realloc().        if (desired > mDataCapacity) {            uint8_t* data = http://www.mamicode.com/(uint8_t*)realloc(mData, desired);//在原mData位置上重新分配内存"continueWrite Setting data size of %p to %d\n", this, mDataSize);            }            if (mDataPos > desired) {                mDataPos = desired;                ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);            }        }            } else {        // This is the first data.  Easy!        uint8_t* data = http://www.mamicode.com/(uint8_t*)malloc(desired);//直接申请所需大小"continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);        }                mData = http://www.mamicode.com/data;"continueWrite Setting data size of %p to %d\n", this, mDataSize);        ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);        mDataCapacity = desired;    }    return NO_ERROR;}

  小结:上面内存分配管理比较细致,总的来说就是“要么新申请一块内存”、“要么复用一块内存”,“释放内存”,外加对象的生命周期的控制。

 

android分析之Parcel