从AIDL分析Framework层中的跨进程通信--Binder机制

AIDL简介

AIDL是Android Interface Definition Language的缩写,即Android接口定义语言。它是Android的进程间通信比较常用的一种方式,其原理是通过Binder机制实现进程间通信的

从一个简单的AIDL实例开始分析

由于Binder机制的进程间通信是基于C/S架构的,这里先看下客户端需要创建的文件以及代码---

  • 客户端(Client)应用创建:在客户端定义一个Book实体,如果在Binder通信中传递非基本类型,那么除了需要创建一个实现Parcelable接口的实体类外,还需要再建个和实体类命名一样的实体AIDL文件,如下:
// Book.aidl
package com.example.client;
parcelable Book;

在同一个包下定义一个AIDL接口文件,其中有两个方法:

// IBookManager.aidl
package com.example.client;
//注意即使在同一个包下也需要导入
import com.example.client.Book;

interface IBookManager {
    //添加书本
    void addBook(in Book person);
    //返回图书列表
    List getBookList();
}

绑定远程服务端代码(获取远程Binder引用):

    private void bindService() {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.client", "com.xx.leo_service.LeoAidlService"));
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iBookManager = IBookManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iBookManager = null;
        }
    };
  • 服务端(Server)应用创建,注意需要把Book实体类和AIDL接口文件完全拷贝过来,包名也需要一致,除此之外,再新建一个服务,其内部创建一个Binder,继承IBookManager.Stub,实现远程方法:
    void addBook(in Book book);
    List getBookList();
    并通过onBind()返回给客户端
    如下:
public class BookManagerService extends Service {
    private ArrayList books;
    private String TAG = "BookManagerService";
    @Override
    public IBinder onBind(Intent intent) {
        books = new ArrayList<>();
        Log.e(TAG, "success onBind:"+getApplicationInfo().processName);
        return iBinder;
    }

    private IBinder iBinder = new IBookManager.Stub() {
        @Override
        public void addBook(Book book) throws RemoteException {
            Log.e(TAG, "addBook:"+ Thread.currentThread().getName());
            books.add(book);
        }

        @Override
        public List getBookList() throws RemoteException {
            Log.e(TAG, "getBookList:"+ Thread.currentThread().getName());
            return books;
        }
    };
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate: success");
    }
}

接下来将两个应用跑起来就可以在Client和Server间进行进程间通信了,在客户端调用以下方法即会调用到服务端的具体实现方法:
iBookManager.addBook(new Book("历史", 1));
List books = iBookManager.getBookList();

简单分析下AIDL为我们生成的文件

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.example.client;

public interface IBookManager extends android.os.IInterface {
    public static abstract class Stub extends android.os.Binder implements com.example.client.IBookManager {
        private static final java.lang.String DESCRIPTOR = "com.example.client.IBookManager";
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
        public static com.example.client.IBookManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.client.IBookManager))) {
                return ((com.example.client.IBookManager) iin);
            }
            return new com.example.client.IBookManager.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_addBook: {
                    data.enforceInterface(DESCRIPTOR);
                    com.example.client.Book _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.example.client.Book.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getBookList: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.example.client.IBookManager {
            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 addBook(com.example.client.Book book) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((book != null)) {
                        _data.writeInt(1);
                        book.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public java.util.List getBookList() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.example.client.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public void addBook(com.example.client.Book book) throws android.os.RemoteException;

    public java.util.List getBookList() throws android.os.RemoteException;
}

这里主要生成了两个类,一个Stub和一个Proxy,都实现了IBookManager接口,很显然这是代理模式

  • 从客户的绑定服务开始,可以看到在ServiceConnection的onServiceConnected方法中返回了一个IBinder参数service,通过传入方法IBookManager.Stub.asInterface(service)中获取一个客户端代理类,
  • 在Stub的asInterface()中,queryLocalInterface作用是判断是否是在同一个进程中,如果是直接返回当前对象,无需跨进程,如果不是,则将远程返回的BinderProxy(也实现了IBinder)传入Proxy,创建一个本地客户端代理类
  • 当调用代理类的iBookManager.addBook(new Book("历史", 1));时,将对象序列化入参调用mRemote.transact()(这个函数三个重要参数:int code、Parcel data、Parcel reply,分别对应了被调函数编号、参数包、响应包),这里就通过Binder驱动,调到了远程服务端的Stub(继承Binder实现IBookManger)的onTransact()方法,根据入参定位具体方法,进而调用到服务端的Binder中addBook()方法。getBookList()方法调用方式一样

整体流程很简单,通过绑定远程服务-->获取远程BinderProxy代理引用-->作为入参创建本地客户端Proxy-->调用本地Proxy方法--->mRemote.transact()-->通过Binder底层驱动处理-->调用到远程Stub的onTransact方法-->最终调用到远程服务的目标实现方法。虽然服务端和客户端有着一模一样的代码,可以看出Stub主要给服务端使用,而Proxy主要是给客户端使用

类关系图如下:
从AIDL分析Framework层中的跨进程通信--Binder机制_第1张图片
AIDL类关系图.png

bindService()如何获取到远程服务Binder引用

进程间通信客户端如何从服务端获取Binder引用是关键,拿到了引用才能调用其远程方法,接下来简单分析下bindService()源码(Android-23)。

@Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }

  • mBase是上下文context,而调用context的bindService()实际上实际上是调用它的实现类ContextImpl的bindService()方法,所以最终会调用到ContextImpl的bindServiceCommon()方法:
    从AIDL分析Framework层中的跨进程通信--Binder机制_第2张图片
    bindServiceCommon.png

1.构建IServiceConnection后面用于给客户端回传服务端Binder引用。
2.ActivityManagerNative.getDefault()获取的其实是ActivityManagerService本地客户端(即当前用户进程)的代理类,调用ActivityManagerService代理类的bindService()方法,最终通过Binder驱动会跨进程调用Systemserver进程中ActivityManagerServicebindService()方法。

  • 看下ActivityManagerNative.getDefault()
从AIDL分析Framework层中的跨进程通信--Binder机制_第3张图片
ActivityManagerNative.getDefault().png
  1. 由于AMS所在进程是Systemserver进程,因此应用进程调用系统服务ActivityManagerService的方法也需要跨进程,那就必须拿到(即Systemserver进程)ActivityManagerService服务的Binder引用,才能跨进程通信,所以上面代码1处即通过ServiceManager获取ActivityManagerService在远程服务端的Binder引用,然后在2处传入本地客户端代理,最终返回客户端代理类ActivityManagerProxy,当调用代理类的bindService()时即会跨进程调用服务端ActivityManagerService方法绑定服务。可以看出这里是一次跨进程调用,应用进程与Systemserver进程的通信,通过系统服务ActivityManagerService去绑定一个服务
  2. 而1处是如何拿到AMS远程服务的Binder引用的呢?
  • 接着看下ServiceManager.getService("activity")
 public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }
        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

根据系统服务名,先从Cache中查找是否已有,没有的话则通过getIServiceManager().getService(name)获取,
getIServiceManager()中通过BinderInternal.getContextObject()获取远程服务端ServiceManager服务的Binder引用,并创建本地代理类,通过代理类的getService()方法调用远程服务的getService()方法获取ActivityManagerService系统服务。
可以看到这里又是一次进程间通信,通过ServiceManager获取系统服务ActivityManagerService的Binder引用还需要与ServiceManager所在进程跨进程通信,那么与ServiceManager服务通信的Binder引用又从哪里来呢???
这里简单介绍下ServiceManager服务,进程间通信的客户端想要获取服务端的 Bind引用都需要通过它来获取,而所有服务端都需要向ServiceManager注册自己的Binder以供客户端使用,由于其他进程与ServiceManager服务进程通信也必须获取它的Binder引用,所以ServiceManager 提供的 Binder 比较特殊,它没有名字也不需要注册。当一个进程使用BINDERSETCONTEXT_MGR 命令将自己注册成 ServiceManager时 Binder 驱动会自动为它创建 Binder 实体,其次这个 Binder 实体的引用在所有 Client 中都固定为 0 而无需通过其它手段获得。也就是说,一个 Server 想要向ServiceManager注册自己的 Binder 就必须通过这个 0 号引用Binder和 ServiceManager服务进行通信。

  • 回到ActivityManagerNative.getDefault().bindService(),经过上面的分析可以知道其实这里调用是用户应用进程的ActivityManagerService代理类(其实现IActivityManager接口)的bindService(),即是:ActivityManagerProxy.bindService()
public int bindService(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType, IServiceConnection connection,
            int flags,  String callingPackage, int userId) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeStrongBinder(token);
        service.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(connection.asBinder());
        data.writeInt(flags);
        data.writeString(callingPackage);
        data.writeInt(userId);
        mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        data.recycle();
        reply.recycle();
        return res;
    }

其实就是AIDL中代理类的方法,mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);最终会通过这个方法调用到远程服务ActivityManagerServiceonTransact()方法,ActivityManagerService继承自ActivityManagerNative,并实现了IActivityManager中相应的方法。
所以先看下ActivityManagerNative中的transact()方法中对应的BIND_SERVICE_TRANSACTION位置:

从AIDL分析Framework层中的跨进程通信--Binder机制_第4张图片
ActivityManagerNative.png

上述代码1处即调用 ActivityManagerServicebindService()方法,至此,从用户进程切换到了AMS所在进程进行绑定服务操作。
AMS服务中的相关AIDL类关系:
从AIDL分析Framework层中的跨进程通信--Binder机制_第5张图片
image.png

进入到ActivityManagerService中,看下bindService具体实现流程

由于细节太多,这里仅仅列出主线,可自行根据主线方法名跟入源码仔细研究

  • ActivityManagerService#bindService会再调用ActiveServices#bindServiceLocked,
    ActiveServices#bindServiceLocked中如果目标进程会去创建目标进程,如果服务未启动,会启动服务
  • ActiveServices中启动服务端调用流程:bindServiceLocked()-->bringUpServiceLocked()-->realStartServiceLocked()-->app.thread.scheduleCreateService()在这里app.thread其实又是一个跨进程通信,从AMS进程进入到目标用户进程,其AIDL接口是IApplicationThread,Stub是ApplicationThreadNative,Proxy是ApplicationThreadProxy,远程服务端实现是ActivityThread内部类ApplicationThread,它继承自ApplicationThreadNative(这里用户进程变成了服务端,AMS服务所在进程变成了客户端),所以先看下客户端代理类的ApplicationThreadProxy#scheduleCreateService方法:
    从AIDL分析Framework层中的跨进程通信--Binder机制_第6张图片
    image.png

可以看到调用了s.onBind,就是我们在服务端服务中定义的onBind方法
获取我们的Binder对象,接着又调用ActivityManagerNative.getDefault()publishService(),这里非常眼熟,与前面的bindService就很类似,又是跨进程通信,拿到AMS的客户端代理,执行它的publishService(),最终又会交给AMS去执行,不再重复看

  • 直接到ActivityManagerService中找publishService()方法,发现它又会调用ActiveServices#publishServiceLocked()
 void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                    + " " + intent + ": " + service);
            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 clist = r.connections.valueAt(conni);
                        for (int i=0; i

可以看到核心部分c.conn.connected(r.name, service),(其实这里涉及到一开始bindServiceCommon中构建的IServiceConnection,在LoadedApk中的ServiceDispatcher.InnerConnection中,其实本质又是一次跨进程通信,感兴趣的可以看下源码)这里就会再调用到我们在客户端绑定服务时传入的ServiceConnection的onServiceConnected方法,最终客户端拿到服务端IBinder的引用!!!
至此,终于结束了,可以发现为了实现自定义的一次跨进程通信,其内部经历了无数次跨进程。。。

你可能感兴趣的:(从AIDL分析Framework层中的跨进程通信--Binder机制)