两种AIDL用法分析(原)

原创 2013年09月27日 10:11:19
        我们在前面介绍了关于AIDL的两种用法,第一种用法主要用在应用层中(应用层的AIDL调用),第二种用法主要用在framework中(Framework中的AIDL调用)。但是这两种用法中都提到了Stub、asInterface等关键字,在这一节中我们主要针对AIDL内部机制的分析来深入理解AIDL调用的过程。
        为了便于分析,我们还拿第一节中我们自己搭建的例子去分析。
        当时我们在Eclipse Android工程的Java包目录中建立了一个扩展名为aidl的文件(IMyService.aidl),并写下需要的接口。Eclipse会在gen目录下生成一个IMyService.Java的文件。

一、整体结构

        我们打开IMyService.Java文件查看,发现他的结构是这样的:

  public interface IMyService extends android.os.IInterface {
      //可以看出,Stub其实是一个实现了IMyService的Binder抽象类。
      public static abstract class Stub extends android.os.Binder implements aidl.pac.IMyService {
          public Stub() {
          }
          //把远程Service的Binder对象传递进去,得到的是远程服务的本地代理
          public static aidl.pac.IMyService asInterface(android.os.IBinder obj) {
          }
          public android.os.IBinder asBinder() {
          }
          //两个不同进程之间传递是通过onTransact接口完成的
          public boolean onTransact(int code, android.os.Parcel data,    android.os.Parcel reply, int flags)
                  throws android.os.RemoteException {
          }
          //远程服务的本地代理,当然也会继承自IMyService
          private static class Proxy implements aidl.pac.IMyService {
              private android.os.IBinder mRemote;
              //构造函数
              Proxy(android.os.IBinder remote) {
              }
              public android.os.IBinder asBinder() {
              }
              public java.lang.String getInterfaceDescriptor() {
              }
              //调用的getValue其实就是这里。
              public java.lang.String getValue()
                      throws android.os.RemoteException {
          }
          //可以看到,系统将我们的方法转换成以FIRST_CALL_TRANSACTION为基准的数字。
          static final int TRANSACTION_getValue = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
      }
      public java.lang.String getValue() throws android.os.RemoteException;
  }

        下面是一个结构图:              整体上来看,IMyService.java文件中的IMyService类有一个Stub的内部类,还有一个getValue方法。这个方法就是我们在aidl中定义的方法。同时我们看到,生成的IMyService继承自IInterface,说明这也是一个接口,并没有对getValue进行实现。

        对于getValue这个方法,当我们在服务端的内部类中继承了IMyService.Stub抽象类以后,就需要对未曾实现的getValue方法进行定义。
        再来看IMyService的内部类Stub。这个内部类是一个实现了IMyService接口的Binder抽象类。内部有3个方法asInterface、asBinder、onTransact,还有一个内部类Proxy。

二、得到的远端Service对象

        现在我们来看一下客户端当初得到的服务端对象的情况,当我们连接上服务端后,会被动调用onServiceConnected方法:

        public void onServiceConnected(ComponentName name, IBinder service) {
            mIMyService = IMyService.Stub.asInterface(service);
        }

        在这里得到的service对象其实就是MyServiceImpl对象,他是实现了IMyService.Stub具体接口的IBinder。再来看一下asInterface:

        public static aidl.pac.IMyService asInterface(android.os.IBinder obj) {
            //通过asInterface得到的其实是远程Service的本地“代理”,而代理对象的参数是远程的服务端“obj”
            return new aidl.pac.IMyService.Stub.Proxy(obj);
        }

        可以看出,onServiceConnected参数是远程服务端的IBinder对象,返回值是IMyService.Stub.Proxy(obj),这里的Proxy是Stub的内部类:

        private static class Proxy implements aidl.pac.IMyService {}
        内部除了构造方法以外,只有getValue方法:
        //调用的getValue其实就是这里。
        public java.lang.String getValue()    throws android.os.RemoteException {
            _data.writeInterfaceToken(DESCRIPTOR);
            //mRemote是远程的服务对象的binder,通过transact与服务端交换数据
            mRemote.transact(Stub.TRANSACTION_getValue, _data, _reply,0);
            _reply.readException();
            _result = _reply.readString();
            return _result;
        }
        到这里我们看到,Proxy内部确实拥有服务端的各个方法,但这些方法并不是真实的实现,而只是通过mRemote.transact传输出去

        也就是说,在客户端通过mIMyService = IMyService.Stub.asInterface(service)得到的就是Proxy对象,可以通过这个对象间接的调用服务端的各个方法,而具体调用过程就是经过mRemote.transact传输给真正的Service(也就是MyService.MyServiceImpl类)
        那么,具体来说,我们是如何通过这个代理对象调用到真实的getValue呢?

三、如何通过代理对象调用远端Service方法

        在代理类的getValue方法中看到,他是调用了mRemote.transact的方法。

        而mRemote.transact的方法通过底层的Binder通讯,将数据传输给服务端进程,并调用服务端的onTransact方法:

        public boolean onTransact(int code, android.os.Parcel data,    android.os.Parcel reply, int flags){
            switch (code) {
                //客户端调用的getValue方法,最终由这里传输给服务端
                case TRANSACTION_getValue: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _result = this.getValue();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
        因为当初得到的远程服务对象是MyServiceImpl的对象,因此这里的this就指向了MyServiceImpl类。因此getValue方法就进入到了MyServiceImpl的内部,也就是远程服务端的内部。由此完成了一次完整的调用过程。

四、AIDL总结    

        1、AIDL要是实现的最终目标是跨进程访问,简单的说就是得到另一个进程的对象,并调用其方法。
        2、AIDL与接口类似,本质属性都是一个Interface(AIDL文件是IInterface,而Interface是继承自Interface的),而且都只定义了抽象方法,没有具体的实现,需要子类去实现。
        3、与接口不同的是:由AIDL生成的stub类本质上是一个Binder!这个类所生成的对象有两种方式可以传递给另外一个进程:
                3.a、一种是通过bindService的方式,绑定一个服务,而在绑定后,服务将会返回给客户端一个Binder的对象,此时可以把继承自stub的Binder传递给客户端。
                3.b、另外一种就是把继承自stub的类提升为系统服务,此时,我们通过ServiceManager去得到当前的系统服务,ServiceManager就会把目标Service的Binder对象传递给客户端。
        4、经过上面两种方法得到的Binder对象,就像得到了本地的某个对象一样,可以调用其远程的方法。


版权声明:本文为博主原创文章,未经博主允许不得转载。

Binder学习总结_native(1)

这几天一直在看binder的结构,感叹这样天才的设计。 现在只研究到binder的native框架,在IPCThreadState以下,真正的driver和数据交换还需要进一步研究。在此记录一些目前...
  • ljsbuct
  • ljsbuct
  • 2012年09月18日 15:08
  • 16184

AIDL原理解析

首先为什么需要aidl? 下面是不需要aidl 的binder的IPC通讯过程,表面上结构很简单,但是有个困难就是,客户端和服务端进行通讯,你得先将你的通讯请求转换成序列化的数据,然后调用transa...
  • xude1985
  • xude1985
  • 2013年07月03日 11:34
  • 16476

Android AIDL使用详解

1.什么是aidl:aidl是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间...
  • stonecao
  • stonecao
  • 2011年05月16日 17:56
  • 411441

理解Aidl中Stub和Stub.Proxy

前言 之前看Binder的时候,一直对aidl自动生成的Stub类和Stub.Proxy类感到很疑惑。为什么要创建两个类呢?他们的区别在哪呢?他们代表的意思又是什么呢? 本文尝试去解答这些问题。A...

Android 核心分析 之六 -----IPC框架分析 Binder,Service,Service manager

IPC框架分析 Binder,Service,Service manager  我首先从宏观的角度观察Binder,Service,Service Manager,并阐述各自的概念。从Linux的...
  • maxleng
  • maxleng
  • 2010年04月15日 22:15
  • 152863

Android 使用反射调用自定义AIDL **.Stub.asInterface(IBinder obj)、反射实现关机shutdown

自定义AIDL调用 如: 新增 com.android.internal.telephony.IVideoTelephony; 不使用反射时的调用方式如下(需依赖系统编译才能通过): pr...

Java工程使用axis的stub生成webservice客户端代码

Java工程使用axis的stub生成webservice客户端代码

android service中stub作用是什么?

AIDL(android 接口描述语言)是一个IDL语言,它可以生成一段代码,可以使在一个android设备上运行的两个进程使用内部通信进程进行交互。如果你需要在一个进程中(例如:在一个Activit...

Android中 .stub类的使用

stub类是为了方便client,service交互而生成出来的代码。 AIDL(Android Interface Definition Language Android接口定义语言)实现进程...

Service跨进程调用服务三部曲之AIDL详解(三)

AIDL关于RemoteCallbackList的使用
  • yzwty
  • yzwty
  • 2016年07月16日 15:24
  • 635
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:两种AIDL用法分析(原)
举报原因:
原因补充:

(最多只允许输入30个字)