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

Parcel.java :

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

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

  1. static protected final Parcel obtain() {
  2. final Parcel[] pool = sHolderPool;//尝试从sHolderPool这个缓冲池取
  3. synchronized (pool) {
  4. Parcel p;
  5. for (int i=0; i<POOL_SIZE; i++) {//POOL_SIZE为6
  6. p = pool[i];
  7. if (p != null) {
  8. pool[i] = null;
  9. if (DEBUG_RECYCLE) {
  10. p.mStack = new RuntimeException();
  11. }
  12. p.init(obj);//找到一个可用的(非null),初始化这个Parcel
  13. return p;
  14. }
  15. }
  16. }
  17. return new Parcel(0);//如果6个都不可用(即缓冲池空了),则新new一个出来
  18. }
  19.  
  20. private Parcel(int nativePtr) {
  21. if (DEBUG_RECYCLE) {
  22. mStack = new RuntimeException();
  23. }
  24. //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);
  25. init(nativePtr);//简单调用
  26. }
  27.  
  28. private void init(int nativePtr) {
  29. if (nativePtr != 0) {
  30. mNativePtr = nativePtr;
  31. mOwnsNativeParcelObject = false;
  32. } else {
  33. mNativePtr = nativeCreate();//调用Native CODE
  34. mOwnsNativeParcelObject = true;//表明,需要负责本Parcel对象的生命周期。后面有几个方法会根据该boolean值决定是否释放Native CODE生成的对象。
  35. }
  36. }

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

Parcel.h(.cpp)分析:

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

  1. status_t mError;
  2. uint8_t* mData;//指针,从字面上看应该是指向数据的指针
  3. size_t mDataSize;//表明数据大小,已经存储的数据大小
  4. size_t mDataCapacity;//应该是内存空间的容量
  5. mutable size_t mDataPos;//mutable修饰,说明这个变量要及时反映出最新值,类比数组中position下标

  6. size_t* mObjects;//指针,可以看作数组。其存储的是每个保存在Parcel对象所申请的内存的大小
  7. size_t mObjectsSize;//与上面数组配合使用
  8. size_t mObjectsCapacity;
  9. mutable size_t mNextObjectHint;
  10.  
  11. mutable bool mFdsKnown;
  12. mutable bool mHasFds;
  13. bool mAllowFds;
  14.  
  15. release_func mOwner;
  16. void* mOwnerCookie;

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

  1. Parcel::Parcel()//构造函数
  2. {
  3. initState();
  4. }
  5. ...
  6. void Parcel::initState()//简单给各个成员变量赋初值
  7. {
  8. mError = NO_ERROR;
  9. mData = 0;
  10. mDataSize = 0;
  11. mDataCapacity = 0;
  12. mDataPos = 0;
  13. ALOGV("initState Setting data size of %p to %d\n", this, mDataSize);
  14. ALOGV("initState Setting data pos of %p to %d\n", this, mDataPos);
  15. mObjects = NULL;
  16. mObjectsSize = 0;
  17. mObjectsCapacity = 0;
  18. mNextObjectHint = 0;
  19. mHasFds = false;
  20. mFdsKnown = true;
  21. mAllowFds = true;
  22. mOwner = NULL;
  23. }

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

  1. status_t Parcel::continueWrite(size_t desired)
  2. {
  3. // If shrinking, first adjust for any objects that appear
  4. // after the new data size.
  5. size_t objectsSize = mObjectsSize;
  6. if (desired < mDataSize) {//表明需要缩小申请的内存容量
  7. if (desired == 0) {
  8. objectsSize = 0;
  9. } else {
  10. while (objectsSize > 0) {
  11. if (mObjects[objectsSize-1] < desired)//找到一个对象的内存大小小于所要申请的内存大小
  12. break;
  13. objectsSize--;
  14. }
  15. }
  16. }
  17.  
  18. if (mOwner) {//mOwner是一个回调函数指针
  19. // If the size is going to zero, just release the owner's data.
  20. if (desired == 0) {
  21. freeData();//释放数据
  22. return NO_ERROR;
  23. }
  24.  
  25. // If there is a different owner, we need to take
  26. // posession.
  27. uint8_t* data = (uint8_t*)malloc(desired);//分配内存
  28. if (!data) {
  29. mError = NO_MEMORY;
  30. return NO_MEMORY;
  31. }
  32. size_t* objects = NULL;
  33.  
  34. if (objectsSize) {
  35. objects = (size_t*)malloc(objectsSize*sizeof(size_t));//分配objectSize*sizeof(size_t)大小的内存
  36. if (!objects) {
  37. mError = NO_MEMORY;
  38. return NO_MEMORY;
  39. }
  40.  
  41. // Little hack to only acquire references on objects
  42. // we will be keeping.
  43. size_t oldObjectsSize = mObjectsSize;
  44. mObjectsSize = objectsSize;
  45. acquireObjects();//给各个对象增加强、弱引用计数——加入需要的话
  46. mObjectsSize = oldObjectsSize;
  47. }
  48.  
  49. if (mData) {
  50. memcpy(data, mData, mDataSize < desired ? mDataSize : desired);//拷贝到data(新申请的)
  51. }
  52. if (objects && mObjects) {
  53. memcpy(objects, mObjects, objectsSize*sizeof(size_t));
  54. }
  55. //ALOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
  56. mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
  57. mOwner = NULL;
  58.  
  59. mData = data;
  60. mObjects = objects;
  61. mDataSize = (mDataSize < desired) ? mDataSize : desired;
  62. ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
  63. mDataCapacity = desired;
  64. mObjectsSize = mObjectsCapacity = objectsSize;
  65. mNextObjectHint = 0;
  66.  
  67. } else if (mData) {
  68. if (objectsSize < mObjectsSize) {
  69. // Need to release refs on any objects we are dropping.
  70. const sp<ProcessState> proc(ProcessState::self());
  71. for (size_t i=objectsSize; i<mObjectsSize; i++) {
  72. const flat_binder_object* flat
  73. = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
  74. if (flat->type == BINDER_TYPE_FD) {
  75. // will need to rescan because we may have lopped off the only FDs
  76. mFdsKnown = false;
  77. }
  78. release_object(proc, *flat, this);//尝试释放对象
  79. }
  80. size_t* objects =
  81. (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
  82. if (objects) {
  83. mObjects = objects;
  84. }
  85. mObjectsSize = objectsSize;
  86. mNextObjectHint = 0;
  87. }
  88.  
  89. // We own the data, so we can just do a realloc().
  90. if (desired > mDataCapacity) {
  91. uint8_t* data = (uint8_t*)realloc(mData, desired);//在原mData位置上重新分配内存
  92. if (data) {
  93. mData = data;
  94. mDataCapacity = desired;
  95. } else if (desired > mDataCapacity) {
  96. mError = NO_MEMORY;
  97. return NO_MEMORY;
  98. }
  99. } else {
  100. if (mDataSize > desired) {
  101. mDataSize = desired;
  102. ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
  103. }
  104. if (mDataPos > desired) {
  105. mDataPos = desired;
  106. ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
  107. }
  108. }
  109.  
  110. } else {
  111. // This is the first data. Easy!
  112. uint8_t* data = (uint8_t*)malloc(desired);//直接申请所需大小
  113. if (!data) {
  114. mError = NO_MEMORY;
  115. return NO_MEMORY;
  116. }
  117.  
  118. if(!(mDataCapacity == 0 && mObjects == NULL
  119. && mObjectsCapacity == 0)) {
  120. ALOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
  121. }
  122.  
  123. mData = data;
  124. mDataSize = mDataPos = 0;
  125. ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
  126. ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
  127. mDataCapacity = desired;
  128. }
  129.  
  130. return NO_ERROR;
  131. }

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

android分析之Parcel的更多相关文章

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

    Android中的Parcel机制    实现了Bundle传递对象    使用Bundle传递对象,首先要将其序列化,但是,在Android中要使用这种传递对象的方式需要用到Android Parc ...

  2. 探索Android中的Parcel机制(上)

    一.先从Serialize说起 我们都知道JAVA中的Serialize机制,译成串行化.序列化……,其作用是能将数据对象存入字节流其中,在须要时又一次生成对象.主要应用是利用外部存储设备保存对象状态 ...

  3. Android中的Parcel机制(上)

    一.先从Serialize说起 我们都知道JAVA中的Serialize机制,译成串行化.序列化--,其作用是能将数据对象存入字节流当中,在需要时重新生成对象.主要应用是利用外部存储设备保存对象状态, ...

  4. android分析之Binder 01

    终于还是得写一篇关于Binder的文章了.从最初接触Android到花大把时间研究Android源码,Binder一直是分析道路的拦路虎.看了几本最流行的Android源码分析书籍,每次基本上都不能把 ...

  5. Android 分析工具 APKAnalyser

    APKAnalyser 是 Android 静态,虚拟分析工具,用来测试和验证 Android 应用的开发工作.ApkAnalyser 是个完整的工具链,可以修改二进制应用.用户可以改装,安装,运行, ...

  6. cocos android分析

    来自:http://xiebaochun.github.io/ cocos2d-x Android环境搭建 cocos2d-x环境搭建比較简单,可是小问题还是不少,我尽量都涵盖的全面一些. 下载软件  ...

  7. Android分析应用程序的构建过程

    为了方便Android应用开发要求我们Androidproject编制和包装有了更深入的了解,例如,我们知道这是做什么的每一步,境和工具.输入和输出是什么.等等. 在前文<命令行下Android ...

  8. android分析windowManager、window、viewGroup之间关系(二)

    三.接上一节,分析windowManager中添加一个悬浮框的方式,首先看代码 WindowManager.LayoutParams params = new LayoutParams(); para ...

  9. android分析windowManager、window、viewGroup之间关系(一)

    本文将主要介绍addview方法,在windowManager.window.viewGroup中的实现原理.首先将介绍这些类结构关系,然后分析其内在联系,介绍实现原理,最后介绍重要的一个参数wind ...

随机推荐

  1. spring再学习之AOP实操

    一.spring导包 2.目标对象 public class UserServiceImpl implements UserService { @Override public void save() ...

  2. 创建AVL树,插入,删除,输出Kth Min

    https://github.com/TouwaErioH/subjects/tree/master/C%2B%2B/PA2 没有考虑重复键,可以在结构体内加一个int times. 没有考虑删除不存 ...

  3. Python源码剖析——01内建对象

    <Python源码剖析>笔记 第一章:对象初识 对象是Python中的核心概念,面向对象中的"类"和"对象"在Python中的概念都为对象,具体分为 ...

  4. Prettier All In One

    Prettier All In One .prettierrc.js / .prettierrc / .prettierrc.json module.exports = { singleQuote: ...

  5. javascript 克隆对象/数组的方法 clone()

      1 11 javascript 克隆对象/数组的方法 clone() 1 demo: code: 1 var Obj; 2 let clone = (Obj) => { 3 var buf; ...

  6. website URL & UTM

    website URL & UTM UTM user track message utm_source https://zhuanlan.zhihu.com/p/143473571?utm_s ...

  7. STAR 法则

    STAR 法则 STAR: Situation, Task, Action, Result 一. 什么是 STAR 法则? STAR法则是情境(situation).任务(task).行动(actio ...

  8. React Native Apps

    React Native Apps https://github.com/ReactNativeNews/React-Native-Apps github app https://github.com ...

  9. 算法型稳定币USDN是如何保持稳定的?

    数据显示,2019年稳定币市场总市值25亿美元,在整个加密货币市场占比 1.3%.可别小瞧了看似微小的1.3%这个数据,它其实是一个庞大的市场.稳定币不仅仅是货币的电子化,它还是一种可编程的加密货币, ...

  10. BGV币与YFI币、YFII币存在着怎样的相关性?

    大多数的玩家并没有长期的打算,而是更倾向于关注短期利好的币种.比如最近在圈内赚足眼球的YFI,之所以能够成为明星角色,并非它的技术和平台,而是因为它在短期就创造了86倍的暴涨.YFI币的暴涨在某种程度 ...