引言

在上一篇Blog中,在分析服务注册过程时,往data(Parcel对象)变量写入数据时,有这样的调用路径:

BpServiceManager::addService()–>Parcel::writeStrongBinder()–>flatten_binder()–>finish_flatten_binder()

由于finish_flatten_binder()方法中涉及到的东西太多,在上一篇博客就没有展开来讲。这篇博客将详细分析数据是如何写入到data中的。

下面是Parcel类的定义:

Parcel.h
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
class Parcel { public:  Parcel();  ~Parcel();   const uint8_t* data() const;  size_t dataSize() const;  size_t dataAvail() const;  size_t dataPosition() const;  size_t dataCapacity() const;   status_t setDataSize(size_t size);  void setDataPosition(size_t pos) const;  status_t setDataCapacity(size_t size);   status_t setData(const uint8_t* buffer, size_t len);   status_t appendFrom(Parcel *parcel, size_t start, size_t len);   bool hasFileDescriptors() const;   status_t writeInterfaceToken(const String16& interface);  bool enforceInterface(const String16& interface) const;  bool checkInterface(IBinder*) const;   void freeData();   const size_t* objects() const;  size_t objectsCount() const;   status_t errorCheck() const;  void setError(status_t err);   status_t write(const void* data, size_t len);  void* writeInplace(size_t len);  status_t writeUnpadded(const void* data, size_t len);  status_t writeInt32(int32_t val);  status_t writeInt64(int64_t val);  status_t writeFloat(float val);  status_t writeDouble(double val);  status_t writeIntPtr(intptr_t val);  status_t writeCString(const char* str);  status_t writeString8(const String8& str);  status_t writeString16(const String16& str);  status_t writeString16(const char16_t* str, size_t len);  status_t writeStrongBinder(const sp<IBinder>& val);  status_t writeWeakBinder(const wp<IBinder>& val);  status_t write(const Flattenable& val);   // Place a native_handle into the parcel (the native_handle's file-  // descriptors are dup'ed, so it is safe to delete the native_handle  // when this function returns).   // Doesn't take ownership of the native_handle.  status_t writeNativeHandle(const native_handle* handle);   // Place a file descriptor into the parcel. The given fd must remain  // valid for the lifetime of the parcel.  status_t writeFileDescriptor(int fd);   // Place a file descriptor into the parcel. A dup of the fd is made, which  // will be closed once the parcel is destroyed.  status_t writeDupFileDescriptor(int fd);   status_t writeObject(const flat_binder_object& val, bool nullMetaData);   void remove(size_t start, size_t amt);   status_t read(void* outData, size_t len) const;  const void* readInplace(size_t len) const;  int32_t readInt32() const;  status_t readInt32(int32_t *pArg) const;  int64_t readInt64() const;  status_t readInt64(int64_t *pArg) const;  float readFloat() const;  status_t readFloat(float *pArg) const;  double readDouble() const;  status_t readDouble(double *pArg) const;  intptr_t readIntPtr() const;  status_t readIntPtr(intptr_t *pArg) const;   const char* readCString() const;  String8 readString8() const;  String16 readString16() const;  const char16_t* readString16Inplace(size_t* outLen) const;  sp<IBinder> readStrongBinder() const;  wp<IBinder> readWeakBinder() const;  status_t read(Flattenable& val) const;   // Retrieve native_handle from the parcel. This returns a copy of the  // parcel's native_handle (the caller takes ownership). The caller  // must free the native_handle with native_handle_close() and   // native_handle_delete().  native_handle* readNativeHandle() const;    // Retrieve a file descriptor from the parcel. This returns the raw fd  // in the parcel, which you do not own -- use dup() to get your own copy.  int readFileDescriptor() const;   const flat_binder_object* readObject(bool nullMetaData) const;   // Explicitly close all file descriptors in the parcel.  void closeFileDescriptors();   typedef void (*release_func)(Parcel* parcel,  const uint8_t* data, size_t dataSize,  const size_t* objects, size_t objectsSize,  void* cookie);   const uint8_t* ipcData() const;  size_t ipcDataSize() const;  const size_t* ipcObjects() const;  size_t ipcObjectsCount() const;  void ipcSetDataReference(const uint8_t* data, size_t dataSize,  const size_t* objects, size_t objectsCount,  release_func relFunc, void* relCookie);   void print(TextOutput& to, uint32_t flags = 0) const;  private:  Parcel(const Parcel& o);  Parcel& operator=(const Parcel& o);   status_t finishWrite(size_t len);  void releaseObjects();  void acquireObjects();  status_t growData(size_t len);  status_t restartWrite(size_t desired);  status_t continueWrite(size_t desired);  void freeDataNoInit();  void initState();  void scanForFds() const;   template<class T>  status_t readAligned(T *pArg) const;   template<class T> T readAligned() const;   template<class T>  status_t writeAligned(T val);   status_t mError;  uint8_t* mData;  size_t mDataSize;  size_t mDataCapacity;  mutable size_t mDataPos;  size_t* mObjects;  size_t mObjectsSize;  size_t mObjectsCapacity;  mutable size_t mNextObjectHint;   mutable bool mFdsKnown;  mutable bool mHasFds;   release_func mOwner;  void* mOwnerCookie; }; 

虽然public方法有很多,但是我们先只要注意它的成员变量即可,特别是mData,mDataSize,mDataCapacity,mDataPos,mObjects,mObjectsSize,mObjectsCapacity这几个成员变量。

另外,为了方便大家理解,先说1个结论:对于普通数据,使用mData进行储存;对于IBinder类型的数据以及FileDescriptor使用的是mObjects;

1.Parcel类的初始化

在C++中,类的初始化非常重要,可能在成员初始化列表中就进行非常多的操作。所以首先要看它的构造函数:

1234
Parcel::Parcel() {  initState(); } 

出乎意料地是,Parcel类的构造方法异常简单,就是调用initState()方法,下面是initState()的代码:

1234567891011121314151617
void Parcel::initState() {  mError = NO_ERROR;  mData = 0;  mDataSize = 0;  mDataCapacity = 0;  mDataPos = 0;  LOGV("initState Setting data size of %p to %d\n", this, mDataSize);  LOGV("initState Setting data pos of %p to %d\n", this, mDataPos);  mObjects = NULL;  mObjectsSize = 0;  mObjectsCapacity = 0;  mNextObjectHint = 0;  mHasFds = false;  mFdsKnown = true;  mOwner = NULL; } 

可以发现,initState()函数主要就是对成员变量初始化。而mDataSize,mDataCapacity,mDataPos,mObjectsSize,mObjectsCapacity都为0,另外指针都初始化为NULL.注意这些成员的初始值很重要,因为后面会用到。

2.finish_flatten_binder()

由于在上一篇Blog中已经分析过Parcel::writeStrongBinder()和flatten_binder()函数,所以这里直接分析finish_flatten_binder()方法了。该方法的代码如下:

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

竟然又是调用,这个嵌套太多了,而且binder参数没有再被用到的话,其实就可以不传递过来了。下面看Parcel::writeObject()方法的代码:

123456789101112131415161718192021222324252627282930313233343536373839404142
status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) {  const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;  const bool enoughObjects = mObjectsSize < mObjectsCapacity;  if (enoughData && enoughObjects) { restart_write:  //code_1  *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;   // Need to write meta-data?  //code_2  if (nullMetaData || val.binder != NULL) {  mObjects[mObjectsSize] = mDataPos;  acquire_object(ProcessState::self(), val, this);  mObjectsSize++;  }   // remember if it's a file descriptor  //code_3  if (val.type == BINDER_TYPE_FD) {  mHasFds = mFdsKnown = true;  }  //code_4  return finishWrite(sizeof(flat_binder_object));  }   //code_5  if (!enoughData) {  const status_t err = growData(sizeof(val));  if (err != NO_ERROR) return err;  }  //code_6  if (!enoughObjects) {  size_t newSize = ((mObjectsSize+2)*3)/2;  size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));  if (objects == NULL) return NO_MEMORY;  mObjects = objects;  mObjectsCapacity = newSize;  }   goto restart_write; } 

由于从Parcel data;定义之后,一直到这里,除了写入接口描述符和服务名称之外,并没有改变data的其他成员变量,所以mDataPos,mDataCapacity,mObjectsSize,mObjectsCapacity仍然是初始值0,所以enoughData,enoughObjects均为false.

所以先执行code_5和code_6处的代码,先看growData()方法的代码:

1234567
status_t Parcel::growData(size_t len) {  size_t newSize=((mDataSize+len)*3)/2;  return (newSize<=mDataSize)  ? (status_t) NO_MEMORY  : continueWrite(newSize); } 

其中len是flat_binder_object的大小,显然这里无论如何都不会出现newSize<=mDataSize的情况,所以这里是个很明显的bug,存在着内存泄露的风险。 下面我们看一下continueWrite(newSize)的代码,注意此时传入的参数值是(mDataSize+len)*3/2:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
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;  //code_1  if (desired < mDataSize) {  if (desired == 0) {  objectsSize = 0;  } else {  while (objectsSize > 0) {  if (mObjects[objectsSize-1] < desired)  break;  objectsSize--;  }  }  }  //code_2  if (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));  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);  }  if (objects && mObjects) {  memcpy(objects, mObjects, objectsSize*sizeof(size_t));  }  //LOGI("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;  LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);  mDataCapacity = desired;  mObjectsSize = mObjectsCapacity = objectsSize;  mNextObjectHint = 0;   } else if (mData) { //code_3  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);  if (data) {  mData = data;  mDataCapacity = desired;  } else if (desired > mDataCapacity) {  mError = NO_MEMORY;  return NO_MEMORY;  }  } else {  mDataSize = desired;  LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);  if (mDataPos > desired) {  mDataPos = desired;  LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);  }  }   } else { //code_4  // 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)) {  LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);  }   mData = data;  mDataSize = mDataPos = 0;  LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);  LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);  mDataCapacity = desired;  }   return NO_ERROR; } 

其实这个方法写得挺糟糕的,有那么多分支,应该增加几个工具函数,这样一个函数的代码量就不会那么大了,阅读代码就会方便很多。
由于传入的desired值为(mDataSize+size(val))*3/2,肯定大于mDataSize,再加上mOwner和mData仍然为NULL,所以这里不会执行code_1,code_2和code_3这3部分代码。只需要看code_4这个分支下的代码。

这段代码非常简单,就是先调用malloc()方法分配一块(mDataSize+size(val))*3/2大小的内存,然后让mData指向该内存,并且将mDataCapacity的值修改为分配内存的大小。

到这里可以归纳一下,growData()方法只是分配了一块比flat_binder_object对象大一些的内存,但是暂时还没有将数据放进去。

再回到Parcela::writeObject()方法中,下面执行的仍然是从堆上分配内存,分配好之后让mObjects指向内存的起始位置,并且mObjectsCapacity赋值为刚刚分配的内存大小。另外,由于mObjectsSize初始值为0,所以这里其实newSize==3,从而分配的内存大小其实是3*sizeof(size_t);其中size_t是typedef unsigned long size_t,所以sizeof(size_t)的结果为4,从而这里最终是分配了12个字节的内存大小。

接着是goto restart_write,再次吐槽一句,Android Framework的架构虽然很好,但是有些代码质量堪忧,像这样的goto语句在很多个地方出现过。还有像interpret_cast这样很容易导致程序crash的转化其实也应该尽量避免的。

reinterpret_cast>(mData+mDataPos)=val;的作用是将从mData+mDataPos位置处开始的内存内容填充为flat_binder_object对象val的值;

虽然nullMetaData为false,但是val.binder不为NULL,所以下面会给mObjects数组赋值,此时mObjectsSize==0,所以mObjects数组中第一个元素为mDataPos,下面进入acquire_object()方法:

123456789101112131415161718192021222324252627282930313233343536
void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who) {  switch (obj.type) {  case BINDER_TYPE_BINDER:  if (obj.binder) {  LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);  static_cast<IBinder*>(obj.cookie)->incStrong(who);  }  return;  case BINDER_TYPE_WEAK_BINDER:  if (obj.binder)  static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);  return;  case BINDER_TYPE_HANDLE: {  const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);  if (b != NULL) {  LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());  b->incStrong(who);  }  return;  }  case BINDER_TYPE_WEAK_HANDLE: {  const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);  if (b != NULL) b.get_refs()->incWeak(who);  return;  }  case BINDER_TYPE_FD: {  // intentionally blank -- nothing to do to acquire this, but we do  // recognize it as a legitimate object type.  return;  }  }   LOGD("Invalid object type 0x%08lx", obj.type); } 

注意到传入的参数分别是:ProcessState::self(),flat_binder_object对象以及Parcel对象,由于obj.type为BINDER_TYPE_BINDER,所以obj的cookie对象,其实就是之前创建的MediaPlayerService对象执行incStrong()函数,这里涉及到指针的引用问题,后面会有专门的博客进行深入讲解,这里可以将其简单地理解成为Parcel对象增加一次引用。

之后再回到Parcel::writeObject()方法中,mObjectsSize执行自加操作之后变为1.

由于val.type值是BINDER_TYPE_BINDER,所以下面进入到Parcel::finishWrite()方法中,注意传入的参数sizeof(flat_binder_object)值为16:

123456789101112
status_t Parcel::finishWrite(size_t len) {  //printf("Finish write of %d\n", len);  mDataPos += len;  LOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos);  if (mDataPos > mDataSize) {  mDataSize = mDataPos;  LOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize);  }  //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);  return NO_ERROR; } 

这个方法异常简单,就是让mDataPos增加到刚刚写入数据的末尾,并且进行一个判断,如果mDataPos>mDataSize的话,就将mDataSize=mDataPos;而实际上mDataSize在赋值前还是0,所以会进行这个赋值操作,因此我们可以知道,其实mDataSize是记录当前mData中写入数据的大小。

到这里,我们就将flat_binder_object这个对象写入到Parcel对象中的mData指向的内存中。

最后,欢迎大家关注我的微信公众号:AndroidGeek.  AndroidGeek专注于Android源码解析、框架设计、最新技术分享以及职位招聘和内推

更多相关文章

  1. android一些有用的方法总结(持续更新……)
  2. 深入浅出Android(安卓)Service (3)
  3. Android调用系统图库获取图片
  4. android中多语言的设置
  5. 2018年Android面试题整理
  6. 关于 bin/resources.ap_ does not exist 的解决方法
  7. Android(安卓)Studio -添加你见过的最牛Log*神器*
  8. Android4.03中遭遇Installation error: INSTALL_FAILED_INSUFFIC
  9. Android中Handler、HandlerThread、AsyncTask的应用

随机推荐

  1. Android中AsyncTask使用详解
  2. Android(安卓)前景
  3. Android老版本项目导入到新版SDK提示错误
  4. 《Android经验分享》周刊第2期
  5. Android(安卓)图像存储在SD卡ContentReso
  6. Android高手进阶教程(二)之----Android(
  7. Android(安卓)Content Provider
  8. Android入门第十六篇之Style与Theme
  9. Android消息机制(Handler原理)
  10. Android开发——Android搜索框架(一)