美文网首页
AMS系列②—Binder通信的双向代理绑定

AMS系列②—Binder通信的双向代理绑定

作者: leap_ | 来源:发表于2020-10-22 22:54 被阅读0次

Binder进程见通信是通过远程代理来实现的,SystemServer进程APP用户进程使用Binder进行通信,必须建立双向的代理绑定,即:一个进程即使客户端也是服务端,这样才能实现双工通道


只有持有对方进程的代理对象,才能通过代理对象控制真实对象做事情,代理对象必须是一个Binder接口,因为它要依赖Binder帮我们做底层的进程间的数据传递,下面从源码分析下,这个双向代理的建立过程:

App进程创建AMS代理 (APP作为客户端)

上一篇文章介绍了ams的创建的具体细节,在 startBootstrapServices ()开启引导服务这个方法的分析4中:调用了AMS的setSystemProcess()这个方法,在这个方法中,将我们的SystemServer进程(从APP进程的角度:远程进程,服务端进程)的各种服务(包括AMS本身)都添加到ServiceManager这个类中:

    public void setSystemProcess() {
        try {
            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
            ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
            ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_HIGH);
            ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
            ServiceManager.addService("dbinfo", new DbBinder(this));
            if (MONITOR_CPU_USAGE) {
                ServiceManager.addService("cpuinfo", new CpuBinder(this),
                        /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            }
            ServiceManager.addService("permission", new PermissionController(this));
            ServiceManager.addService("processinfo", new ProcessInfoService(this));
    }

不知道大家在学习Bidner的时候也没有关注到ServiceManager这个东西,简单在过一下Binder吧:

Binder通信模型中有四个东西:
Binder驱动:谷歌在linux层面嵌入的一个插件/驱动,实现进程间通信的底层细节,比如调用mmap实现内存映射,调用copy_from_user实现内存拷贝;
ServiceManager:本质是一个进程,由Binder驱动控制,它的作用是维护了一张表service_manager表,这张表里面存放了所有的服务端进程的记录(具体记录的是什么我忘了,类似具柄引用什么的)
客户端进程:进程通信的C端进程
服务端进程:进程通信的S端进程
首先服务端进程向Binder驱动申请成为服务端,那么服务端进程就会存放到ServiceManager这张表中,当客户端需要通信时,可以向Binder驱动申请查询对应的服务端,如果查询到,就会返回一个服务端的代理给客户端,那么客户端就可以通过这个代理去让服务端的真实对象做事情;

在这里的Servicemanager添加的各种服务,就会被添加到ServiceManager进程的service_manager表中,这样就完成了服务端(SystemServer进程的服务)的注册;

App创建AMS代理:

在AMS的setSystemProcess中想ServiceManager表中注册了之后,就可以通过ServiceManager.getService()向Binder驱动申请获取这个服务的IBinder对象:

    IBinder b = ServiceManager.getService("activity");

在APP进程,AMS的代理是一个叫做iActivityManager的对象,这个玩意儿在7.0和8.0还不一样,我们先看7.0的版本:

7.0 Nougat

在7.0中又一个ActivityManagerNative类,用户进程在startActivity的时候(具体是在Instrumentation.execStartActivity的时候,不清楚的可以看前面的文章),会调用AMN的getDefault()获取AMS的代理:ActivityManagerProxy对象;(这个ActivityManagerProxy是IActivityManager的子类)

Instrumentation.execStartActivity():
int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
ActivityManagerNative.getDefault():
    static public IActivityManager getDefault() {
        return gDefault.get();
    }

   private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            IActivityManager am = asInterface(b);
            return am;
        }
    };

    static public IActivityManager asInterface(IBinder obj) {
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        return new ActivityManagerProxy(obj);
    }

这里的逻辑也非常简单,首先通过ServiceManager.getService()向底层的Binder注册表service_manager查询AMS的IBinder对象,然后将AMS的iBinder对象封装到ActivityManagerProxy中:

   class ActivityManagerProxy implements IActivityManager{
        public ActivityManagerProxy(IBinder remote)
        {
        mRemote = remote;
        }
  }
  • AMN是服务端进程(SystemServer)的,它实现了Binder接口,iActivityManager接口,AMS是其的子类;AMN作为服务端被代理的对象,所有的实际功能都是尤其子类AMS实现的;
  • AMP是客户端进程的,拥有一个Binder成员变量(AMS的iBinder对象,从ServiceManager表中查询到的代理对象),AMP作为客户端的代理对象,它通过mRemote调用的方法都会代理到服务端的AMN中,而AMS继承了AMN,所以最终都是由AMS进程处理的;
8.0 Oreo
Instrumentation.execStartActivity():
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target, requestCode, 0, null, options);
ActivityManager.getService():
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

这里的处理方式和7.0如出一辙,首先通过ServiceManager获取ams的iBinder对象,然后通过这个对象构造出一个iActivityManager对象;

  • IActivityManager是一个aidl接口,它编译后会生成一个对应的java类,这个类有一个内部类Stub,要实现跨进程通信只要服务端继承iActivityManager.Stub就好;

  • 服务端的AMS继承iActivityManager.Stub后,就可以和客户端的ActivityManager实现跨进程通信

public class ActivityManagerService extends IActivityManager.Stub

SystemServer 进程创建App进程的代理 (SystemServer进程作为客户端)

回忆一下用户进程的入口ActivityThread的main中的初始化做了哪些事情:

    public static void main(String[] args) {
        Looper.prepareMainLooper();
        thread.attach(false, startSeq);
        Looper.loop();
    }

重点关注ActivityThread的attach() :

ActivityThread.attach():
    private void attach(boolean system, long startSeq) {

           final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread, startSeq);

    }

这里调用了AMS在用户进程的代理iActivityManager的attachApplication(),会执行AMS的attachApplication():注意这里传入的参数,是当前ActivityThread的ApplicationThread对象,ApplicationThread是ActivityThread的内部类,继承了IApplicationThread.Stub

public final class ActivityThread extends ClientTransactionHandler {
    final ApplicationThread mAppThread = new ApplicationThread();

    private class ApplicationThread extends IApplicationThread.Stub {  }
}

我们在看看传给AMS后,AMS做了什么事情:

    public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        }
    }

   private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
          //  分析1
          app.makeActive(thread, mProcessStats);

                //  分析2
                thread.bindApplication(processName, appInfo, providers,
                        app.instr.mClass,
                        profilerInfo, app.instr.mArguments,
                        app.instr.mWatcher,
                        app.instr.mUiAutomationConnection, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(getGlobalConfiguration()), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial);
    }
  • app是一个ProcessRecord对象,ProcessRecord是AMS的一个内部类,是对一个进程的封装,包含了一个用户进程的所有信息;将用户进程传入的ApplicationThread对象通过makeActive()保存到ProcessRecord中,以后当AMS需要向APP发起Binder通信时,就可以直接通过app.thread发起一次Binder通信;

  • 这里就是发起了一次Binder,最终会调用服务端(APP进程)ApplicationThread的bindApplication(); 在这里App进程就知道刚刚发起的attach成功了;

整体梳理:
  • 在AMS构造的时候,会调用ServiceManager.addService()将SystemServer进程的各种需要跨进程的服务保存起来,本质是保存到Binder驱动确定的ServiceManager进程的service_manager表中;
  • Binder通信的本质是通过客户端代理和服务端真实对象实现的,所以AMS进程和APP进程需要实现双工通信,必须同时是客户端和服务端(即有代理对象也有真实对象)
  • App进程作为客户端,AMS作为服务端:首先通过ServiceManager.getService()获取AMS的Binder对象;然后对这个对象封装到ActivityManagerProxy中,这个AMP就是AMS在APP进程本地的代理;
  • App进程作为服务端,AMS作为客户端:在APP的入口main中通过AMS在本地的代理发起一次Binder通信,将本地的Binder(ApplicationThread)发送给AMS进程,AMS接收到了以后将其保存在自己的ProcessRecord中,以后当AMS需要向APP发起跨进程通信时,只需要通过ProcessRecord中保存的APP进程的代理即可;

相关文章

网友评论

      本文标题:AMS系列②—Binder通信的双向代理绑定

      本文链接:https://www.haomeiwen.com/subject/yoqemktx.html