zoukankan      html  css  js  c++  java
  • Android AIDL——实现机制浅析

    1.基于前面写的aidl使用,这段时间准备研究ActivityManager框架,对aidl进行了更深入的研究,因为android框架大量使用了进程通信机制,所以,在研究android framework前认真研究一下AIDL的实现机制十分有必要的

      2.前面讲了aidl是 Android Interface definition language的缩写,它是一种进程通信接口的描述,通过sdk解释器对器进行编译,会把它编译成java代码在gen目录下,类路径与aidl文件的类路径相同。

      3.aidl接口
    package com.cao.android.demos.binder.aidl; 
    import com.cao.android.demos.binder.aidl.AIDLActivity;
    interface AIDLService {  
        void registerTestCall(AIDLActivity cb);  
        void invokCallBack();
    }

    它编译后生成的java文件如下

    AIDLService.java详细描述了aidl接口的实现,看上面图示,AIDLActivity.aidl编译成了一个接口AIDLActivity,一个存根类Stub,一个代理类Proxy
    public interface AIDLService extends android.os.IInterface//与AIDLActivity.aidl中定义的接口对应的java接口实现
    public static abstract class Stub extends android.os.Binder implements com.cao.android.demos.binder.aidl.AIDLService
    //继承android.os.Binder,在onTransact完成对通信数据的接收,通过不同通信参数code调用AIDLService接口方法,并回写调用返回结果AIDLService接口方法需要在
    //服务端实现
    private static class Proxy implements com.cao.android.demos.binder.aidl.AIDLService
    //实现AIDLService接口方法,但是方法只是执行代理远程调用操作,具体方法操作在远端的Stub存根类中实现

    总的来说,AIDLActivity.aidl编译会生成一个AIDLActivity接口,一个stub存根抽像类,一个proxy代理类,这个实现其实根axis的wsdl文件编译生成思路是一致的,
    stub存根抽像类需要在服务端实现,proxy代理类被客户端使用,通过stub,proxy的封装,屏蔽了进程通信的细节,对使用者来说就只是一个AIDLActivity接口的调用

      4.根据以上思路使用aidl再看一下AIDLService调用实现代码
    --1.在服务端实现AIDLService.Stub抽象类,在服务端onBind方法中返回该实现类
    --2.客户端绑定service时在ServiceConnection.onServiceConnected获取onBind返回的IBinder对象
            private ServiceConnection mConnection = new ServiceConnection() {
                    public void onServiceConnected(ComponentName className, IBinder service) {
                            Log("connect service");
                            mService = AIDLService.Stub.asInterface(service);
                            try {
                                    mService.registerTestCall(mCallback);
                            } catch (RemoteException e) {

                            }
                    }
            注意mConnection在bindservice作为调用参数:bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    --3.AIDLService.Stub.asInterface(service);
    public static com.cao.android.demos.binder.aidl.AIDLService asInterface(android.os.IBinder obj)
    {
    if ((obj==null)) {
    return null;
    }
    android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
    //如果bindService绑定的是同一进程的service,返回的是服务端Stub对象本省,那么在客户端是直接操作Stub对象,并不进行进程通信了
    if (((iin!=null)&&(iin instanceof com.cao.android.demos.binder.aidl.AIDLService))) {
    return ((com.cao.android.demos.binder.aidl.AIDLService)iin);
    }
    //bindService绑定的不是同一进程的service,返回的是代理对象,obj==android.os.BinderProxy对象,被包装成一个AIDLService.Stub.Proxy代理对象
    //不过AIDLService.Stub.Proxy进程间通信通过android.os.BinderProxy实现
    return new com.cao.android.demos.binder.aidl.AIDLService.Stub.Proxy(obj);
    }
    --4.调用AIDLService接口方法,如果是同一进程,AIDLService就是service的Stub对象,等同直接调用Stub对象实现的AIDLService接口方法
    如果是一个proxy对象,那就是在进程间调用了,我们看一个客户端调用的例子:
                            public void onClick(View v) {
                                    Log("AIDLTestActivity.btnCallBack");
                                    try {
                                            mService.invokCallBack();
                                    } catch (RemoteException e) {
                                            // TODO Auto-generated catch block
                                            e.printStackTrace();
                                    }
            --mService.invokCallBack()等同调用Proxy.invokCallBack,这个时候是进程间调用,我们看代理方法的实现
    public void invokCallBack() throws android.os.RemoteException
    {
    //构造一个Parcel对象,该对象可在进程间传输
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
    //DESCRIPTOR = "com.cao.android.demos.binder.aidl.AIDLService",描述了调用哪个Stub对象
    _data.writeInterfaceToken(DESCRIPTOR);
    //Stub.TRANSACTION_invokCallBack 标识调用Stub中哪个接口方法,mRemote在是构造Proxy对象的参数obj,也就是public void onServiceConnected(ComponentName className, IBinder service)
    //中的service参数,它是一个BinderProxy对象,负责传输进程间数据。
    mRemote.transact(Stub.TRANSACTION_invokCallBack, _data, _reply, 0);
    _reply.readException();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    }
    --5.BinderProxy.transact 该方法本地化实现
       public native boolean transact(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException;
            //对应实现的本地化代码 /frameworks/base/core/jni/android_util_Binder.cpp->static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
                                                    jint code, jobject dataObj,
                                                    jobject replyObj, jint flags)
      //具体进程通信在c代码中如何实现,以后再深入研究。
    --6.服务端进程数据接收
            --调用堆栈
            ##AIDLService.Stub.onTransact
            ##AIDLService.Stub(Binder).execTransact
            ##NativeStart.run
            --AIDLService.Stub.onTransact
            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_registerTestCall:
    {
    data.enforceInterface(DESCRIPTOR);
    com.cao.android.demos.binder.aidl.AIDLActivity _arg0;
    _arg0 = com.cao.android.demos.binder.aidl.AIDLActivity.Stub.asInterface(data.readStrongBinder());
    this.registerTestCall(_arg0);
    reply.writeNoException();
    return true;
    }
    //TRANSACTION_invokCallBack由前面客户端调用的时候transact方法参数决定,code==TRANSACTION_invokCallBack,执行
    //invokCallBack方法,方法由继承Stud的服务端存根类实现。
    case TRANSACTION_invokCallBack:
    {
    data.enforceInterface(DESCRIPTOR);
    this.invokCallBack();
    reply.writeNoException();
    return true;
    }

    5.里面设置本地C代码的调用,我没有深入研究,随着后面我对android框架的深入,我会发blog进一步说民底层C代码是如何实现进程通信的,关于AIDL进程通信,暂时研究到这里。

    原文:http://blog.csdn.net/stonecao/article/details/6579333

  • 相关阅读:
    ASP.NET Web API模型验证以及异常处理方式
    Javascript基础恶补
    求一个集合的集合下所有集合元素求值
    C#创建唯一的订单号, 考虑时间因素
    git的几十个基本面
    报错:ASP.NET Web API中找不到与请求匹配的HTTP资源
    使用RAML描述API文档信息的一些用法整理
    Postman测试Web API
    Javascript中的Prototype到底是啥
    AngularJS和DataModel
  • 原文地址:https://www.cnblogs.com/xiaoxiaoboke/p/2342921.html
Copyright © 2011-2022 走看看