Android5.0中Binder机制相关的native层的Parcel分析

来源:互联网 发布:无锡软件招聘研究所 编辑:程序博客网 时间:2024/05/25 19:56
    文章仅仅用于个人的学习记录,基本上内容都是网上各个大神的杰作,此处摘录过来以自己的理解学习方式记录一下。
    个人最为认可和推崇的大神文章:
          http://blog.csdn.net/luoshengyang/article/details/6618363     罗升阳Binder系列文章
          http://blog.csdn.net/innost/article/details/47208049                Innost的Binder讲解

          https://my.oschina.net/youranhongcha/blog/149575              侯 亮的Binder系列文章.

1、native层的Parcel.

           1)、writeStrongBinder(service)分析
           这感觉是最最最重要的一个函数了,在Parcel中,对于理解整个Binder流程也是至关重要的。从函数的名字皆可以看出,它是要往Parcel中写  
           一个Binder的引用或者实体. 位于android/frameworks/native/libs/binder/Parcel.cpp这个文件当中.
           此处的service参数按照是一个MediaPlayerService对象它继承BnInterface、BBinder两个类。
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}     
status_t flatten_binder(const sp<ProcessState>& /*proc*/, //这里
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj; // 描述传输过程中的Binder.flatten使光滑,打包等等.
 
//0x7f表示处理本Binder实体请求数据包的线程的最低优先级,
//FLAT_BINDER_FLAG_ACCEPTS_FDS表示这个Binder实体可以接受文件描述符,
//Binder实体在收到文件描述符时,就会在本进程中打开这个文件
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) {
IBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE; ////Binder引用的时候flat_binder_object 中的type = BINDER_TYPE_HANDLE.
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;//引用的时候为handle赋值,这个Handler就是初始化BpBinder的时候设置的.
obj.cookie = 0;
} else {
//又由于MediaPlayerService继承自BBinder类,它是一个本地Binder实体,因此binder->localBinder返回一个BBinder指针,
//就是服务端走这边.
obj.type = BINDER_TYPE_BINDER;//Binder实体的时候flat_binder_object 中的type = BINDER_TYPE_BINDER.
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());//实体的时候为binder赋值.
//果然只有在binder实体的时候才会有值,是Binder实体地址的指针.
obj.cookie = reinterpret_cast<uintptr_t>(local);//指向这个Binder实体地址的指针local保存在flat_binder_obj的成员变量cookie中。
}
} else {
obj.type = BINDER_TYPE_BINDER;//Binder == null 的时候flat_binder_object 中的type = BINDER_TYPE_BINDER.
obj.binder = 0;
obj.cookie = 0;
}
 
return finish_flatten_binder(binder, obj, out);//进一步调用这个.
}
            此时有个知识点就是IBinder中定义了localBinder、remoteBinder两个virtual的方法,但是它都自己实现了,默认都是返回null的.        
BBinder* IBinder::localBinder()
{
return NULL;
}
 
BpBinder* IBinder::remoteBinder()
{
return NULL;
}
               而在BBinder中实现了localBinder返回this,在BBinder中实现了remoteBinder返回this,从名字上我们也可以很轻松的记住每个函数的用意.
          先是调用binder->localBinder(),注意此时的binder传入的是MediaPlayerService它是一个BBinder对象。它的localBinder返回的是this,(
          BpBinder中没有看来是不会走到这里).
BBinder* BBinder::localBinder()
{
return this;
}
           此时拿到这个BBinder对象,然后会走到else,但是我们都要分析一下:
           结构体flat_binder_object进行对应的赋值,这个结构体我们在别的地方也有总结它是用来描述一个传输中的binder对象.其中比较重要的一
           个联合体,当是一个binder实体的时候binder_uintptr_t  binder起作用。当是一个binder引用的时候联合体的__u32   handle起作用,并且只
           有当为binder实体的时候binder_uintptr_t   cookie才起作用,那么究竟是怎么实现的那?接下来就分析一下
           struct  flat_binder_object  obj;
           在if (!local)这个条件下:
                 此时是传入的这个IBinder对象是一个BpBinder对象,取出BpBinder对象的句柄handle然后obj.handle = handle。此时obj.binder = 0、
           obj.cookie = 0都不起作用。还有一个很重要的赋值:obj.type = BINDER_TYPE_HANDLE.在传入的是Binder的引用也就是BpBinder对
           象的时候进行的都是这些的赋值.
           在else条件下:(此时是binder实体也就是BBinder对象)
                和上面类似也是对一些自己想要的变量进行赋值操作:obj.type = BINDER_TYPE_BINDER、obj.binder = reinterpret_cast<uintptr_t>
           (local->getWeakRefs())、obj.cookie = reinterpret_cast<uintptr_t>(local)。把local->getWeakRefs()强制转换然后存入到obj.binder
            然后就很关键了把这个Binder实体的地址强制转换然后保存在flat_binder_object的cookie变量当中!!(难道客户端通过这个去取?)
                 最后调用finish_flatten_binder(binder, obj, out)这个就是把obj也就是我们封装好的flat_binder_object写入到Pracel out当中。   
inline static status_t finish_flatten_binder(
const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
{
return out->writeObject(flat, false);//将这个flat_binder_obj写入到Parcel中去.
}
        接下来就是writeObject()了,把flat_binder_obj写到Parcel里面之内,还要记录这个flat_binder_obj在Parcel里面的偏移位置.
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:
*reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
 
// Need to write meta-data?
if (nullMetaData || val.binder != 0) {//如果有binder对象
mObjects[mObjectsSize] = mDataPos;//记录这个flat_binder_obj在Parcel里面的偏移位置,(mDataPos前面普通数据存入的量,)
//,如果进程间传输的数据间带有Binder对象的时候,Binder驱动程序需要作进一步的处理,以维护各个Binder实体的一致性,
acquire_object(ProcessState::self(), val, this);
mObjectsSize++;
}
 
// remember if it's a file descriptor
if (val.type == BINDER_TYPE_FD) {
if (!mAllowFds) {
return FDS_NOT_ALLOWED;
}
mHasFds = mFdsKnown = true;
}
 
return finishWrite(sizeof(flat_binder_object));//完成最终处理.
}
 
if (!enoughData) {
//......空间不足时候的一些处理
}
if (!enoughObjects) {
//......空间不足时候的一些处理
}
 
goto restart_write;
}

0 0
原创粉丝点击