Binder通信机制

1.什么是Binder

Binder 是一种进程间通信机制,基于开源的 OpenBinder 实现;OpenBinder 起初由 Be Inc. 开发,后由 Plam Inc. 接手。从字面上来解释 Binder 有胶水、粘合剂的意思,顾名思义就是粘和不同的进程,使之实现通信。

2.什么时候需要用到进程间通信?

Android开发者们都知道,Android 应用程序是由 Activity、Service、Broadcast Receiver 和 Content Provide 四大组件中的一个或者多个组成的。然而有时这些组件运行在同一进程,有时运行在不同的进程。这些进程间的通信就依赖于 Binder IPC 机制。Android 系统对应用层提供的各种服务如:ActivityManagerService、PackageManagerService 等都是基于 Binder IPC 机制来实现的。还有就是支付宝纳入海量应用、大型登入架构的实现等等。由此可见Binder 机制在 Android 中的位置非常重要。

3.进程间通信为什么要用到Binder机制?

Android 系统是基于 Linux 内核的,Linux 已经提供了共享内存和 Socket 等 IPC 机制。那为什么 Android 还要提供 Binder 来实现 IPC 呢?
Binder通信与其他通信的区别如下图:

Binder与传统IPC通信对比

4. 进程间通信原理

在Android系统中每一个进程的用户空间(User Space)都是隔离的,进程1没有办法直接访问进程2的数据,这也就是所谓的进程隔离,但是内核空间(Kernal Space)是共享的。当进程1发起系统调用时(Binder实现IPC通信),进行一个复制数据到内核空间的缓存区,再通过mmap的映射关系,就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。(整个过程就是一个数据copy和一个内存数据映射过程)

Binder IPC原理

4.Biner通信机制的简单实现(AIDL)

通常我们在开发时,实现进程间通信的最多可能就是AIDL了,当我在AS中定义好我们的.AIDL文件,AS就会给我们直接生成对应的实现IPC通信的.java文件,因此帮助我们进一步了解IPC通信机制。

IBinder : IBinder 是一个接口,代表了一种跨进程通信的能力。只要实现了这个借口,这个对象就能跨进程传输。
IInterface : IInterface 代表的就是 Server 进程对象具备什么样的能力(能提供哪些方法,其实对应的就是 AIDL 文件中定义的接口)
Binder : Java 层的 Binder 类,代表的其实就是 Binder 本地对象。BinderProxy 类是 Binder 类的一个内部类,它代表远程进程的 Binder 对象的本地代理;这两个类都继承自 IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder 驱动会自动完成这两个对象的转换。
Stub : AIDL 的时候,编译工具会给我们生成一个名为 Stub 的静态内部类;这个类继承了 Binder, 说明它是一个 Binder 本地对象,它实现了 IInterface 接口,表明它具有 Server 承诺给 Client 的能力;Stub 是一个抽象类,具体的 IInterface 的相关实现需要开发者自己实现。

AIDL实现进程通信时序图

4.1.AS自动生成的代码

package com.drsports;
/**
 * @author Vson
 * 项目描述:这个是客户端AIDL自动生成的,里面有注释过程
 */
public interface IMyAidlInterface extends android.os.IInterface {

    ...

    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements IMyAidlInterface {
        //描述符
        private static final java.lang.String DESCRIPTOR = "IMyAidlInterface";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            //挂载接口
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an IMyAidlInterface interface,
         * generating a proxy if needed.
         * *将一个IBinder对象转换成com.drsports.server.IMyAidlInterface接口,
         * *如果需要,生成代理。(动态代理)
         */
        public static IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof IMyAidlInterface))) {
                //查看是否本地接口,如果是本地接口,直接返回
                return ((IMyAidlInterface) iin);
            }
            //如果不是本地接口,远程获取一个接口(句柄)
            return new IMyAidlInterface.Stub.Proxy(obj);
        }

  ...

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            //这个是远程的Server,因为客户端和服务端的代码是一个的,为了节省空间就是贴出来
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                ...
                case TRANSACTION_addPerson: {
                   ...
                    //调用继承类的addPerson(_arg0)方法,也就是
                    //AidlService中的new IMyAidlInterface.Stub()
                    this.addPerson(_arg0);
                    reply.writeNoException();
                    return true;
                }
              ....
            }
        }

        private static class Proxy implements IMyAidlInterface {

            //内部对象
            public static IMyAidlInterface sDefaultImpl;

            //发送数据(远程IBinder)
            private android.os.IBinder mRemote;

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

            @Override
            public android.os.IBinder asBinder() {
                //获取远程IBinder
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                //获取描述符
                return DESCRIPTOR;
            }

            @Override
            public void addPerson(com.drsports.server.Person person) throws android.os.RemoteException {
                //客户端发送数据
                android.os.Parcel _data = android.os.Parcel.obtain();
                //服务端返回数据
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    //C层校验数据
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((person != null)) {
                        _data.writeInt(1);
                        person.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    //调用服务端方法,将客服端挂起,直到服务端返回数据
                    //flags 是0表示客户端和服务端相互通信;是1表示客户端只能发送,服务端不能返回数据
                    //Stub.TRANSACTION_addPerson方法ID
                    boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
                    if (!_status && getDefaultImpl() != null) {
                        getDefaultImpl().addPerson(person);
                        return;
                    }
                    //读取异常
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
         .....
        }

        static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
...

4.2.客户调用代码


    /**
     * onAIDLServer点击事件
     *
     * @param view
     */
    public void onAIDLServer(View view) {
        try {
          //使用服务句柄调用服务方法,完成IPC通行
            myAidlInterface.addPerson(new Person("vson", 2));
            List<Person> mList = myAidlInterface.getPersonList();
            Log.d("sss", mList.toString());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private IMyAidlInterface myAidlInterface;

    private ServiceConnection connection2 = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //获取服务句柄
            myAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            myAidlInterface = null;
        }
    };

    //进入页面时调用完成bind代码
    public void myBindService() {
        Intent intent = new Intent();
        //服务端通过反射创建的Service
        remoteServer = new ComponentName("com.drsports.server", "com.drsports.server.AidlService");
        intent.setComponent(remoteServer);
        bindService(intent, connection2, Service.BIND_AUTO_CREATE);
    }

4.3.服务端代码

package com.drsports.server;
/**
 * @author vson
 */
public class AidlService extends Service {
    private ArrayList<Person> mList;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        mList = new ArrayList<>();
        return binder;
    }

    private IBinder binder = new IMyAidlInterface.Stub() {
        @Override
        public void addPerson(Person person) throws RemoteException {
            Log.d("TAG", person.toString());
            mList.add(person);
        }

        @Override
        public List<Person> getPersonList() throws RemoteException {
            return mList;
        }
    };
}

当客户端调用bindService时,系统层代码会调用connection2中的onServiceConnected实现一次服务绑定,而在onServiceConnected中,通过IMyAidlInterface.Stub.asInterface(service)获取服务端的server句柄,这个过程是动态代理的过程。接下来当客户端调用 myAidlInterface.addPerson(new Person("vson", 2)),是调用实现IMyAidlInterface接口的Proxy中的addPerson方法,其中 mRemote.transact()方法就是内核层使用Binder调用远程Server的onTransact()方法。在Server端中的AIDL中有一个this.addPerson()方法其实是调用Stub的实现类的addPerson方法,也就是上面服务端代码new IMyAidlInterface.Stub() 的addPerson()方法。

5.Biner通信机制的源码分析(API23中bindService实现)

当客户端调用bindServer方法时,进入了Context的装饰类ContextWrapper中,但是真正实现bindServer方法的是Context的实现类ContextImpl:

public class ContextWrapper extends Context {
...
  @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }
...
}
class ContextImpl extends Context {
...
 @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, Process.myUserHandle());
    }

 private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
        IServiceConnection sd;
...
        if (mPackageInfo != null) {
             //ServiceConnection的接口回调的封装
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
        } 
...
            // ActivityManagerNative.getDefault() 返回就相当于AIDL的proxy
            //而这个Proxy就是ActivityManagerService类
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
...
}
//ActivityManagerNative==>Stub
public abstract class ActivityManagerNative extends Binder implements IActivityManager{
   /**
     * Cast a Binder object into an activity manager interface, generating
     * a proxy if needed.
     */
    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }

        return new ActivityManagerProxy(obj);
    }

    /**
     * Retrieve the system's default/global activity manager.
     */
    static public IActivityManager getDefault() {
        //返回Binder 的proxy
        return gDefault.get();
    }

  @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
       switch (code) {
         case BIND_SERVICE_TRANSACTION: {
        ...
            IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
            //调用真正的服务(启动服务)ActivityManagerService
            int res = bindService(app, token, service, resolvedType, conn, fl,
                    callingPackage, userId);
          ...
        }

}

  private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>(){
        protected IActivityManager create() {
            //IBiner就是AMS服务,这个是系统启动时添加进去的
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            //获取远程服务句柄
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };
}

//ActivityManagerProxy ===>proxy
class ActivityManagerProxy implements IActivityManager{
...
 public ActivityManagerProxy(IBinder remote)
    {
        mRemote = remote;
    }
   public int bindService(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType, IServiceConnection connection,
            int flags,  String callingPackage, int userId) throws RemoteException {
     ....
        //进行远程调用服务方法
        mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
     ...
    }
...
}
public interface IActivityManager extends IInterface {}

有上面的代码可以看出:bindServer过程是调用ContextImpl的bindSever方法进而调用了bindServiceCommon方法,bindServiceCommon方法中调用了ActivityManagerNative.getDefault().bindService方法,可以看出ActivityManagerNative.getDefault()返回的IActivityManager就相当与AIDL中实现 IMyAidlInterface的Proxy,而这个Proxy就是ActivityManagerService类;而ActivityManagerNative.getDefault().bindService()就是相当于Proxy.bindService();IActivityManager继承IInterface接口,所以IActivityManager就相当于AIDL接口IMyAidlInterface ;可以看出ActivityManagerNative和ActivityManagerProxy就是相当于Stub和Proxy的关系。

整理如下图:

image.png

接下来我在看ActivityManagerService这个类:

public final class ActivityManagerService extends ActivityManagerNative{
...
  public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String callingPackage,
            int userId) throws TransactionTooLargeException {
        enforceNotIsolatedCaller("bindService");
    ....
        synchronized(this) {
            //同步处理(枷锁)
            //mServices是ActiveServices
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, callingPackage, userId);
        }
    }
...
}
public final class ActiveServices {
    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags,
            String callingPackage, int userId) throws TransactionTooLargeException {
    ...
            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                //>1.进程B,整个进程都没有启动
                //>2.进程B启动了,但是里面的Service没有创建出来
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
                    return 0;
                }
            }
       ...
           if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    //重新bind服务
                    //1.进程B启动了,里面的Service也创建了,但是Service没有绑定过,回调onBind()
                    //2.进程B启动了,里面的Service也创建了,但是Service已经绑定过,回调onRebind()
                    requestServiceBindingLocked(s, b.intent, callerFg, true);
            } else if (!b.intent.requested) {
               //没有bind服务
               //1.进程B启动了,里面的Service也创建了,但是Service没有绑定过,回调onBind()
               //2.进程B启动了,里面的Service也创建了,但是Service已经绑定过,回调onRebind()
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }
        }
    private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting) throws TransactionTooLargeException {
         ...
        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        ProcessRecord app;

        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
  
            if (app != null && app.thread != null) {
                //>1.进程B,整个进程都没有启动
                //>2.进程B启动了,但是里面的Service没有创建出来
                //B进程已成启动了
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } 
            }
        }
   ...
        return null;
    }
}

  private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
     ...
            //ProcessRecord是一个进程记录,ProcessRecord.thread指向的是ActivityThread.ApplicationThread
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
    ...
        } 
public final class ActivityThread {
...
        public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;
            //这里是Handler消息
            sendMessage(H.CREATE_SERVICE, s);
        }

        public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;
          //这里是Handler消息
           sendMessage(H.BIND_SERVICE, s);
        }

   public void handleMessage(Message msg) {
...
                  case CREATE_SERVICE:
                    handleCreateService((CreateServiceData)msg.obj);
                    break;
..
}


    //真正创建服务的方法
    private void handleCreateService(CreateServiceData data){
            //使用类加载器加载Service
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
       ....
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //服务挂载参数
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            //服务的生命周期onCreate方法回调
            service.onCreate();
            //存储服务,如果再次创建就从这个获取
            mServices.put(data.token, service);
           ...
    }


...
}

A进程访问B进程时几种状态
1.bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null)

1.进程B,整个进程都没有启动
2.进程B启动了,但是里面的Service没有创建出来

2.requestServiceBindingLocked(s, b.intent, callerFg, false);

1.进程B启动了,里面的Service也创建了,但是Service没有绑定过,回调onBind()
2.进程B启动了,里面的Service也创建了,但是Service已经绑定过,回调onRebind()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容