1.IBinder的传递

Binder IPC通信中,Binder是通信的媒介,Parcel是通信的內容。远程调用过程中,其参数都被打包成Parcel的形式來传递。IBinder对象当然也不例外,在前一篇 Binder机制,从Java到C (4. Parcel) 中说到IBinder对象是能够进行进程间传递的。

下面就看一下IBinder对象在传递过程中会有什么变化。

在IPC通信的Proxy端,我们经常可以看到下面类似的代码,一些参数都会打包到Parcel中。看下面的data和reply。

  1. public void publishService(IBinder token,
  2. Intent intent, IBinder service) throws RemoteException {
  3. Parcel data = Parcel.obtain();
  4. Parcel reply = Parcel.obtain();
  5. data.writeInterfaceToken(IActivityManager.descriptor);
  6. data.writeStrongBinder(token);
  7. intent.writeToParcel(data, 0);
  8. data.writeStrongBinder(service);
  9. mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);
  10. reply.readException();
  11. data.recycle();
  12. reply.recycle();
  13. }

在IPC通信里,android是通过Parcel类的成员函数writeStrongBinder()向Parcel写入IBinder,再通过mRemote发送出去。

2.writeStrongBinder()

接下來就看一下writeStrongBinder()这个函数里做了什么。
/frameworks/base/core/java/android/os/Parcel.java

  1. public final class Parcel {

  2. /**
  3. * Write an object into the parcel at the current dataPosition(),
  4. * growing dataCapacity() if needed.
  5. */
  6. public final void writeStrongBinder(IBinder val) {
  7. nativeWriteStrongBinder(mNativePtr, val);
  8. }
  9. private static native void nativeWriteStrongBinder(int nativePtr, IBinder val);

  10. }

看,这里又调用了native方法,我们会发现Java 层的一些Parcel其实只是对C/C++层的一个封裝,大部分操作还是依靠JNI去调用Native的操作。
那看一下C++里对应的方法:

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

  1. static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
  2. {
  3. Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
  4. if (parcel != NULL) {
  5. const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
  6. if (err != NO_ERROR) {
  7. signalExceptionForError(env, clazz, err);
  8. }
  9. }
  10. }

最主要的就是ibinderForJavaObject 这个函数,继续跟踪代码:

/frameworks/base/core/jni/android_util_Binder.cpp

  1. sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
  2. {
  3. if (obj == NULL) return NULL;
  4.  
  5. if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { //mClass指向Java层中的Binder class
  6. JavaBBinderHolder* jbh = (JavaBBinderHolder*)
  7. env->GetIntField(obj, gBinderOffsets.mObject);
  8. return jbh != NULL ? jbh->get(env, obj) : NULL; //get() 返回一個JavaBBinder,继承自BBinder
  9. }
  10.  
  11. if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { //mClass 指向Java层的BinderProxy class
  12. return (IBinder*)
  13. env->GetIntField(obj, gBinderProxyOffsets.mObject); //返回一个BpBinder,mObject是它的地址值
  14. }
  15. ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
  16. return NULL;
  17. }

这个函数呢,就是根据传进来的Java对象找到对应的C++对象,这里的参数obj,可能会指向两种对象:Binder对象或者BinderProxy对象。这两个对象我们在RemoteService那一篇里其实就遇到过了,Binder对象呢就是Service里实现的那个mRemoteBinder,BinderProxy对象呢就是Activity里回调传进来的那个service。不记得的话,可以再看一下那一篇:Binder机制,从Java到C (1. IPC in Application Remote Service)

接着说,如果传进來的是Binder对象,那么就会把gBinderOffsets.mObject转化成JavaBBinderHolder, 并从中获得一个JavaBBinder对象。JavaBBinder继承自BBinder。(在RemoteService那一篇,Service会在onBind回调里把mRemoteBinder传给AMS,这里传递的就是Binder对象)

如果传进來的是BinderProxy對象。就会返回一个BpBinder,这个BpBinder的地址值就保存在gBinderProxyOffsets.mObject中。(在RemoteService那一篇,AMS要传递给Acticity的就是BinderProxy对象)。

到这里,你可能会奇怪,为什么Service把Binder对象传递给AMS,后面AMS却是把BinderProxy对象传递给Activity呢?这个我们后面再说,(可以先说一下,其实是因为这些Binder对象都会经过底层传输,那在传输的过程中,Binder模块就会根据不同的情况对这些对象进行转化)

好吧,那还是接着说,有发送,当然会有接收,再來看一下Parcel的readStrongBinder():

3.readStrongBinder()

同样也是JNI调用:

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

  1. static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
  2. {
  3. ...
  4. return javaObjectForIBinder(env, parcel->readStrongBinder());
  5. }
  6.  
  7. /frameworks/base/core/jni/android_util_Binder.cpp
  8. jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) 1
  9. {
  10. if (val == NULL) return NULL;
  11. if (val->checkSubclass(&gBinderOffsets)) { 2 // One of our own!
  12. jobject object = static_cast<JavaBBinder*>(val.get())->object();
  13. LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
  14. return object;
  15. }
  16. ...
  17. jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
  18. if (object != NULL) {
  19. jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet); 3
  20. if (res != NULL) {
  21. ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
  22. return res;
  23. }
  24. ...
  25. }
  26. object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); 4
  27. if (object != NULL) {
  28. ….
  29. }
  30. return object;
  31. }

(1):这里的val和writeStrongBinder类似,不过是反过來,指向的可能是JavaBBinder或者BpBinder。

(2):如果是JavaBBinder,就会通过成员函數object(),返回一个Java对象,这个对象就是Java层的Binder对象。

(3):如果是BpBinder,那就先查找是否已經存在需要使用的BinderProxy对象,如果找到就返回引用

(4):如果沒找到可用的引用,就new 一个BinderProxy对象。

  1.  

4.Binder Module in Kernel

实际上,在Client端將参数打包成Parcel后,会发送到kernel的Binder module。在Binder module中,会有两种IBinder类型:BINDER_TYPE_BINDER,BINDER_TYPE_HANDLE。也对应着ava的本地对象和代理对象。

在Binder module收到数据后,会对不同的情况做进一步处理:
1.传來的IBinder类型是BINDER_TYPE_BINDER, 会将binder_type转化为BINDER_TYPE_HANDLE;

(这里理解起来有点别扭,因为只有在不同进程间传递IBinder时,才会把IBinder传递到kernel里,所以传递进來的IBinder必定是传递给別的process,不会是IBinder所在的process,这时,IBinder所在的process和发送目标process不是同一个,就需要改成BINDER_TYPE_HANDLE。如果IBinder是在同一个进程间传递,也不会进入到kernel里。所以一个BINDER_TYPE_BINDER类型的IBinder传进kernel,就必然需要转化成BINDER_TYPE_HANDLE)

2.传來的IBinder类型是BINDER_TYPE_HANDLE,会判断这个IBinder实体定义的process和发送的目标process是否相同,如果相同,就将binder_type转化成BINDER_TYPE_BINDER。如果不同,保持BINDER_TYPE_HANDLE。

因为只有不同进程间传递才会把IBinder发送到Binder module,所以在IBinder的传递中,可能会有2中可能。
1.process A → process B → process A
2.process A → process B → process C

这時候,对应的IBinder类型就会是:
1.BINDER_TYPE_BINDER → BINDER_TYPE_HANDLE → BINDER_TYPE_BINDER
2.BINDER_TYPE_BINDER → BINDER_TYPE_HANDLE → BINDER_TYPE_HANDLE

5.再看 Bind service

实际上,bind一个service的过程,也就是上述的第2中情況。

Binder机制,从Java到C (5. IBinder对象传递形式)的更多相关文章

  1. Binder机制,从Java到C (大纲)

    转载请标注:张小燕:http://www.cnblogs.com/zhangxinyan/p/3487381.html 前段时间一直在看有关Binder机制的内容,觉得受益匪浅,整理记录于此,大家请随 ...

  2. Binder机制,从Java到C (6. Binder in Native : libbinder)

    1.Java和C++中的Binder 从前一篇 Binder机制,从Java到C (5. IBinder对象传递形式) 中可以看到,使用Binder的Java代码,到最后都会进入到Native环境,将 ...

  3. 从mediaserver入手快速理解binder机制(最简单理解binder)【转】

    本文转载自;https://blog.csdn.net/u010164190/article/details/53015194 Android的binder机制提供一种进程间通信的方法,使一个进程可以 ...

  4. Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了A ...

  5. Binder机制,从Java到C (1. IPC in Application Remote Service)

    转载请标注:张小燕:http://www.cnblogs.com/zhangxinyan 1. Application 中的 service 我们知道Android中Service有三种类型:Loca ...

  6. Binder机制,从Java到C (2. IPC in System Service :AMS)

    1.建立Activity和Service的IPC之前 在上一篇 Binder机制,从Java到C (1. IPC in Application Remote Service)  里面有说到Activi ...

  7. Binder机制,从Java到C (3. ServiceManager in Java)

    上一篇 Binder机制,从Java到C (2. IPC in System Service :AMS)  中提到 Application是通过ServiceManager找到了AMS 的servic ...

  8. Binder机制,从Java到C (8. ServiceManager in Native)

    在第三篇 Binder机制,从Java到C (3. ServiceManager in Java) 中,讲到ServiceManager的Stub端在Native,Proxy端在Java.实际上,还要 ...

  9. Android中的Binder机制的简要理解

    转载自:http://www.linuxidc.com/Linux/2012-07/66195.htm http://blog.csdn.net/sunxingzhesunjinbiao/articl ...

随机推荐

  1. 照片详细解释YUV420数据格式

    YUV格式有两大类:planar和packed. 对于planar的YUV格式.先连续存储全部像素点的Y.紧接着存储全部像素点的U.随后是全部像素点的V. 对于packed的YUV格式,每一个像素点的 ...

  2. Select与SelectMany的区别

    Select() 和 SelectMany() 的工作都是依据源值生成一个或多个结果值. Select() 为每个源值生成一个结果值.因此,总体结果是一个与源集合具有相同元素数目的集合.与之相反,Se ...

  3. Swift游戏开发实战教程(霸内部信息大学)

    Swift游戏开发实战教程(大学霸内部资料) 试读下载地址:http://pan.baidu.com/s/1sj7DvQH 介绍:本教程是国内第一本Swift游戏开发专向资料. 本教程具体解说记忆配对 ...

  4. ReactJS.NET 开发

    初探ReactJS.NET 开发   ReactJS通常也被称为"React",是一个刚刚在这场游戏中登场的新手.它由Facebook创建,并在2013年首次发布.Facebook ...

  5. hibernate tools连接数据报错

    报如下的错误: An internal error occurred during: "Fetching children of Database". org.slf4j.spi. ...

  6. WeakReference and WeakHashMap

    弱引用通过WeakReference类实现,弱引用和软引用很像,但弱引用的引用级别更低.对于只有弱引用的对象而言,当系统垃圾回收机制运行时,不管系统北村是否足够,总会回收该对象所占用的内存.当然,并不 ...

  7. 【转】UiAutomator简要介绍

    原文地址:http://blog.csdn.net/g19920917/article/details/16131565 3.1.必备条件: 1.JDK    2.SDK(API高于15)    3. ...

  8. python解析命令行

    可以解析这样的命令 ./cron_ctrl jobname1 --stop ;./cron_ctrl jobname1 --start;./cron_ctrl jobname1 --list #!/u ...

  9. java 集装箱 arraylist 用法

    1. ArrayList概述: ArrayList 是一个数组队列.相当于 动态数组. 与Java中的数组相比.它的容量能动态增长.它继承于AbstractList.实现了List, RandomAc ...

  10. 详解linux vi命令用法

    vi是所有UNIX系统都会提供的屏幕编辑器,它提供了一个视窗设备,通过它可以编辑文件.当然,对UNIX系统略有所知的人,或多或少都觉得vi超级难用,但vi是最基本的编辑器,所以希望读者能好好把它学起来 ...