Android中AIDL的使用(二) 之 Binder和AIDL的原理

1 Binder原理

1.1 简介

Binder是Android中的一种跨进程通信方式,Android的四大组件、各种Manager 和其对应ManagerService等无不与Binder挂钩。从Android Framework角度来说,Binder是ServiceManager连接ActivityManager、WindowManager等Manager和他们相应ManagerService的桥梁; 从Android 应用层来说,Binder是客户端和服务端进行通信的媒介,正如我们在使用Service时bindService时, Service的onBind方法会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取Service中提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。

Binder单词翻译过来叫“粘合剂”,它的机制是将Client、Server、ServiceManager和Binder驱动粘合起来。其中Client、Server和Service Manager运行在用户空间,Binder驱动运行在内核空间。Service Manager和Binder驱动已经在Android平台中实现好,我们在开发过程中只要按照规范实现自己的Client和Server组件就可以了。

1.2内核空间 和 用户空间

Linux内核独立于普通的应用程序,它可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。内核和上层的应用程序抽像隔离开,分别称之为内核空间和用户空间。

1.3 ServiceManager

ServiceManager是整个Binder IPC通信过程中的守护进程,本身也是一个Binder服务,它的主要就两个工作就是查询和注册Service。

1.4 Binder驱动

用户空间可以通过系统提供的方法调用访问内核空间,而一个用户空间想与另外一个用户空间进行通信的话,就得使用Linux的动态可加载内核模块机制(Loadable Kernel Module,LKM),因为Android系统可以通过添加一个内核模块运行在内核空间,用户进程之间通过这个模块作为桥梁,就可以完成通信了,而这个负责各个用户进程通过Binder通信的内核模块程序叫做Binder驱动

1.5 通信过程

我们通过例子来讲述Binder的通信过程,当你想给你的朋友打电话时,那么你就是Client,而你的朋友就是Server,而电话公司就是ServiceManager,它系统里注册了很多人的电话号码。当你在拔打你朋友电话时,若你朋友电话号码是没有在电话公司注册过,就会返回空号的错误,也就是Server没有在ServiceManager中注册,否则就能拔打电话,在这个拔过电话过程中,是要通过基站来完成接线的,而基站就是Binder驱动。

 

2 AIDL原理

AIDL是Binder的延伸,它的使用我们在前面的文章《Android中AIDL的使用》已经介绍过。我们知道,当新建一个aidl文件后执行编译后,便会在app\build\generated\source\aidl\debug\目录下生成对应的同名的类文件。我们在日常开发中,大可不必理会此文件,也正因为此文件是自动生成和格式错乱使很多人对其望而止步。其实只要将该Java文件格式化后,就会清晰多了,这个类的结构其实很简单的。只要读懂该类,基本上就会明白AIDL的工作原理了。

现在我们就按照《Android中AIDL的使用》中介绍的步骤来通过一个最简单的示例来了解AIDL的原理,首先创建一个IMyAidl.aidl文件,内容如下:

package com.zyx.myapplication;

interface IMyAidl {
    int sum(int a, int b);
}

在执行编译后,就会在app\build\generated\source\aidl\debug\com\zyx\myapplication目录下生成IMyAidl.java文件。在介绍IMyAidl.java文件前,先来创建 Client端和Server端的调用代码。

Client端的MainActivity.Java代码:

public class MainActivity extends Activity {

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {

            IMyAidl myaidl = IMyAidl.Stub.asInterface(iBinder);
            try {
                myaidl.sum(1, 2);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public void onServiceDisconnected(ComponentName className) {
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }
    @Override
    protected void onDestroy() {
        unbindService(mConnection);
        super.onDestroy();
    }
}

Server端的MyService.Java代码:

public class MyService extends Service {
    private Binder mBinder = new IMyAidl.Stub() {
        @Override
        publicint sum(int a, int b) throws RemoteException {
            return a + b;
        }
    };
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

好的,动手敲的代码完成了,现在就来看看自动生成的代码是长什么样的,IMyAidl.java内容部分是这样:

package com.zyx.myapplication;

public interface IMyAidl extends android.os.IInterface {
    public static abstract class Stub extends android.os.Binder implements com.zyx.myapplication.IMyAidl {
        ……
    }
    public void sum(int a, int b) throws android.os.RemoteException;
}

IMyAidl.java文件中,存在一个继承自己的内部类Stub和我们在aidl中定义的sum方法。Stub就是一个Binder类。可以看出,它就是MyService中onBind方法return的mBinder对象的类。再来细看下Stub类的代码:

public static abstract class Stub extends android.os.Binder implements com.zyx.myapplication.IMyAidl {
    private static final java.lang.String DESCRIPTOR = "com.zyx.myapplication.IMyAidl";

    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }

    public static com.zyx.myapplication.IMyAidl asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof com.zyx.myapplication.IMyAidl))) {
            return ((com.zyx.myapplication.IMyAidl) iin);
        }
        return new com.zyx.myapplication.IMyAidl.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 {
        java.lang.String descriptor = DESCRIPTOR;
        switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(descriptor);
                return true;
            }
            case TRANSACTION_sum: {
                data.enforceInterface(descriptor);
                int _arg0;
                _arg0 = data.readInt();
                int _arg1;
                _arg1 = data.readInt();
                int _result = this.sum(_arg0, _arg1);
                reply.writeNoException();
                reply.writeInt(_result);
                return true;
            }
            default: {
                return super.onTransact(code, data, reply, flags);
            }
        }
    }

    private static class Proxy implements com.zyx.myapplication.IMyAidl {
        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 int sum(int a, int b) throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            int _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                _data.writeInt(a);
                _data.writeInt(b);
                mRemote.transact(Stub.TRANSACTION_sum, _data, _reply, 0);
                _reply.readException();
                _result = _reply.readInt();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }
    }

    static final int TRANSACTION_sum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}

下面我们来看看Stub类的变量和方法的含义:

DESCRIPTOR

DESCRIPTORBinder的唯一标识,一般用当前Binder的类名表示

asInterface

asInterface方法用于将ServerBinder对象转换成Client所需的AIDL接口类型的对象,正如我们可以看到asInterface方法就是我们在Client中代码:

IMyAidl myaidl = IMyAidl.Stub.asInterface(iBinder);
try {
    myaidl.sum(1, 2);
} catch (Exception e) {
    e.printStackTrace();
}

asInterface方法它的参数是接收由服务绑定成功后返回的一个IBinder对象,返回值一个AIDL接口类型的对象,从代码中可以发现,该对象有三种情况返回值,第一种因为参数输入错误所以返回了null 接着判断了ClientServer是否位于同一进程,如果是同一进程,则是第二情况,返回就是Server中的Stub对象本身,也就是本示例中就是MyService中的mBinder对象; 如果Client端和Server端不是同一进程,那么就是第三种情况,返回的是Stub类的内部代理类Proxy对象。而Client端中代码:myaidl.sum(1, 2);调用的就是Proxy类的sum方法。

Proxy

Proxy类是内部类Stub的内部代理类,同样也是继承于IMyAidl.java。它的sum方法会使用Parcelable来准备数据,把参数都写入_data,让_reply接收方法返回值。最后使用IBinder的transact方法把数据传给Binder的Server端去。代码中mRemote就是asInterface方法接收的参数obj。这时当前线程挂起,Server端的onTransact方法会被调用。

onTransact

onTransact方法是运行在Server中的Binder线程池中的,当Client端发起跨进程请求时,远程请求会通过系统底层封装后交由onTransact方法来处理。通过TRANSACTION_sum找到对应的方法sum,接着从data中取出从Client端进程传递过来的参数,然后执行目标方法sum,在执行完毕后就向reply中写入返回值。此时,Proxy中的sum方法线程恢复执行。

总结

到这里,自动生成的对应AIDL文件对应类就介绍完了,理解清楚这个类就是等于理解清楚AIDL的工作原理。我们在实际开发中其实也可以通过自己手动敲出该类来实现,这样做跟使用AIDL文件是一样的,不过一般情况下我们都不会这样做,因为使用AIDL文件实在太方便了,它是系统为我们提供了一种高效快捷实现Binder的工具。

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值