老罗的ANDROID之旅---IPC学习笔记

下面所涉及到的内容基本上都来自---老罗的Android之旅


在Android系统的Binder机制中,由一系统组件组成,分别是Client、Server、Service Manager和Binder驱动程序,其中Client、Server和Service Manager运行在用户空间,Binder驱动程序运行内核空间。Binder就是一种把这四个组件粘合在一起的粘结剂了,其中,核心组件便是Binder驱动程序了,Service Manager提供了辅助管理的功能,Client和Server正是在Binder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。Service Manager和Binder驱动已经在Android平台中实现好,开发者只要按照规范实现自己的Client和Server组件就可以了。说起来简单,做起难,对初学者来说,Android系统的Binder机制是最难理解的了,而Binder机制无论从系统开发还是应用开发的角度来看,都是Android系统中最重要的组成,因此,很有必要深入了解Binder的工作方式。


Android系统Binder机制中的四个组件Client、Server、Service Manager和Binder驱动程序的关系如下图所示


说明;

1. Client、Server和Service Manager实现在用户空间中,Binder驱动程序实现在内核空间中

        2. Binder驱动程序和Service Manager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server

        3. Binder驱动程序提供设备文件/dev/binder与用户空间交互,Client、Server和Service Manager通过open和ioctl文件操作函数与Binder驱动程序进行通信

        4. Client和Server之间的进程间通信通过Binder驱动程序间接实现

        5. Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力


接下来我们通过以下几个情景来进一步对Binder源码进行分析,深入了解Binder机制

一:浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路

实在是太复杂,涉及的数据结构特别多,要理解好必须得对Linux内核,驱动等要好好掌握。。。。
下面用一时序图进行简要的梳理一下相关的流程。

总结一下,Service Manager是成为Android进程间通信(IPC)机制Binder守护进程的过程是这样的:

        1. 打开/dev/binder文件:open("/dev/binder", O_RDWR);

        2. 建立128K内存映射:mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);

        3. 通知Binder驱动程序它是守护进程:binder_become_context_manager(bs);

        4. 进入循环等待请求的到来:binder_loop(bs, svcmgr_handler);

        在这个过程中,在Binder驱动程序中建立了一个struct binder_proc结构、一个struct  binder_thread结构和一个struct binder_node结构,这样,Service Manager就在Android系统的进程间通信机制Binder担负起守护进程的职责了。


二:浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路

上面介绍了Service Manager是如何成为Binder机制的守护进程的。既然作为守护进程,Service Manager的职责当然就是为Server和Client服务了。那么,Server和Client如何获得Service Manager接口,进而享受它提供的服务呢?下面将简要分析Server和Client获得Service Manager的过程。

首先上一相关类图


说明:其中BpInterface是一个模板类,IServiceManager类继承了IInterface类,而IInterface类和BpRefBase类又分别继承了RefBase类。在BpRefBase类中,有一个成员变量mRemote,它的类型是IBinder*,实现类为BpBinder,它表示一个Binder引用,引用句柄值保存在BpBinder类的mHandle成员变量中。BpBinder类通过IPCThreadState类来和Binder驱动程序并互,而IPCThreadState又通过它的成员变量mProcess来打开/dev/binder设备文件,mProcess成员变量的类型为ProcessState。ProcessState类打开设备/dev/binder之后,将打开文件描述符保存在mDriverFD成员变量中,以供后续使用。

在了解了相关类之间的关系之后,我们从defaultServiceManager()开始进行代码的跟中,下面是其相关时序图:


也就是说在defaultServiceManager()中:最终的gDefaultServiceManager = new BpServiceManager(new BpBinder(0)。

这样,Service Manager远程接口就创建完成了,它本质上是一个BpServiceManager,包含了一个句柄值为0的Binder引用。

        在Android系统的Binder机制中,Server和Client拿到这个Service Manager远程接口之后怎么用呢?

        对Server来说,就是调用IServiceManager::addService这个接口来和Binder驱动程序交互了,即调用BpServiceManager::addService 。而BpServiceManager::addService又会调用通过其基类BpRefBase的成员函数remote获得原先创建的BpBinder实例,接着调用BpBinder::transact成员函数。在BpBinder::transact函数中,又会调用IPCThreadState::transact成员函数,这里就是最终与Binder驱动程序交互的地方了。回忆一下前面的类图,IPCThreadState有一个PorcessState类型的成中变量mProcess,而mProcess有一个成员变量mDriverFD,它是设备文件/dev/binder的打开文件描述符,因此,IPCThreadState就相当于间接在拥有了设备文件/dev/binder的打开文件描述符,于是,便可以与Binder驱动程序交互了。

       对Client来说,就是调用IServiceManager::getService这个接口来和Binder驱动程序交互了。具体过程上述Server使用Service Manager的方法是一样的。


下面就深入到Binder驱动程序这一层,进行详细的源代码分析,以便更好地理解Binder进程间通信机制。


三:Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析

MediaPlayerService为例,看其Server的启动过程:



在IServiceManager::addService过程中。对IServiceManager::addService过程中MediaPlayerService、ServiceManager和BinderDriver之间的交互不是很了解,附上老罗的一张它们三者之间的交互图



至此,Server就启动起来了,Server启动起来之后,就会在一个无穷循环中等待Client的请求了,下面我们将介绍Client如何通过Service Manager远程接口来获得Server远程接口,进而调用Server远程接口来使用Server提供的服务


四:Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析

以Android系统中自带的多媒体播放器为例子来说明Client是如何通过IServiceManager::getService接口来获得MediaPlayerService这个Server的远程接口的:下面是相关序列图



以上3、4的说明(来自评论)

首先server和client都调用了ProcessState的构造函数从而都向驱动申请了一块物理内存用于通信数据的存放,然后:
1.server调用SM的addService函数传递一个字符串和实际Binder对象在自己虚拟地址空间的地址到Binder驱动,Binder驱动记录下该地址值,在SM申请的物理内存中分配一个虚拟地址并连同字符串一起传递给SM,而且Binder驱动会记录下两个地址之间的对应关系.
2.client调用SM的getService函数传递一个字符串给SM,SM将相对应的虚拟地址值传递给Binder驱动,Binder驱动查询出实际对象的地址,在client申请的物理内存中分配一个虚拟地址并传递给client,而且Binder驱动会记录下这个地址和实际Binder对象地址之间的对应关系,client这里得到的就是实际Binder的引用了.
到了这一步,真正的Binder对象就拥有两个引用,一个在SM,一个client.
3.client通过得到的Binder引用调用server中的函数,驱动会根据传递过来引用值找到应该处理该请求的进程,并唤醒其中的Binder线程,调用BBinder对象的onTransaction函数,最终调用到实际的函数。



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



package android.os;  
interface IHelloService  
{  
    void setVal(int val);  
    int getVal();  
}  

public interface IHelloService extends android.os.IInterface  
{ 
	public void setVal(int val) throws android.os.RemoteException;  
  public int getVal() throws android.os.RemoteException;  
  
	public static abstract class Stub extends android.os.Binder implements android.os.IHelloService  
  {  
  	 static final int TRANSACTION_setVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 
  	 static final int TRANSACTION_getVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
  	 
 	   public Stub(){}
 	   public static android.os.IHelloService asInterface(android.os.IBinder obj){
 	   		...
 	   		return new android.os.IHelloService.Stub.Proxy(obj); 
 	   }
 	   public android.os.IBinder asBinder(){}
 	   public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  {
 	   		...
 	   		case TRANSACTION_setVal:  
 	   		...
 	   		case TRANSACTION_getVal:
 	   		...
 	   }
 	   
 	   private static class Proxy implements android.os.IHelloService 
 	   {
 	   		private android.os.IBinder mRemote;
 	   		Proxy(android.os.IBinder remote) {}
 	   		public android.os.IBinder asBinder() {}
 	   		public java.lang.String getInterfaceDescriptor() {}
 	   		public void setVal(int val) throws android.os.RemoteException {
 	   			...
 	   			mRemote.transact(Stub.TRANSACTION_setVal, _data, _reply, 0); 
 	   			...
 	   		} 
 	   		public int getVal() throws android.os.RemoteException {
 	   			...
 	   			mRemote.transact(Stub.TRANSACTION_getVal, _data, _reply, 0);
 	   			...
 	   		} 
 	   }
  }
  
}

这里我们可以看到IHelloService.aidl这个文件编译后的真面目,原来就是根据IHelloService接口的
定义生成相应的Stub和Proxy类,这个就是我们熟悉的Binder机制的内容了,即实现这个HelloService
的Server必须继续于这里的IHelloService.Stub类,而这个HelloService的远程接口就是这里的
IHelloService.Stub.Proxy对象获得的IHelloService接口

public class HelloService extends IHelloService.Stub {  
    private static final String TAG = "HelloService";  
  
    HelloService() {  
        init_native();  
    }  
  
    public void setVal(int val) {  
        setVal_native(val);  
    }     
  
    public int getVal() {  
        return getVal_native();  
    }  
      
    private static native boolean init_native();  
    private static native void setVal_native(int val);  
    private static native int getVal_native();  
}  


有了HelloService这个Server类后,下一步就是考虑怎么样把它启动起来了。
在frameworks/base/services/java/com/android/server/SystemServer.java文件中,定义了SystemServer类。
SystemServer对象是在系统启动的时候创建的,它被创建的时候会启动一个线程来创建HelloService,并且把它
添加到Service Manager中去。

class ServerThread extends Thread {  
    ......  
    @Override  
    public void run() {  
        ......  
        Looper.prepare();  
        ......  
        try {  
            Slog.i(TAG, "Hello Service");  
            ServiceManager.addService("hello", new HelloService());  //ServiceManagerProxy.addService()
        } catch (Throwable e) {  
            Slog.e(TAG, "Failure starting Hello Service", e);  
        }  
        ......  
        Looper.loop();  
        ......  
    }  
}  
  
......  
  
public class SystemServer  
{  
    native public static void init1(String[] args);  
    ......  
    public static final void init2() {  
        Slog.i(TAG, "Entered the Android system server!");  
        Thread thr = new ServerThread();  
        thr.setName("android.server.ServerThread");  
        thr.start();  
    }  
    ......  
}  


而Client端就是借助Service Manager这个Java远程接口来获得HelloService的远程接口的:
public class Hello extends Activity implements OnClickListener {    
    ......   
    private IHelloService helloService = null;    
    ......  
    @Override    
    public void onCreate(Bundle savedInstanceState) {    
        helloService = IHelloService.Stub.asInterface(ServiceManager.getService("hello"));  
        //====》
        //helloService = IHelloService.Stub.asInterface(ServiceManagerProxy.getService("hello"));  
        //====》
        //helloService = IHelloService.Stub.asInterface(new BinderProxy()));  
        //====>>
        //helloService = android.os.IHelloService.Stub.Proxy(new BinderProxy()); 
    }  
    ......  
}  

 这样,我们就获得了HelloService的远程接口了,它实质上是一个实现了IHelloService接口的IHelloService.Stub.Proxy对象。
 
 然后通过client端的helloService.getVal以及setVal来调用android.os.IHelloService.Stub.Proxy的setVal、getVal进而调用
 mRemote.transact来请求HelloService执行TRANSACTION_getVal操作。经过一大圈又回到android.os.IHelloService.Stub的onTransact
 来执行相关的调用......函数最终又调用了HelloService.getVal函数,最终,经过层层返回,就回到IHelloService.Stub.Proxy.getVal函数中来



呵呵,胡乱瞎凑完了。。。。

----------------------------------------------------谢谢 老罗的Android之旅-------------------------------------------------------------------


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值