搜索
您的当前位置:首页正文

Binder和AIDL实例及原理解析

来源:二三娱乐

AIDL和Binder简介

  • 他们都与IPC(远程调用)有关
  • Binder是一个实现IBinder的类,提供了两个与Binder驱动通信的重要接口方法,你可以通过它实现自定义的RPC协议(ClientServerService Manager
    (1)Transact():客户端调用,用于发送调用请求
    (2)onTransact():服务端响应,用于接收调用请求
  • Service与客户端通信,有两种方式,AIDL和Messenger。AIDL基于Binder,而Messenger基于AIDL。
  • AIDL是android提供的接口定义语言,借助这个工具,你可以很轻松地实现IPC通信机制,根据需要灵活定义接口。
  • 作用范围:
    (1)Binder:如果是在一个应用里实现远程调用,使用Binder即可,没必要使用AIDL。
    (2)AIDL:如果涉及到在多个应用程序之间使用IPC通信,并且在服务又有多线程业务处理,这时可以使用AIDL。

Binder

pic1.jpeg

注意:Client、Server、ServiceManager之间是相互独立互不干涉,都是通过Binder驱动进行交互的

Binder的进程间通信,一共有四个角色:

  • Client:客户端(使用服务的进程)

  • Server:服务端(提供服务的进程)

  • ServiceManager:
    (1) ServiceManager 是 Binder 进程间通信的核心组件之一,扮演者 Binder 进程间通信机制的上下文管理者 ( Context Manager ) 的角色。
    (2)负责管理系统中的 Service (如AMS)组件,并且向 Client 组件提供获取 Service 代理对象的服务(开启循环,处理IPC请求)。

  • Binder驱动:底层的驱动架构与Linux驱动一样。binder驱动在以misc设备进行注册,作为虚拟设备,没有直接操作硬件,只是对设备内存的处理。主要是驱动设备的初始化binder_init,打开 binder_open,映射binder_mmap,数据操作binder_ioctl
    (1) binder_init: 注册驱动
    (2) binder_open: 创建一个struct binder_proc数据结构来保存打开设备文件/dev/binder的进程的上下文信息
    (3) binder_mmap : 进程空间和内核空间的虚拟地址映射到同一个物理页面,从而达到进程空间和内核空间共享一块物理页面的目的

    为什么要这么映射地址呢?

    把同一块物理页面同时映射到进程空间和内核空间时,当需要在两者之间传递数据时,只需要其中任意一方把数据拷贝到物理页面,另一方直接读取即可,也就是说,数据的跨进程传递,只需要一次拷贝就可以完成。
    用户进程 --拷贝--> 物理页面 <--直接读取-- 内核进程
    (4) binder_ioctl : 两个进程间收发IPC数据和IPC reply数据

    说到Binder驱动你必须理解两个概念
    共享内存(Share Memory)

    共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在该进程的地址空间中。其他进程可以将同一段共享内存连接到自己的地址空间中。所有进程都可以访问共享内存中的地址,如果一个进程向共享内存中写入了数据,所做的改动将立刻被其他进程看到。

    共享内存是IPC最快捷的方式,共享内存方式直接将某段内存段进行映射,多个进程间的共享内存是同一块的物理空间,仅仅映射到各进程的地址不同而已,因此不需要进行复制,可以直接使用此段空间
    共享内存本身并没有同步机制,需要程序员自己控制。

    内存映射(Memory Map)

    内存映射是由一个文件到一块内存的映射,在此之后进程操作文件,就像操作进程空间里的内存地址一样了。

Binder实例

Client-ServiceManager-Server时序图

pic6.jpeg
流程如下:
  • 第一步Server端通过Binder驱动向ServiceManager注册信息,在Binder驱动创建mRemote对象。(传递的参数打包成Parcel对象transact()
  • 第二步Client端通过Binder驱动向ServiceManager请求Server的Binder引用,然后Binder驱动将对应的mRemote对象返回
  • 第三步Client获得Binder引用(mRemote对象,该对象对应如下示例中的MyServiceProxy对象)后,通过调用mRemote对象中的callHi方法将传递的参数打包成Parcel对象再通过transact()向Binder驱动层写入,这个时候Client端的线程会挂起,而Server端中的onTransact方法收到Binder驱动层的回调后,会进行执行指令从而调用真正的callHi执行其逻辑,执行成功后会调用reply.writeNoException进行应答,而Binder驱动收到应答后会唤醒Client端被挂起的线程
    p8.jpeg
如果还是看不懂,我们直接上栗子来看吧,这样会更加直观些。

1 Server端

1.1 定义IMyService接口

public interface IMyService extends IInterface {
    //DESCRIPTOR是唯一标识
    static final java.lang.String DESCRIPTOR = " com.shengyuan.Server";
    //TRANSACTION_say是binder通信的cmd
    static final int TRANSACTION_say = android.os.IBinder.FIRST_CALL_TRANSACTION; 
    //service中的接口,提供给客户端用实现某些功能
    public void callHi(String str) throws RemoteException ;
}

1.2 继承Binder,实现IMyService接口,重写onTransact方法

public class MyService extends Binder implements IMyService{
//继承自Binder实现IMyService接口

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

    @Override
    public IBinder asBinder() {
        return this;
    }

    public static com.shengyuan.IMyService asInterface(android.os.IBinder obj) {
        if ((obj == null)) return null;
        android.os.IInterface iInterface = obj.queryLocalInterface(DESCRIPTOR);
        if (( iInterface != null && iInterface instanceof com.shengyuan.IMyService)){
            return ((com.shengyuan.IMyService) iInterface);
        }
        return null;
    }

    @Override
    protected boolean onTransact(
            int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        //该方法主要用于接收binder驱动的回传信息
        switch (code) {
        case INTERFACE_TRANSACTION: {
            reply.writeString(DESCRIPTOR);
            return true;
        }
        case TRANSACTION_say: {//响应命令
            data.enforceInterface(DESCRIPTOR);
            String str = data.readString();
            sayHello(str);
            reply.writeNoException();
            return true;
        }}
        return super.onTransact(code, data, reply, flags);
    }

    @Override
    public void callHi(String str) { //实现接口
        System.out.println("MyService:: Hello, " + str);
    }
}

1.3 作为Server端需调用ServiceManager.addService方法进行注册

public class ServerDemo {
    public static void main(String[] args) {
        Looper.prepareMainLooper();
        android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
        ServiceManager.addService("MyService", new MyService()); //注册service
        Looper.loop();
    }
}

2 Client端

2.1 实现IMyService接口的代理

public class MyServiceProxy implements IMyService {
    private android.os.IBinder mRemote;

    public MyServiceProxy(android.os.IBinder remote) {
        mRemote = remote;
    }

    @Override
    public IBinder asBinder() {
        return mRemote;
    }

    public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
    }

    @Override
    public void callHi(String str) throws RemoteException {
        android.os.Parcel data = android.os.Parcel.obtain();
        android.os.Parcel reply = android.os.Parcel.obtain();
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            data.writeString(str);
            mRemote.transact(TRANSACTION_say, _data, _reply, 0);//通过获取的mRemote(即service在本地的代理)发送命令
            reply.readException();
        } finally {
            reply.recycle();
            data.recycle();
        }
    }
}

2.2 与Server端通信

public class ClientDemo {
    public static void main(String[] args) throws RemoteException { 
        //调用getService方法,会根据传入的名称参数打包成Parcel对象调用
        //transact方法写入给binder驱动,Binder驱动将对应的mRemote对象返回
        IBinder binder = ServiceManager.getService("MyService"); 
        IMyService myService = new MyServiceProxy(binder); 
        myService.callHi("binder"); 
    }
}

AIDL

AIDL即Android Interface Definition Language(安卓接口定义语言),当我们创建了这个接口后,系统会自动生成其对应的Binder类,它继承了IInterface, 内部有一个静态抽象类Stub和Stub内部的Proxy类。其中Stub继承了Binder类,所以AIDL中的Stub即为一个Binder对象。 在服务端实现该接口后,支持在客户端远程调用(RPC)。
综上AIDL定义的接口,它除了是一个接口以外,它还是一个Binder对象,支持在接口和Binder之间相互转换(asBinder(), asInterface())。

bindservice绑定流程时序图

pic6.jpeg

注意:ContextImpl.bindServiceCommon中调用ActivityManagerNative.getDefault().bindService这个方法,是涉及到(Client-ServiceManager-Server)通信,具体可以看其Binder实例中的时序图。

流程如下:
  • 第一步定义AIDL接口
  • 第二步实现AIDL文件生成的JAVA接口Stub(即stubSerVice类)
  • 第三步定义一个自己的Service,在实现自己的Service时,为了让Client端可以通过bindService来和我们的Service进行交互,我们都要实现Service中的onBind()方法,并且返回一个继承了Binder的内部类(即stubSerVice类)
  • 第四步Client端调用bindService方法进行服务绑定(流程请看如上时序图),服务绑定成功后,serviceConnection.onServiceConnected接口回调,获取到BinderProxy对象(即Server端Binder引用),再利用asInterface方法将BinderProxy对象转化为接口对象,从而实现与Server端跨进程通信

AIDL实例

1 定义AIDL接口

package 
interface Publicmake {
    void dealwith();
}

2 Server端

public class AidlService extends Service {
    private static final String TAG = AidlService.class.getSimpleName();
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new SstubSerVice();
    }

    class SstubSerVice extends Publicmake.Stub {
        @Override
        public void dealwith() {
            AidlService.this.callHi();
        }
    }

    public void callHi() {
        Log.i(TAG, "MyService:: Hello");
    }
}

4 注册Service

<service android:name=".aidldemo.AidlService"
            android:process=":remote">
            <intent-filter>
                <action android:name="AidlService"/>
            </intent-filter>
</service>

5 新建AidlActivity绑定Service(Client端)

public class AidlActivity extends AppCompatActivity {
    public Publicmake psb;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button bt = findViewById(R.id.button);
        Intent it = new Intent(this,AidlService.class);

        bindService(it, new serviceConnection(), BIND_AUTO_CREATE);

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clickup(v);
            }
        });
    }

    public void clickup(View v) {
        try {
            psb.dealwith();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    class serviceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //注意一定要利用asInterface转为接口对象
            psb = Publicmake.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    }
}
public interface Publicmake extends android.os.IInterface {
    public static abstract class Stub extends android.os.Binder implements  {
        private static final java.lang.String DESCRIPTOR = 
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        public static  asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof  {
                //同一进程内直接返回
                return  iin);
            }
            //不在同一进程使用代理获取远程服务
            return new 
        }

        @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_dealwith: {
                    data.enforceInterface(DESCRIPTOR);
                    this.dealwith();
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
        /**
          * 代理类,调用transact方法。
          */
        private static class Proxy implements  {
            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 void dealwith() throws android.os.RemoteException {
                // 输入参数
                android.os.Parcel _data = android.os.Parcel.obtain();
                // 输出参数
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_dealwith, _data, _reply, 0);
                    //调用mRemote.transact方法后,会挂起当前线程,等待远程方法执行完后才会继续当前线程
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
           }
        }

    static final int TRANSACTION_dealwith = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    public void dealwith() throws android.os.RemoteException;
}

Binder和AIDL实例异同

综上,你会发现其实Binder实例和AIDL实例有很多相似之处。
Binder实例中Server端会先通过Binder驱动向ServiceManager进行注册,Client端则通过Binder驱动与AMS通信获得远程引用对象(proxy),然后通过这个远程引用对象与Server端通信。
而AIDL其实是一个匿名的Binder传输过程,并没有在ServiceManager中进行注册,匿名binder必须是建立在一个实名binder之上的,也就是指这个实名binder必须在ServiceManager中注册过的,而AIDL实例中通过调用bindService从而与AMS通信(AMS服务在ServiceManager中注册),调用ActivityManagerNative.publishService方法将传入的IBinder对象打包成parcel调用transact方法传入binder驱动层,再通过ActivityManagerNative.onTransact方法获取binder驱动返回的Server端binder引用(即BinderProxy),再调用其子类即ActivityManagerService.publishService(ActivityManagerService继承于ActivityManagerNative)方法,回传给客户端,从而让Client端获取到远程binder对象引用从而与Server端远程通信。

主要源码方法解析

ActivityManagerNative.java

时序图1.2.9在handleBindService 方法中 调用ActivityManagerNative.getService().publishService进入

public void publishService(IBinder token,
            Intent intent, IBinder service) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(token);
        intent.writeToParcel(data, 0);
        data.writeStrongBinder(service);
        mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);
        //调用mRemote.transact方法后,会挂起当前线程,等待远程方法执行完后才会继续当前线程
        //transact方法 客户端调用,用于发送调用请求
        reply.readException();
        data.recycle();
        reply.recycle();
}
  //onTransact方法 服务端响应,用于接收调用请求
  @Override
  public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
            ···
            case PUBLISH_SERVICE_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder token = data.readStrongBinder();
            Intent intent = Intent.CREATOR.createFromParcel(data);
            IBinder service = data.readStrongBinder();
            //此处的IBinder对象是Binder驱动层转换成BinderProxy返回回来的
            //因为ActivityManagerService继承于ActivityManagerNative,且ActivityManagerService重写了publishService方法,
            //所以如下调用的是ActivityManagerService.publishService
            publishService(token, intent, service);
            reply.writeNoException();
            return true;
            ···
        }
}
ActivityManagerService.java
public void publishService(IBinder token, Intent intent, IBinder service) {
        synchronized(this) {
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
}
ActiveServices.java
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
            if (r != null) {
                Intent.FilterComparison filter
                        = new Intent.FilterComparison(intent);
                IntentBindRecord b = r.bindings.get(filter);
                if (b != null && !b.received) {
                    b.binder = service;
                    b.requested = true;
                    b.received = true;
                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                        for (int i=0; i<clist.size(); i++) {
                            ConnectionRecord c = clist.get(i);
                            try {
                               //binder在onTransact回调中已转化成BinderProxy,通过c.conn.connected回调最终进入ServiceConnection的onServiceConnected接口方法中传回给Client端,
                               //从而让Client端获取到Server端的Binder引用,从而实现远程通信。
                               //在一开始ContextImpl.java的bindServiceCommon函数中做了一些准备工作,就是创建这个回调类。
                               c.conn.connected(r.name, service, false);
                            } catch (Exception e) {
                            }
                        }
                    }
                }
                serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
}
onServiceConnected接口方法

bindService是异步调用和Service进行绑定, 如果绑定成功, 则会调用ServiceConnection的onServiceConnected

pic5.jpeg
通过断点,你会发现onServiceConnected方法回调回来的service参数是已经转化成BinderProxy(即Server端Binder对象引用)了,而非通过onBind获取到的IBinder对象,这是为什么呢,通过上面时序图,其实这个对象转换是发生在binder驱动层,可以看时序图1.2.10那一步,开始将未转化的IBinder对象打包成parcel形式通过transact()方法传给binder驱动时序图1.2.11),然后通过onTransact获取Binder驱动返回的BinderProxy(即Server端Binder对象引用),再通过时序图1.2.15回传给客户端。

总结

看到这里,其实你会发现,Binder没有想象中难理解,无论是Client-ServiceManager-Server还是AIDL进行跨进程通信都离不开Binder,Binder是一个实现IBinder的类,提供了两个与Binder驱动通信的重要接口方法(Transact()onTransact()),你可以通过它实现自定义的RPC协议,通过阅读引申一些思考,为什么要使用binder来实现进程间的通信呢?

Top