zoukankan      html  css  js  c++  java
  • Binder机制,从Java到C (1. IPC in Application Remote Service)

    转载请标注:张新燕:http://www.cnblogs.com/zhangxinyan

    1. Application 中的 service

    我们知道Android中Service有三种类型:Local ServiceLocal Bounded ServiceRemote Service

    Local Service:基本是提供给自已应用使用,通过startService(intent)来启动。

    Local Bounded Service:也是提供给自己应用使用,通过bindService(intent)启动,然后在回调中获得service,这种service一般很少写,因为既然只提供给自己使用,又何必从回调绕个圈子呢。用第一种service就好了。

    RemoteService:可以共享給更多使用者,这里就會涉及到IPC机制。在Android中,IPC机制是通过Binder来实现的。接下来就让我们开始看看Binder究竟是什么玩意吧~

    2.Remote Service:

    先来看看App层会遇到IPC的地方。
    我们在写App时,当遇到需要在后台默默做点什么事情时,就会采用Service这个组件,当你这个Service要大公无私的向外面提供服务时,我们会采用RemoteService这个玩意。下面我们就看一下怎么样来写一个RemoteService:

    1.先定義一個aidl文件在这个文件里写上这个Service可以完成的功能接口

    1 package com.example.remoteservice;  
    2     interface IRemoteService {  
    3         void doSomething ( );
    4     }  


    2.实现Remote Service写一个Service组件,在这个组件里,实现Stub(Stub是啥?后面有说)的具体功能,这些功能就对应了上面aidl文件里面定义的一些接口。
    接着在回调函数onBind()中把这个实现的Stub对象返回出去。那谁会来调用这个onBind()函数呢?当然是ActivityManagerService啦,有关与ActivityManagerService的详细内容会新开一篇详细说明。下面就看代码吧:

     1 public class RemoteService extends Service {
     2         @Override  
     3         public IBinder onBind(Intent intent) {  
     4            if (IRemoteService.class.getName().equals(intent.getAction())) {
     5                return mRemoteBinder;  //把一个Binder对象返回出去。其实是返回到AMS里面了。AMS:ActivityManagerService。
     6            }  
     7             return null;  
     8         }
     9         private final IRemoteService.Stub mRemoteBinder =new IRemoteService.Stub() {//实现Stub对象要求的方法,即AIDL的实现。
    10            public void dosomething() {
    11                blablabla;  
    12            }  
    13         };  
    14     }

    3.访问Remote Service接着就是在Activity里面启动和调用Service的功能了,怎么调用呢?看代码:

     1 public class Helloworld extends Activity  
     2 {  
     3     ...
     4     @Override  
     5     public void onCreate(Bundle savedInstanceState)  
     6     {  
     7        super.onCreate(savedInstanceState);  
     8        setContentView(R.layout.main);  
     9        bindService(new Intent(IRemoteService.class.getName()),mRemoteConnection,  
    10                     Context.BIND_AUTO_CREATE);  // 1.触发Service端回调onBind()。     (1)
    11        ...
    12        mRemoteService.getPid(); //3. 会通过Binder IPC 将操作请求发送到Service端的Stub实现。    (3)
    13        ...
    14     }  
    15 
    16     private ServiceConnection mRemoteConnection = new ServiceConnection() {
    17        public void onServiceConnected(ComponentName className, IBinder service) {     (2)
    18            Log.i("binder_test","IBinder service : " + service.getClass());//通过Log发现,这个service是BinderProxy object,BinderProxy是什么呢?後面再說。暂时按字面理解为Binder代理对象。
    19 
    20 
    21            mRemoteService = IRemoteService.Stub.asInterface(service); // 2.通过asInterface,把Binder代理对象转化成接口。
    22        }  
    23        public void onServiceDisconnected(ComponentName className) {  
    24            mRemoteService = null;  
    25        }  
    26 };     
    27 }   

    说明:
    (1)  :在这里调用bindService,最后其实会调用到AMS(ActivityManagerService)中。AMS就会去查找当前系统中有没有已经启动过这个Service了,如果没有启动这个Service,就把它启动起来。然后会调用它的onBind()回调,获得Service的Binder对象。再经过一系列处理后,从调用者 Activity 的 (2)这个地方回调回来,把service传给它,当然其中对象会有一些变化,我们在回调的这个地方把返回的service打印了出来:


    所以那个回调 onServiceConnected传进来的 IBinder service,它其实是一个BinderProxy!按照字面意思,我们称它为 Binder代理对象,先不管这个IBinder是来的,也不管BinderProxy到底是什么,先往下看,看下去你就会慢慢知道了。
    这个对象返回到Activity中之后,通过asInterface进行一个转化,转化成了接口,其实是转化成了Proxy对象啦,Proxy对象实现了接口。
    那这个转化得来的mRemoteService,我们以后就称之为 Service代理对象
    (3) :这样,获得了Service的代理对象之后,就可以通过Service代理对象调用Service的功能啦。虽然Service具体的执行是在另外一个进程,但是你是感觉不到的。

    3. AIDL 工具

    上面说的内容似乎有点乱,那我们整理下上面的访问过程,可以看一下下面的图:

    这里面的Stub对象Stub.Proxy对象,这些对象我们上面都没有创建吧?这些类其实都是由aidl工具自动生成的。

     Client中Activity,通过bindService,触发Service回调onBind()方法,把一个Binder代理对象返回给Client。

    Client通过转化,转化成一个Service代理对象,Client通过这个Service代理对象,在通过底层的Binder驱动,就可以调用进Service进程。在Service进程收到请求后,会根据里面的一个参数值,找到对应的函数,执行具体的操作。

    下面这个类就是用了aidl工具后,IRemoteService.aidl自动生成的对应的类:IRemoteService.java

     1 package com.example.remoteservice;  
     2 
     3     public interface IRemoteService extends android.os.IInterface { 1  
     4         public static abstract class Stub extends android.os.Binder implements  
     5                com.example.remoteservice.IRemoteService {//继承Binder,并且实现了IRemoteService接口
     6              ...
     7            public static com.example.remoteservice.IRemoteService asInterface(android.os.IBinder obj) {//根据传进來的IBinder对象创建一个Service 代理對象給客戶端。
     8                ...
     9                android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
    10                if (((iin != null) && (iin instanceof com.example.remoteservice.IRemoteService))) {  
    11                     return((com.example.remoteservice.IRemoteService) iin);  
    12                }  
    13                return new com.example.remoteservice.IRemoteService.Stub.Proxy(obj);  //看,返回的是Proxy这个对象。就是Service代理对象。
    14            }  
    15 
    16            public android.os.IBinder asBinder() {  
    17                return this;  
    18            }  
    19 
    20            @Override  
    21            public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,  
    22                     int flags)throwsandroid.os.RemoteException { //把IPC消息取出来解析,找到具体执行方法。
    23                switch (code) {  //根据code值,找到方法。
    24                     case INTERFACE_TRANSACTION: {  
    25                     }  
    26                     case TRANSACTION_doSomething: { 
    27                     }  
    28                }  
    29                return super.onTransact(code, data, reply, flags);    
    30            }  
    31 
    32            private static class Proxy implements com.example.remoteservice.IRemoteService {//实现了IRemoteService接口
    33                private android.os.IBinder mRemote; //实际上是BinderProxy对象
    34               ...
    35                public int doSomething() throws android.os.RemoteException {
    36                      ...
    37                         mRemote.transact(Stub.TRANSACTION_doSomething,_data, _reply, 0);//通过BinderProxy將命令发送出去。 
    38                     ….
    39            }  
    40             static final int TRANSACTION_doSomething = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);   //这玩意就是用来区别方法的code。
    41         }  
    42 
    43         public void doSomething() throwsandroid.os.RemoteException;   
    44     }  

    这里面呢,会涉及到几个类,Proxy啦,Binder啦等等,他们的关系图可以在下图中看出:

    那Stub和Proxy都实现了了IRemoteService。但是呢Proxy只是把参数包装一下,通过mRemote发送出去。

    Stub就是真正实现的地方了,不过这边实现的代码其实是写在Service里的,就是那个mRemoteBinder。

    Proxy类是Stub的一个子类。Proxy里面的mRemote就是BinderProxy,通过它就可以把请求发送出去,然后再通过底层Binder的一些操作,最后走到Service进程里去执行一些操作。

    那来总结一下吧,上面这個过程可以概括的说是:

    1.Activity通过AMS的bindService(String name),让AMS做一些查找操作,然后AMS把一個service的Binder代理对象返回给Activity。
    2.Activity通过一個转换,创建一個service代理对象Proxy,其是在Proxy里面,还是利用Binder代理对象向service发送命令。

    下一篇会将一下AMS里面的IPC机制:

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

  • 相关阅读:
    各种算法时空复杂度
    Python文本处理(1)
    数学之路(3)-机器学习(3)-机器学习算法-欧氏距离(3)
    为什么要选择cdn加速
    数据库中操作XML(openXML)
    HDU 3308 LCIS
    Android有效解决加载大图片时内存溢出的问题
    Pathchirp—有效的带宽估计方法(二)
    php三元运算
    C# MVC 自学笔记—4 添加视图
  • 原文地址:https://www.cnblogs.com/zhangxinyan/p/3487828.html
Copyright © 2011-2022 走看看