android分析之Parcel
阅读原文时间:2023年07月11日阅读:2

将数据打包,跨进程传输(通过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 = 0;
mDataSize = 0;
mDataCapacity = 0;
mDataPos = 0;
ALOGV("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 = (uint8\_t\*)malloc(desired);//分配内存  
    if (!data) {  
        mError = NO\_MEMORY;  
        return NO\_MEMORY;  
    }  
    size\_t\* objects = NULL;

    if (objectsSize) {  
        objects = (size\_t\*)malloc(objectsSize\*sizeof(size\_t));//分配objectSize\*sizeof(size\_t)大小的内存  
        if (!objects) {  
            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);//拷贝到data(新申请的)  
    }  
    if (objects && mObjects) {  
        memcpy(objects, mObjects, objectsSize\*sizeof(size\_t));  
    }  
    //ALOGI("Freeing data ref of %p (pid=%d)\\n", this, getpid());  
    mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);  
    mOwner = NULL;

    mData = data;  
    mObjects = objects;  
    mDataSize = (mDataSize < desired) ? mDataSize : desired;  
    ALOGV("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 = (uint8\_t\*)realloc(mData, desired);//在原mData位置上重新分配内存  
        if (data) {  
            mData = data;  
            mDataCapacity = desired;  
        } else if (desired > mDataCapacity) {  
            mError = NO\_MEMORY;  
            return NO\_MEMORY;  
        }  
    } else {  
        if (mDataSize > desired) {  
            mDataSize = desired;  
            ALOGV("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 = (uint8\_t\*)malloc(desired);//直接申请所需大小  
    if (!data) {  
        mError = NO\_MEMORY;  
        return NO\_MEMORY;  
    }

    if(!(mDataCapacity == 0 && mObjects == NULL  
         && mObjectsCapacity == 0)) {  
        ALOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);  
    }

    mData = data;  
    mDataSize = mDataPos = 0;  
    ALOGV("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;  

}

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

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章