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 = 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;
}

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

时间: 2024-10-13 05:05:42

android分析之Parcel的相关文章

Android Binder机制分析(4) Parcel类分析

引言 在上一篇Blog中,在分析服务注册过程时,往data(Parcel对象)变量写入数据时,有这样的调用路径: BpServiceManager::addService()–>Parcel::writeStrongBinder()–>flatten_binder()–>finish_flatten_binder() 由于finish_flatten_binder()方法中涉及到的东西太多,在上一篇博客就没有展开来讲.这篇博客将详细分析数据是如何写入到data中的. 下面是Parcel类

Android中的Parcel机制 实现Bundle传递对象

Android中的Parcel机制    实现了Bundle传递对象    使用Bundle传递对象,首先要将其序列化,但是,在Android中要使用这种传递对象的方式需要用到Android Parcel机制,即,Android实现的轻量级的高效的对象序列化和反序列化机制. JAVA中的Serialize机制,译成串行化.序列化……,其作用是能将数据对象存入字节流当中,在需要时重新生成对象.主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等.        Android中的新的序列

cocos android分析

cocos2d-x Android环境搭建 cocos2d-x环境搭建比较简单,但是小问题还是不少,我尽量都涵盖的全面一些. 下载软件 cygwin.NDK(ADT):C++相关 如果之前没有Android开发环境,还需要Android SDK,Eclipse cocos2d-x源码 我的环境为ndk r7,cygwin1.7,Android SDK为2.2和3.0.另外,我是通过真机调试,在模拟器上不行,估计还是我T410显卡的问题. 安装cygwin,在cygwin文件进行路径设置 在cyg

探索Android中的Parcel机制(上)

一.先从Serialize说起 我们都知道JAVA中的Serialize机制,译成串行化.序列化……,其作用是能将数据对象存入字节流其中,在须要时又一次生成对象.主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等. 二.Android中的新的序列化机制 在Android系统中,定位为针对内存受限的设备,因此对性能要求更高,另外系统中採用了新的IPC(进程间通信)机制,必定要求使用性能更出色的对象传输方式.在这种环境下,Parcel被设计出来,其定位就是轻量级的高效的对象序列化和反序列

探索Android中的Parcel机制(下)

上一篇中我们透过源码看到了Parcel背后的机制,本质上把它当成一个Serialize就可以了,只是它是在内存中完成的序列化和反序列化,利用的是连续的内存空间,因此会更加高效. 我们接下来要说的是Parcel类如何应用.就应用程序而言,最常见使用Parcel类的场景就是在Activity间传递数据.没错,在Activity间使用Intent传递数据的时候,可以通过Parcelable机制传递复杂的对象. 在下面的程序中,MyColor用于保存一个颜色值,MainActivity在用户点击屏幕时将

Android分析第三方应用layout的神器

hierarchyviewer.bat或者monitor.bat一直都是分析layout的神器,不过,很多时候不好用,连不上真机,害的我不得不使用模拟器来分析layout. 今天发现了另外一个申请,就在ADT里面,它就躺在那,我怎么一直就没发现? Dump View Hierarchy for UI Automator Android分析第三方应用layout的神器

android分析之Binder 01

终于还是得写一篇关于Binder的文章了.从最初接触Android到花大把时间研究Android源码,Binder一直是分析道路的拦路虎.看了几本最流行的Android源码分析书籍,每次基本上都不能把Binder相关知识看完.读透.好在一直没有放弃,第一次理解不了就跳过,下一次重新读,每次读都有新的收获.现在是时候整理整理了. 我理解的Binder是什么?一种IPC(跨进程通信)的实现方式.注意“跨进程”,表明数据从一个进程“流向”了另一个进程.首先要了解为什么跨进程那么难?因为应用程序的地址空

android分析之消息处理

前序:每个APP对应一个进程,该进程内有一个ActivityThread的线程,称为主线程(即UI主线程),此外,还有其他线程,这个再论. android的消息系统分析. 每个Thread只对应一个Looper 每个Looper只对应一个MessageQueue 每个MessageQueue中有N个Message 每个Message中最多指定一个Handler来处理事件 一个Thread可以对应多个Handler Looper负责从消息队列中(MessageQueue)取出消息(Message/

android分析之Binder 02

分析Java层的ServiceManager,看看Binder在Java层是如何实现的. public final class ServiceManager { private static final String TAG = "ServiceManager"; private static IServiceManager sServiceManager;//IserviceManager是一个接口,定义了通用(公共)方法. private static HashMap<Str