Binder 解析之 Parcel 理解(三)

1,654 阅读15分钟

背景

在继续深入理解Binder机制前,我们很有必要对Parcel进行学习。

一、Parcel 为何物?

Parcel翻译过来是"包裹"的意思,其实就是个智能化数据容器。它提供了一种能力:将各种类型的数据对象的引用在A进程中打包,经过Binder机制实现跨进程的传递,然后在B进程中解包出来。作为数据的载体,Parcel自动帮你完成打包、解压的过程。

Parcel 进程A打包的数据,和进程B得到数据是同一个份吗

  1. 如果打包的是数据本身,那么肯定不是。数据在内存中存储,A进程的内存空进和B进程的内存空进肯定不想通的。因此,数据或者引用肯定不是A进程的数据或引用,传入A进程的地址肯定不可行。

    • 如果是同一个进程中使用Parcel,也会把数据Student先拆解,拷贝到Parcel的内存中,然后从parcel的内存中根据各个字段,再恢复创建另一个对象Student。再回收Parcel容器的内存。因此,同一个进程不建议使用parcel,内存浪费、效率低。

    • 如果是不同进程,进程A把数据Student先拆解,拷贝到Parcel的内存中。然后再把Parcel内存中的数据拷贝到内核空间,释放Parcel内存。 进程B从内核空间直接读取数据,得到一个进程B中的parcel对象,从parcel对象中根据各个字段再恢复创建一个Student对象。此时,student对象就在B进程了。看起来好像是A进程的student对象传递到了进程B。

二、Parcel支持的传递数据类型

2.1 基本类型

private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len);
private static native void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len);
@FastNative
private static native void nativeWriteInt(long nativePtr, int val);
@FastNative
private static native void nativeWriteLong(long nativePtr, long val);
@FastNative
private static native void nativeWriteFloat(long nativePtr, float val);
@FastNative
private static native void nativeWriteDouble(long nativePtr, double val);
static native void nativeWriteString(long nativePtr, String val);


支持int、string、float、double等基本数据类型的读写。

2.2 Parcelables


/**
 * Flatten the name of the class of the Parcelable and its contents
 * into the parcel.
public final void writeParcelable(Parcelable p, int parcelableFlags) {
    if (p == null) {
        writeString(null);
        return;
    }
    writeParcelableCreator(p);
    //writeToParcel()把自定义对象的数据写入parcel中 
    p.writeToParcel(this, parcelableFlags);
}

支持实现了parcelable接口的自定义对象的写入。如:intent、student等。


/**
 * Read and return a new Parcelable from the parcel.  The given class loader
 * will be used to load any enclosed Parcelables.  If it is null, the default
 * class loader will be used.
 */
 // 创建一个新的自定义对象 
@SuppressWarnings("unchecked")
public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
    Parcelable.Creator<?> creator = readParcelableCreator(loader);
    if (creator == null) {
        return null;
    }
    if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
      Parcelable.ClassLoaderCreator<?> classLoaderCreator =
          (Parcelable.ClassLoaderCreator<?>) creator;
      return (T) classLoaderCreator.createFromParcel(this, loader);
    }
    //注意,这里得到的自定义对象跟写入的不是同一个了。
    return (T) creator.createFromParcel(this);
}

创建并返回一个新的自定义对象。

2.3 Bundles


/**
 * Flatten a Bundle into the parcel at the current dataPosition(),
 * growing dataCapacity() if needed.
 */
public final void writeBundle(Bundle val) {
    if (val == null) {
        writeInt(-1);
        return;
    }

    val.writeToParcel(this, 0);
}

/**
 * Read and return a new Bundle object from the parcel at the current
 * dataPosition(), using the given class loader to initialize the class
 * loader of the Bundle for later retrieval of Parcelable objects.
 * Returns null if the previously written Bundle object was null.
 */
public final Bundle readBundle(ClassLoader loader) {
    int length = readInt();
    if (length < 0) {
        if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
        return null;
    }

    final Bundle bundle = new Bundle(this, length);
    if (loader != null) {
        bundle.setClassLoader(loader);
    }
    return bundle;
}

支持Bundle对象的读写。

与parcelable有什么关系?

答: Bundle本质上就是一个parcelable对象。特点是封装了键值对的数据读写,一定程度上优化了读写效率,提升了性能。

2.4 Active object

什么是Active object?

答:我们一般存入到Parcel的是数据的本身,而Active object则是写入一个特殊的标志token,这个token引用了原数据对象。

当从Parcel中恢复这个对象时,我们可以不用重新实例化这个对象,而是通过得到一个handle值。通过handle值则可以直接操作原来需要写入的对象。

那么哪些对象属于Active object呢?

答: IBinder 对象和FileDescriptor 对象。


/**
 * Write an object into the parcel at the current dataPosition(),
 * growing dataCapacity() if needed.
 */
public final void writeStrongBinder(IBinder val) {
    nativeWriteStrongBinder(mNativePtr, val);
}



/**
 * Read an object from the parcel at the current dataPosition().
 */
public final IBinder readStrongBinder() {
    return nativeReadStrongBinder(mNativePtr);
}

支持IBinder对象的读写。


/**
 * Write a FileDescriptor into the parcel at the current dataPosition(),
 * growing dataCapacity() if needed.
 *
 * <p class="caution">The file descriptor will not be closed, which may
 * result in file descriptor leaks when objects are returned from Binder
 * calls.  Use {@link ParcelFileDescriptor#writeToParcel} instead, which
 * accepts contextual flags and will close the original file descriptor
 * if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p>
 */
public final void writeFileDescriptor(FileDescriptor val) {
    updateNativeSize(nativeWriteFileDescriptor(mNativePtr, val));
}

/**
 * Read a FileDescriptor from the parcel at the current dataPosition().
 */
public final ParcelFileDescriptor readFileDescriptor() {
    FileDescriptor fd = nativeReadFileDescriptor(mNativePtr);
    return fd != null ? new ParcelFileDescriptor(fd) : null;
}

支持fd对象的读写。

2.5 Untyped container

支持java容器类的存取。如 如map、list等。

* {@link #writeArray(Object[])}, {@link #readArray(ClassLoader)},
* {@link #writeList(List)}, {@link #readList(List, ClassLoader)},
* {@link #readArrayList(ClassLoader)},
* {@link #writeMap(Map)}, {@link #readMap(Map, ClassLoader)},
* {@link #writeSparseArray(SparseArray)},
* {@link #readSparseArray(ClassLoader)}.

而以上接口的本质是通过循环集合,内部调用writeValue(Object)readValue(ClassLoader)来实现。 如:

public final void writeMap(Map val) {
    writeMapInternal((Map<String, Object>) val);
}

/* package */ void writeMapInternal(Map<String,Object> val) {
    if (val == null) {
        writeInt(-1);
        return;
    }
    Set<Map.Entry<String,Object>> entries = val.entrySet();
    writeInt(entries.size());
    for (Map.Entry<String,Object> e : entries) {
        writeValue(e.getKey());
        writeValue(e.getValue());
    }
}

内部都是通过调用 writeValue():

public final void writeValue(Object v) {
    if (v == null) {
        writeInt(VAL_NULL);
    } else if (v instanceof String) {
        writeInt(VAL_STRING);
        writeString((String) v);
    } else if (v instanceof Integer) {
        writeInt(VAL_INTEGER);
        writeInt((Integer) v);
    } else if (v instanceof Map) {
        writeInt(VAL_MAP);
        writeMap((Map) v);
    } else if (v instanceof Bundle) {
        // Must be before Parcelable
        writeInt(VAL_BUNDLE);
        writeBundle((Bundle) v);
    } else if (v instanceof PersistableBundle) {
        writeInt(VAL_PERSISTABLEBUNDLE);
        writePersistableBundle((PersistableBundle) v);
    } else if (v instanceof Parcelable) {
        // IMPOTANT: cases for classes that implement Parcelable must
        // come before the Parcelable case, so that their specific VAL_*
        // types will be written.
        writeInt(VAL_PARCELABLE);
        writeParcelable((Parcelable) v, 0);
    } else if (v instanceof Short) {
        writeInt(VAL_SHORT);
        writeInt(((Short) v).intValue());
    } else if (v instanceof Long) {
        writeInt(VAL_LONG);
        writeLong((Long) v);
    } else if (v instanceof Float) {
        writeInt(VAL_FLOAT);
        writeFloat((Float) v);
    } else if (v instanceof Double) {
        writeInt(VAL_DOUBLE);
        writeDouble((Double) v);
    } else if (v instanceof Boolean) {
        writeInt(VAL_BOOLEAN);
        writeInt((Boolean) v ? 1 : 0);
    } else if (v instanceof CharSequence) {
        // Must be after String
        writeInt(VAL_CHARSEQUENCE);
        writeCharSequence((CharSequence) v);
    } else if (v instanceof List) {
        writeInt(VAL_LIST);
        writeList((List) v);
    } else if (v instanceof SparseArray) {
        writeInt(VAL_SPARSEARRAY);
        writeSparseArray((SparseArray) v);
    } else if (v instanceof boolean[]) {
        writeInt(VAL_BOOLEANARRAY);
        writeBooleanArray((boolean[]) v);
    } else if (v instanceof byte[]) {
        writeInt(VAL_BYTEARRAY);
        writeByteArray((byte[]) v);
    } else if (v instanceof String[]) {
        writeInt(VAL_STRINGARRAY);
        writeStringArray((String[]) v);
    } else if (v instanceof CharSequence[]) {
        // Must be after String[] and before Object[]
        writeInt(VAL_CHARSEQUENCEARRAY);
        writeCharSequenceArray((CharSequence[]) v);
    } else if (v instanceof IBinder) {
        writeInt(VAL_IBINDER);
        writeStrongBinder((IBinder) v);
    } else if (v instanceof Parcelable[]) {
        writeInt(VAL_PARCELABLEARRAY);
        writeParcelableArray((Parcelable[]) v, 0);
    } else if (v instanceof int[]) {
        writeInt(VAL_INTARRAY);
        writeIntArray((int[]) v);
    } else if (v instanceof long[]) {
        writeInt(VAL_LONGARRAY);
        writeLongArray((long[]) v);
    } else if (v instanceof Byte) {
        writeInt(VAL_BYTE);
        writeInt((Byte) v);
    } else if (v instanceof Size) {
        writeInt(VAL_SIZE);
        writeSize((Size) v);
    } else if (v instanceof SizeF) {
        writeInt(VAL_SIZEF);
        writeSizeF((SizeF) v);
    } else if (v instanceof double[]) {
        writeInt(VAL_DOUBLEARRAY);
        writeDoubleArray((double[]) v);
    } else {
        Class<?> clazz = v.getClass();
        if (clazz.isArray() && clazz.getComponentType() == Object.class) {
            // Only pure Object[] are written here, Other arrays of non-primitive types are
            // handled by serialization as this does not record the component type.
            writeInt(VAL_OBJECTARRAY);
            writeArray((Object[]) v);
        } else if (v instanceof Serializable) {
            // Must be last
            writeInt(VAL_SERIALIZABLE);
            writeSerializable((Serializable) v);
        } else {
            throw new RuntimeException("Parcel: unable to marshal value " + v);
        }
    }
}

writeValue()内部定义了支持的object类型,根据不同类型调用不同接口来实现序列化。

三、Parcel 传递过程

3.1 一些疑问:

  1. parcel初始化的时候,并没有分配内存,而是动态分配内存。那么分配内存所在空间是指? A进程空间?

答:是的,在进程A创建肯定是进程A的空间中。

  1. 那么parcel有没有数据大小限制? 最大是多少?

答:有的,总大小是Integer最大值。跨进程通信报限制错误,是因为进程间缓冲区有大小限制导致。如1M-8k。

  1. 读取数据的顺序必须要和写入数据的顺序一致,这样才能正确的获取的数据?

答:是的。因为Parcel会根据顺序读取。内部有一个位置指针。

3.2 Parcel的创建

3.2.1 obtain()

Parcel都是通过obtain()方法来获取对象的。

static protected final Parcel obtain(long obj) {
// 系统会缓存池(就是一个数组),大小为POOL_SIZE=6。
    final Parcel[] pool = sHolderPool; 
    synchronized (pool) {
        Parcel p;
        for (int i=0; i<POOL_SIZE; i++) {
            p = pool[i];
            if (p != null) {
                pool[i] = null; // 置空,表示已经被占用
                if (DEBUG_RECYCLE) {
                    p.mStack = new RuntimeException();
                }
                p.init(obj);
                return p;
            }
        }
    }
    //池中全部为空,没有可用的parcel,则创建一个新的parcel对象
    return new Parcel(obj);
}

3.2.2 init()

Parcel的构造方法:

private Parcel(long nativePtr) {
       if (DEBUG_RECYCLE) {
           mStack = new RuntimeException();
       }
       //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);
       //初始化 nativePtr 表示是native层的 parcel 对象
       init(nativePtr);
   }

继续看init(nativePtr),其中nativePtr 表示是native层的 parcel 对象。

  private void init(long nativePtr) {
        if (nativePtr != 0) {
            //没有native parcel的指针
            mNativePtr = nativePtr;
            mOwnsNativeParcelObject = false;
        } else {
            // 拥有native  parcel的指针,走该分支
            mNativePtr = nativeCreate();
            mOwnsNativeParcelObject = true;
        }
    }
    
   

调用的是jni层:

// jni 方法
    private static native long nativeCreate();

3.2.3 nativeCreate(native层)

继续看jni方法。

483  static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
484  {
        // 创建c++ parcel对象
485      Parcel* parcel = new Parcel();
         // 强转为long值,返回引用给java层 
486      return reinterpret_cast<jlong>(parcel);
487  }

3.2.4 reinterpret_cast

这个方法非常重要。可以把一个c++对象解释转换为一个long型的值。后续在根据这个long值再强转回为原来的c++的对象。因此,java层只要持有这个long型值,即可与c++层联系起来了。

继续看native层的 Parcel()对象:

3.2.4 Parcel::initState

352  Parcel::Parcel()
353  {
354      LOG_ALLOC("Parcel %p: constructing", this);
355      initState();
356  }

void Parcel::initState()
2913  {
2914      LOG_ALLOC("Parcel %p: initState", this);
2915      mError = NO_ERROR;
2916      mData = nullptr;
2917      mDataSize = 0;
2918      mDataCapacity = 0;
2919      mDataPos = 0;
2920      ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
2921      ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
2922      mObjects = nullptr;
2923      mObjectsSize = 0;
2924      mObjectsCapacity = 0;
2925      mNextObjectHint = 0;
2926      mObjectsSorted = false;
2927      mHasFds = false;
2928      mFdsKnown = true;
2929      mAllowFds = true;
2930      mOwner = nullptr;
2931      mOpenAshmemSize = 0;
2932      mWorkSourceRequestHeaderPosition = 0;
2933      mRequestHeaderPresent = false;
2934  
2935      // racing multiple init leads only to multiple identical write
2936      if (gMaxFds == 0) {
2937          struct rlimit result;
2938          if (!getrlimit(RLIMIT_NOFILE, &result)) {
2939              gMaxFds = (size_t)result.rlim_cur;
2940              //ALOGI("parcel fd limit set to %zu", gMaxFds);
2941          } else {
2942              ALOGW("Unable to getrlimit: %s", strerror(errno));
2943              gMaxFds = 1024;
2944          }
2945      }
2946  }

从以上可以看出,这里只是初始化了一些成员变量,如parcel的大小、容量、开始位置等信息。

注意,此时Parcel是没有分配内存的。Parcel是在存入数据的时候,动态分配内存的。

四、数据读写过程

4.1 基本数据的写

writeFloat()和readFloat()为例。

4.1.1 nativeWriteFloat()

public final void writeFloat(float val) {
    nativeWriteFloat(mNativePtr, val);
}

传入nativePtr指针,调用的是jni方法,那我们看看native层的方法:

/frameworks/base/core/jni/android_os_Parcel.cpp

static void android_os_Parcel_writeFloat(JNIEnv* env, jclass clazz, jlong nativePtr, jfloat val)
255  {
         // 根据java层的指针强转为c++层的Parcel对象
256      Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
257      if (parcel != NULL) {
            //
258          const status_t err = parcel->writeFloat(val);
259          if (err != NO_ERROR) {
260              signalExceptionForError(env, clazz, err);
261          }
262      }
263  }

继续看Parcel的 writeFloat():

4.1.2 writeFloat()

/frameworks/native/libs/binder/Parcel.cpp

status_t Parcel::writeFloat(float val)
1060  {
1061      return writeAligned(val);
1062  }
1063  
template<class T>
1680  status_t Parcel::writeAligned(T val) {
1681      COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
    1682  //如果在当前的位置mDataPos+插入值val的大小,还没有超过parcel的容量,那么直接插入val
1683      if ((mDataPos+sizeof(val)) <= mDataCapacity) {
1684  restart_write: // 在当前位置插入val
1685          *reinterpret_cast<T*>(mData+mDataPos) = val;
                //完成插入,更新mDataPos位置。结束
1686          return finishWrite(sizeof(val));
1687      }
    1688  //如果超过容量,则自动扩容
1689      status_t err = growData(sizeof(val));
           //扩容成功,再次把val值插入到parcel中
1690      if (err == NO_ERROR) goto restart_write;
1691      return err;
1692  }
1693  

4.1.3 growData()

 status_t Parcel::growData(size_t len)
2681  {
2682      if (len > INT32_MAX) {
2683          // don't accept size_t values which may have come from an
2684          // inadvertent conversion from a negative int.
2685          return BAD_VALUE;
2686      }
2687  
2688      size_t newSize = ((mDataSize+len)*3)/2; //1.5 倍扩容
2689      return (newSize <= mDataSize)
2690              ? (status_t) NO_MEMORY
2691              : continueWrite(newSize);
2692  }

4.1.4 continueWrite()

    ...
    
             // This is the first data.  Easy!
               //调用malloc函数,分配内存
2885          uint8_t* data = (uint8_t*)malloc(desired);
2886          if (!data) {
2887              mError = NO_MEMORY;
2888              return NO_MEMORY;
2889          }
2890  
2891          if(!(mDataCapacity == 0 && mObjects == nullptr
2892               && mObjectsCapacity == 0)) {
2893              ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity, mObjects, mObjectsCapacity, desired);
2894          }
2895  
2896          LOG_ALLOC("Parcel %p: allocating with %zu capacity", this, desired);
2897          pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
2898          gParcelGlobalAllocSize += desired;
2899          gParcelGlobalAllocCount++;
2900          pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
2901  
2902          mData = data;
2903          mDataSize = mDataPos = 0;
2904          ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize);
2905          ALOGV("continueWrite Setting data pos of %p to %zu", this, mDataPos);
2906          mDataCapacity = desired;
2907      }

可以发现,内部是通过malloc()函数完成内存分配的。至此,完成了数据的写入操作。

那数据是如何读取的呢?

4.2 基本数据的读过程

4.2.1 nativeReadFloat()

private static native float nativeReadFloat(long nativePtr);
static jfloat android_os_Parcel_readFloat(jlong nativePtr)
430  {   //同理,根据long值,得到parcel对象
431      Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
432      if (parcel != NULL) {
433          return parcel->readFloat();
434      }
435      return 0;
436  }

看parcel的 readFloat():

float Parcel::readFloat() const
1953  {
1954      return readAligned<float>();
1955  }

4.2.2 readAligned()

status_t Parcel::readAligned(T *pArg) const {
1648      COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
1649  
1650      if ((mDataPos+sizeof(T)) <= mDataSize) {
1651          if (mObjectsSize > 0) {
                  从当前位置读取一个float类型的数据
1652              status_t err = validateReadData(mDataPos + sizeof(T));
1653              if(err != NO_ERROR) {
1654                  // Still increment the data position by the expected length
1655                  mDataPos += sizeof(T);
1656                  return err;
1657              }
1658          }
1659  
1660          const void* data = mData+mDataPos;
1661          mDataPos += sizeof(T);
1662          *pArg =  *reinterpret_cast<const T*>(data);
1663          return NO_ERROR;
1664      } else {
1665          return NOT_ENOUGH_DATA;
1666      }
1667  }

内部会根据插入的顺序,根据前位置mDataPos数据大小,读取一个float类型的数据。

注意,读取数据的顺序和插入数据的顺序必须一致,否则会读取失败。

4.3 Ative Object对象的写过程

4.3.1 nativeWriteStrongBinder()

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
299  {
300      Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
301      if (parcel != NULL) {

302          const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));

303          if (err != NO_ERROR) {
304              signalExceptionForError(env, clazz, err);
305          }
306      }
307  }

4.3.2 ibinderForJavaObject()

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
707  {
708      if (obj == NULL) return NULL;
709  
710      // Instance of Binder? 
711      if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
712          JavaBBinderHolder* jbh = (JavaBBinderHolder*)
713              env->GetLongField(obj, gBinderOffsets.mObject);
714          return jbh->get(env, obj);
715      }
716  
717      // Instance of BinderProxy?
718      if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
719          return getBPNativeData(env, obj)->mObject;
720      }
721  
722      ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
723      return NULL;
724  }

根据java的binder对象得到native层对应的binder对象:

  • 如果是Binder.java 对象(一般为服务端的xxxservice.java),那么就得到一个JavaBBinder.cpp对象,其实就是BBinder对象。
  • 如果是BinderProxy.java对象,那么就得到BpBinder.cpp对象。

4.3.3 writeStrongBinder()

传入的是一个IBinder 对象。

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
        1135  {    // val是binder对象, this是parcel对象,此时为写入
1136      return flatten_binder(ProcessState::self(), val, this);
1137  }
1138  
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
205      const sp<IBinder>& binder, Parcel* out)
206  {
207      flat_binder_object obj; // 构造无障碍 flat_binder_object对象
208  
209      if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
210          /* minimum priority for all nodes is nice 0 */
211          obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
212      } else {
213          /* minimum priority for all nodes is MAX_NICE(19) */
214          obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
215      }
216  
217      if (binder != nullptr) {
218          BBinder *local = binder->localBinder();
219          if (!local) {
                //不是本地的binder,那么使用远端binder的代理
220              BpBinder *proxy = binder->remoteBinder();
221              if (proxy == nullptr) {
222                  ALOGE("null proxy");
223              }
224              const int32_t handle = proxy ? proxy->handle() : 0;
225              obj.hdr.type = BINDER_TYPE_HANDLE; //存入类型为handle
226              obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
227              obj.handle = handle; //存入handle值
228              obj.cookie = 0;
229          } else {
                  //本地binder,存入
230              if (local->isRequestingSid()) {
231                  obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
232              }
233              obj.hdr.type = BINDER_TYPE_BINDER; // 类型为binder
                 
234              obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs()); //存入弱引用
                // 把本地的binder对象存入到obj的cookies中
235              obj.cookie = reinterpret_cast<uintptr_t>(local);
236          }
237      } else {
238          obj.hdr.type = BINDER_TYPE_BINDER; 
239          obj.binder = 0;
240          obj.cookie = 0;
241      }
242  
243      return finish_flatten_binder(binder, obj, out);
244  }
245  

4.3.4 finish_flatten_binder()

inline static status_t finish_flatten_binder(
199      const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
200  {
201      return out->writeObject(flat, false);
202  }

费劲心思把IBinder对象转换成了flat_binder_object对象,直接写入到parcel中:

4.3.5 writeObject()

status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
1371  {
1372      const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
1373      const bool enoughObjects = mObjectsSize < mObjectsCapacity;
1374      if (enoughData && enoughObjects) { //如果parcel中内存足够,则直接存入
        //存入val: flat_binder_object
1375  restart_write:
1376          *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
1377  
1378          // remember if it's a file descriptor
1379          if (val.hdr.type == BINDER_TYPE_FD) {
1380              if (!mAllowFds) {
1381                  // fail before modifying our object index
1382                  return FDS_NOT_ALLOWED;
1383              }
1384              mHasFds = mFdsKnown = true;
1385          }
1386  
1387          // Need to write meta-data?
1388          if (nullMetaData || val.binder != 0) {
1389              mObjects[mObjectsSize] = mDataPos;
1390              acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
1391              mObjectsSize++;
1392          }
1393  
1394          return finishWrite(sizeof(flat_binder_object));
1395      }
1396  
1397      if (!enoughData) {
               //如果parcel中内存不够,则扩容
1398          const status_t err = growData(sizeof(val));
1399          if (err != NO_ERROR) return err;
1400      }
1401      if (!enoughObjects) {
1402          size_t newSize = ((mObjectsSize+2)*3)/2;
1403          if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY;   // overflow //溢出
1404          binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
1405          if (objects == nullptr) return NO_MEMORY;
1406          mObjects = objects;
1407          mObjectsCapacity = newSize;
1408      }
1409  
1410      goto restart_write; // 扩容后,继续写入
1411  }
1412  

至此,我们把一个binder对象转换成了一个flat_binder_object的对象,写入到parcel中(而不是直接写入binder对象本身)。

binder对象的读取过程:

4.4 Ative Object对象的读过程

4.4.1 nativeReadStrongBinder()

private static native IBinder nativeReadStrongBinder(long nativePtr);
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
462  {
463      Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
464      if (parcel != NULL) {
465          return javaObjectForIBinder(env, parcel->readStrongBinder());
466      }
467      return NULL;
468  }
469  

4.4.2 parcel->readStrongBinder()

sp<IBinder> Parcel::readStrongBinder() const
2214  {
2215      sp<IBinder> val;
2216      // Note that a lot of code in Android reads binders by hand with this
2217      // method, and that code has historically been ok with getting nullptr
2218      // back (while ignoring error codes).
2219      readNullableStrongBinder(&val);
2220      return val;
2221  }

4.4.3 unflatten_binder()

status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
2209  {
2210      return unflatten_binder(ProcessState::self(), *this, val);
2211  }
  status_t unflatten_binder(const sp<ProcessState>& proc,
303      const Parcel& in, sp<IBinder>* out)
    304  {// 从parcel中获得 flat_binder_object 对象
305      const flat_binder_object* flat = in.readObject(false);
306  
307      if (flat) {
308          switch (flat->hdr.type) {
309              case BINDER_TYPE_BINDER:
                    //从cookies中强转回得到一个IBinder对象
310                  *out = reinterpret_cast<IBinder*>(flat->cookie);
311                  return finish_unflatten_binder(nullptr, *flat, in);
312              case BINDER_TYPE_HANDLE:
                      //从flat的handle得到一个 IBinder代理
313                  *out = proc->getStrongProxyForHandle(flat->handle);
314                  return finish_unflatten_binder(
315                      static_cast<BpBinder*>(out->get()), *flat, in);
316          }
317      }
318      return BAD_TYPE;
319  }

此时,由于是客户端从SM中获取服务端的Service代理对象,因此走的是BINDER_TYPE_HANDLE分支。得到一个BpBinder对象。具体过程,可参考getService流程。

4.4.4 readObject()

const flat_binder_object* Parcel::readObject(bool nullMetaData) const
2460  {
2461      const size_t DPOS = mDataPos;
2462      if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
            // 从parcel当前位置,强转得到一个flat 对象:obj
2463          const flat_binder_object* obj
2464                  = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
2465          mDataPos = DPOS + sizeof(flat_binder_object);
2466          if (!nullMetaData && (obj->cookie == 0 && obj->binder == 0)) {
2467              // When transferring a NULL object, we don't write it into
2468              // the object list, so we don't want to check for it when
2469              // reading.
2470              ALOGV("readObject Setting data pos of %p to %zu", this, mDataPos);
2471              return obj;
2472          }
2473  
2474        ...
2517      return nullptr;
2518  }

4.4.5 proc->getStrongProxyForHandle()

 sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
260  {
261      sp<IBinder> result;
262  
263      AutoMutex _l(mLock);
264  
265      handle_entry* e = lookupHandleLocked(handle);
266  
267      if (e != nullptr) {
268          // We need to create a new BpBinder if there isn't currently one, OR we
269          // are unable to acquire a weak reference on this current one.  See comment
270          // in getWeakProxyForHandle() for more info about this.
271          IBinder* b = e->binder;
272          if (b == nullptr || !e->refs->attemptIncWeak(this)) {
273              ...

300              b = BpBinder::create(handle);
301              e->binder = b;
302              if (b) e->refs = b->getWeakRefs();
303              result = b;
304          } else {
305              // This little bit of nastyness is to allow us to add a primary
306              // reference to the remote proxy when this team doesn't have one
307              // but another team is sending the handle to us.
308              result.force_set(b);
309              e->refs->decWeak(this);
310          }
311      }
312  
313      return result;
314  }

根据handle 创建一个bpBinder对象。

4.4.6 finish_unflatten_binder()

inline static status_t finish_unflatten_binder(
296      BpBinder* /*proxy*/, const flat_binder_object& /*flat*/,
297      const Parcel& /*in*/)
298  {
299      return NO_ERROR;
300  }

这里,啥事都没做,直接返回code。

4.4.7 javaObjectForIBinder()

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
666  {
667      if (val == NULL) return NULL;
668  
669      if (val->checkSubclass(&gBinderOffsets)) {
670          // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
671          jobject object = static_cast<JavaBBinder*>(val.get())->object();
672          LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
673          return object;
674      }
    675  
676      BinderProxyNativeData* nativeData = new BinderProxyNativeData();
677      nativeData->mOrgue = new DeathRecipientList;
678      nativeData->mObject = val;
    679  //通过反射,构造了BinderProxy.java类,其中的nativeData指向了BpBinder.cpp对象
680      jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
681              gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
682      if (env->ExceptionCheck()) {
683          // In the exception case, getInstance still took ownership of nativeData.
684          return NULL;
685      }
686      BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
687      if (actualNativeData == nativeData) {
688          // Created a new Proxy
689          uint32_t numProxies = gNumProxies.fetch_add(1, std::memory_order_relaxed);
690          uint32_t numLastWarned = gProxiesWarned.load(std::memory_order_relaxed);
691          if (numProxies >= numLastWarned + PROXY_WARN_INTERVAL) {
692              // Multiple threads can get here, make sure only one of them gets to
693              // update the warn counter.
694              if (gProxiesWarned.compare_exchange_strong(numLastWarned,
695                          numLastWarned + PROXY_WARN_INTERVAL, std::memory_order_relaxed)) {
696                  ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies);
697              }
698          }
699      } else {
700          delete nativeData;
701      }
702  
703      return object;
704  }

通过反射,构造了BinderProxy.java对象,其中的nativeData成员指向了BpBinder.cpp对象。至此,java层就得到一个IBinder对象。

4.5 总结

经过以上的分析,我们有了一个基本的认识,不管什么类型的数据,我们通过parcel提供的接口就能轻松实现数据的序列化和反序列化。而这种序列化的过程是基于内存的。

五、Parcel与Serializable区别

Parcel:

  • 基于内存中的序列化
  • 把对象拆解,再组装,效率更高
  • 不适合序列化到文件和网络
  • 对写入数据的和读取数据有顺序要一致,否则会失败
  • 一般情况下用于跨进程,当然也可以在同一个进程(不推荐)

Serializable:

  • 基于网络、文件的序列化。 直接转成二进制,占用内存小。
  • 当然也可以基于内存,不过有缺点:但是临时变量多,内存碎片化,导致频繁gc

参考

3dobe.com/archives/22…