AIDL小结

来源:互联网 发布:应用数据可以删除吗 编辑:程序博客网 时间:2024/06/05 08:26

    

系统服务依赖的是Binder构架。


Binder和BinderProxy直接继承IBinder。


通信:服务Proxy(如:ActivityManagerService)通过BinderProxy,再通过BpBinder,再将请求传到Binder驱动。Binder驱动通过ServiceManager得到注册的IBinder对应的JavaBBinder,再层层上到java层的真正服务对象。这样可以实现跨进程通信。


在以上的构架基础上,ADIL为我们简化了整个通信的搭建过程。

首先,你要定义一个aidl格式的文件,如:

package com.udnderstanding.samples;

interface ImyServer{

   int foo(String str);

}

这样就定义了一个名为IMyServer的Binder服务,并提供了一个可以跨Binder调用的接口foo()。

一个AIDL文件将被aidl工具解析成三个产物:

1.IMyServer接口:它仅仅用来在Java 中声明IMyServer.aidl中所声明的接口。

2.IMyServer.Stub类:这个继承自Binder类的抽象类实现了Bn端与Binder通信相关的代码

3.IMyServer.Stub.Proxy类。这个类实现了Bp端与Binder通信相关的代码。

在完成爱的了解析后,为了实现一个Bn端,开发者需要继承IMyServer.Stub类并实现其抽象方法。

每个MyServer实例都具有了作为Bn端的能力。

典型用法:

1.将MyServer类的实例通过ServiceManager.addService(String name, IBinder service)将其注册为一个系统服务。

2.在一个Android标准Service的onBind()方法中将其作为返回值使之可以被其他进程访问

3.通过binder调用将其传递给另外一个进程,使之成为一个跨进程的回调对象。

但是殊途同归,在Bp端所在进程中,一旦获取了IMyServer的BinderProxy(通过ServiceManager.geService()、onSrviceConnected()、或者其他方式),就可以通过如下方式获得一个IMyServer.Proxy:

//就是最终需要获得com.understanding.samples.IMyServer.Stub.Proxy,asInterface()返回就是这个类型

IMyServer remote = IMyServer.Stub.asInterface(binderProxy);

remote.foo("Hello AIDL");




下面是aidl工具自动解析成的文件。

public interface IMyServer extends android.os.IInterface{

    //自动生成一个内部类

    public static abstract class Stub extends android.os.Binder implements com.understanding.samples.IMyServer{


/********code:对应不同的方法,表示proxy所需调用的方法。

data:从proxy打包传过来的参数

在proxy发出请求后,最终会调用Stub的子类的onTransact()方法,而onTransact()中会调用foo(),所以子类需实现foo()

*/

          public boolena onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)

           throws android.os.RemoteException{

              switch(code){

                   ......

               case TRANSACTION_foo:{

                   ......//从data中读取参数_arg0

            //Stub类的子类需要实现foo()方法

                  int _result = this.foo(_arg0);

                  ......//向reply中写入_result

                  return true;

                    }

               }

        return super.onTransact(code, data, reply, flags);

        }

    


     //这是Bp端(客户端)实现。这边foo和Bn端(服务端)的foo是不一样的,虽然名字一样。名字一样的原因在于为了更好的让别人知道

//调用了Bp端的foo对应会调用Bn端的foo。Bp端的foo()的逻辑是固定的,就是将传过来的参数打包传Bn端。

      private static class Proxy implements com.understanding.samples.IMyServer{

            ......//Proxy类的其他实现

           public int foo(java.lang.String str)

                 throws android.os.RemoteException{

              android.os.Parcel _data = android.os.Parcel.obtain();

             android.os.Parcel _reply = android.os.Parcel.obtain();

             int _result;

              try{

                  ......//将参数str写入_data

           //mRemot就是指向IMyServer Bn端的BinderProxy;可能会阻塞等待返回结果

                 mRemot.transact(Stub.TRANSCATION_foo, _data, reply, 0);

                 ......//从_replay中读取返回值_result

                    } finally{

                        ......

                    }

          return _result;

               }

                static final int TRANSACTION_foo = (android.os.Ibinder.FIRST_CALL_TRANSCATION + 0);

         }


    }

     //声明IMyServer所提供的接口。

     public int foo(java.lang.String str) throws android.os.RemoteException;

}



下面说说AIDL在AS上的操作:(以下demo参考自:http://blog.csdn.net/u011974987/article/details/51243539)

首先在new file 中选择AIDL,会自动生成一个名为“aidl”与java文件夹同级的文件夹,aidl文件就放在该文件夹下。注意包名和java文件一样是文件夹的路径。

// IMyInterface.aidlpackage com.example.zhangjinbiao.aidltest;// Declare any non-default types here with import statementsinterface IMyInterface {    String getInfor(String s);}

写一个Service,在Service中返回一个IBinder(就是服务端stub的子类),然后在使用的时候调用asInterface(IBinder)转为IMyInterface(IInterface),该方法最终会返回一个Proxy。所以客户端最终使用的是Proxy。

下面是客户进程代码:

public class MainActivity extends AppCompatActivity {    public final static String TAG = "AIDLTEST_MainActivity";    private IMyInterface myInterface;    private ServiceConnection serviceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            myInterface = IMyInterface.Stub.asInterface(service);            Log.i(TAG, "连接Service 成功");            try {                String s = myInterface.getInfor("我是Activity传来的字符串");                Log.i(TAG, "从Service得到的字符串:" + s);            } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.e(TAG, "连接Service失败");        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        startAndBindService();    }    private void startAndBindService() {        Intent service = new Intent(MainActivity.this, MyService.class);        //startService(service);        bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);    }}

下面是服务端进程代码:

public class MyService extends Service {    public final static String TAG = "AIDLTEST_MyService";    private IBinder binder = new IMyInterface.Stub() {        @Override        public String getInfor(String s) throws RemoteException {            Log.i(TAG, s);            return "我是 Service 返回的字符串";        }    };    @Override    public void onCreate() {        super.onCreate();        Log.i(TAG, "onCreat");    }    @Override    public IBinder onBind(Intent intent) {        return binder;    }}

需要在Manifest中声明:

<service            android:name=".MyService"            android:process="com.xu.remote" />
声明该Service在独立进程中。


下面是自动生成的IMyInterface.java文件:

/* * This file is auto-generated.  DO NOT MODIFY. * Original file: /home/zhangjinbiao/AndroidStudioProject/AIDLTest/app/src/main/aidl/com/example/zhangjinbiao/aidltest/IMyInterface.aidl */package com.example.zhangjinbiao.aidltest;// Declare any non-default types here with import statementspublic interface IMyInterface extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements com.example.zhangjinbiao.aidltest.IMyInterface{private static final java.lang.String DESCRIPTOR = "com.example.zhangjinbiao.aidltest.IMyInterface";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an com.example.zhangjinbiao.aidltest.IMyInterface interface, * generating a proxy if needed. */public static com.example.zhangjinbiao.aidltest.IMyInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.example.zhangjinbiao.aidltest.IMyInterface))) {return ((com.example.zhangjinbiao.aidltest.IMyInterface)iin);}return new com.example.zhangjinbiao.aidltest.IMyInterface.Stub.Proxy(obj);}@Override public android.os.IBinder asBinder(){return this;}@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{switch (code){case INTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);return true;}case TRANSACTION_getInfor:{data.enforceInterface(DESCRIPTOR);java.lang.String _arg0;_arg0 = data.readString();java.lang.String _result = this.getInfor(_arg0);reply.writeNoException();reply.writeString(_result);return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements com.example.zhangjinbiao.aidltest.IMyInterface{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}@Override public android.os.IBinder asBinder(){return mRemote;}public java.lang.String getInterfaceDescriptor(){return DESCRIPTOR;}@Override public java.lang.String getInfor(java.lang.String s) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeString(s);mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);_reply.readException();_result = _reply.readString();}finally {_reply.recycle();_data.recycle();}return _result;}}static final int TRANSACTION_getInfor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);}public java.lang.String getInfor(java.lang.String s) throws android.os.RemoteException;}



注意:AIDL一般是阻塞式调用,就像调用一般方法一样,要非阻塞调用需要设置IBinder接口类中打FLAY_ONEWAY字段.,在native曾中涉及到Binder调用打基本是阻塞式,而java framework层一般非阻塞式的.









0 0