[Android]你不知道的Android进程化(6)--进程通信Andromeda框架

大家好,我系苍王。
以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章。

[Android]如何做一个崩溃率少于千分之三噶应用app–章节列表

《[Android]你不知道的Android进程化(6)--进程通信Andromeda框架》 Android组件化架构热卖中

组件化群1已经满员,进来的可以加群2 763094035

近来看到爱奇艺发布了多进程的架构框架Andromeda。研究一下其多进程的通信方式。

具体github地址

通过此框架的初步分析

1.通过grade插件完善AndroidManifest.xml配置文件

2.通过ContentProvider传输binder对象

3.活动binder.stub对象

4.动态绑定进程service以及binder对象

5.多进程binder管理

其在利用自定义Gradle插件来插入DispatchService和DipatchProvider。
自定义的Gradle插件只会有app module上运行。
其会读取Manifest里面的内容并进行修改。

《[Android]你不知道的Android进程化(6)--进程通信Andromeda框架》 插件配置.png

1.查找遍历Manifest文件

   void injectStubServiceToManifest(Project project) {

        println "injectStubServiceToManifest"
        //主目录
        rootDirPath = project.rootDir.absolutePath

        def android = project.extensions.getByType(AppExtension)
        
        this.dispatcher = project.extensions.getByType(DispatcherExtension)

        project.afterEvaluate {
            android.applicationVariants.all { variant ->
                 
                if (pkgName == null) {
                    //获取包名
                    pkgName = getPackageName(variant)
                    println "pkgName:" + pkgName
                }
               //查找遍历Mainfest文件
                variant.outputs.each { output ->

                    output.processManifest.doLast {

                        println "manifestOutputDirectory:" + output.processManifest.manifestOutputDirectory.absolutePath

                        //output.getProcessManifest().manifestOutputDirectory
                        output.processManifest.outputs.files.each { File file ->
                            //在gradle plugin 3.0.0之前,file是文件,且文件名为AndroidManifest.xml
                            //在gradle plugin 3.0.0之后,file是目录,且不包含AndroidManifest.xml,需要自己拼接
                            //除了目录和AndroidManifest.xml之外,还可能会包含manifest-merger-debug-report.txt等不相干的文件,过滤它
                            if ((file.name.equalsIgnoreCase("AndroidManifest.xml") && !file.isDirectory()) || file.isDirectory()) {
                                if (file.isDirectory()) {
                                    //3.0.0之后,自己拼接AndroidManifest.xml
                                    injectManifestFile(new File(file, "AndroidManifest.xml"))
                                } else {
                                    //3.0.0之前,直接使用
                                    injectManifestFile(file)
                                }
                            }
                        }
                    }

                }
            }
        }
    }

其内会写入三种文件

def static final STUB_SERVICE = 'org.qiyi.video.svg.stub.CommuStubService$CommuStubService'

xml.application {

            int index = 0
            //每个进程都声明使用这个CommuStubService文件
            customProcessNames.each {
                //加上序号,$CommuStuService会替换成数字
                String serviceName = "${STUB_SERVICE}" + index.toString()

                service("${NAME}": serviceName,
                        "${ENABLED}": "${TRUE}",
                        "${EXPORTED}": "${FALSE}",
                        "${PROCESS}": it
                )

                if (matchedServices == null) {
                    matchedServices = new HashMap<>()
                }
                matchedServices.put(it, serviceName)

                ++index
            }

这里DipatcherService和DipatchProvider是binder的中转管理控件,默认配置到主进程。

        //配置进程地址
        this.dispatcher = project.extensions.getByType(DispatcherExtension)

           //之后,写入DispatcherService和DispatcherProvider
            def dispatcherProcess = dispatcher.process
            println "dispatcher.process:" + dispatcher.process
            if (dispatcherProcess != null && dispatcherProcess.length() > 0) {
                service("${NAME}": DISPATCHER_SERVICE,
                        "${ENABLED}": "${TRUE}",
                        "${EXPORTED}": "${FALSE}",
                        "${PROCESS}": dispatcherProcess
                )

                provider(
                        "${AUTHORITIES}": getAuthority(),
                        "${EXPORTED}": "${FALSE}",
                        "${NAME}": DISPTACHER_PROVIDER,
                        "${ENABLED}": "${TRUE}",
                        "${PROCESS}": dispatcherProcess
                )

            } else {
                service("${NAME}": DISPATCHER_SERVICE,
                        "${ENABLED}": "${TRUE}",
                        "${EXPORTED}": "${FALSE}"
                )

                provider(
                        "${AUTHORITIES}": getAuthority(),
                        "${EXPORTED}": "${FALSE}",
                        "${NAME}": DISPTACHER_PROVIDER,
                        "${ENABLED}": "${TRUE}"
                )

            }

正如通信所涉及的必要的几个步骤
1.注册
2.发其通信
3.binder间的相互绑定
4.binder间传输数据

《[Android]你不知道的Android进程化(6)--进程通信Andromeda框架》 注册流程

首先注册,通过公共的Andromeda入口注册提供远程沟通的服务

Andromeda.getInstance().registerRemoteService(IBuyApple.class, BuyAppleImpl.getInstance());

    //RemoteTransfer
    public static <T extends IBinder> void registerRemoteService(Class serviceClass, T stubBinder) {
        if (null == serviceClass || null == stubBinder) {
            return;
        }
        RemoteTransfer.getInstance().registerStubService(serviceClass.getCanonicalName(), stubBinder);
    }

    //RemoteServiceTransfer
    public void registerStubServiceLocked(String serviceCanonicalName, IBinder stubBinder,
                                          Context context, IDispatcher dispatcherProxy, IRemoteTransfer.Stub stub) {
        stubBinderCache.put(serviceCanonicalName, stubBinder);
        if (dispatcherProxy == null) {
            BinderWrapper wrapper = new BinderWrapper(stub.asBinder());
            Intent intent = new Intent(context, DispatcherService.class);
            intent.setAction(Constants.DISPATCH_REGISTER_SERVICE_ACTION);
            intent.putExtra(Constants.KEY_REMOTE_TRANSFER_WRAPPER, wrapper);
            intent.putExtra(Constants.KEY_BUSINESS_BINDER_WRAPPER, new BinderWrapper(stubBinder));
            intent.putExtra(Constants.KEY_SERVICE_NAME, serviceCanonicalName);
            setProcessInfo(intent, context);
            ServiceUtils.startServiceSafely(context, intent);
        } else {
            try {
                dispatcherProxy.registerRemoteService(serviceCanonicalName,
                        ProcessUtils.getProcessName(context), stubBinder);
            } catch (RemoteException ex) {
                ex.printStackTrace();
            }
        }
    }

启动Service注册到DispatcherService当中

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent == null) {
            return super.onStartCommand(intent, flags, startId);
        }
        Logger.d("DispatcherService-->onStartCommand,action:" + intent.getAction());
        if (Constants.DISPATCH_REGISTER_SERVICE_ACTION.equals(intent.getAction())) {
            //注册远程服务
            registerRemoteService(intent);
        } else if (Constants.DISPATCH_UNREGISTER_SERVICE_ACTION.equals(intent.getAction())) {
            //注销远程服务
            unregisterRemoteService(intent);
        } else if (Constants.DISPATCH_EVENT_ACTION.equals(intent.getAction())) {
            //传递数据
            publishEvent(intent);
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private void registerRemoteService(Intent intent) {

        BinderWrapper wrapper = intent.getParcelableExtra(Constants.KEY_REMOTE_TRANSFER_WRAPPER);
        BinderWrapper businessWrapper = intent.getParcelableExtra(Constants.KEY_BUSINESS_BINDER_WRAPPER);
        String serviceCanonicalName = intent.getStringExtra(Constants.KEY_SERVICE_NAME);
        int pid = intent.getIntExtra(Constants.KEY_PID, -1);
        String processName = intent.getStringExtra(Constants.KEY_PROCESS_NAME);
        try {
            if (TextUtils.isEmpty(serviceCanonicalName)) {
                //注意:RemoteTransfer.sendRegisterInfo()时,serviceCanonicalName为null,这是正常的,此时主要目的是reigsterAndReverseRegister()
                Logger.e("service canonical name is null");
            } else {
             //注册到分发器上管理
                Dispatcher.getInstance().registerRemoteService(serviceCanonicalName,
                        processName, businessWrapper.getBinder());
            }
        } catch (RemoteException ex) {
            ex.printStackTrace();
        } finally {
            if (wrapper != null) {
                registerAndReverseRegister(pid, wrapper.getBinder());
            }
        }

    }

ServiceDipatcher负责管理服务信息

 @Override
    public void registerRemoteServiceLocked(final String serviceCanonicalName, String processName,
                                            IBinder binder) throws RemoteException {
        Log.d(TAG, "ServiceDispatcher-->registerStubServiceLocked,serviceCanonicalName:" + serviceCanonicalName + ",pid:" + android.os.Process.myPid() + ",thread:" + Thread.currentThread().getName());
        if (binder != null) {
            binder.linkToDeath(new IBinder.DeathRecipient() {
                @Override
                public void binderDied() {
                    Logger.d("ServiceDispatcher-->binderDied,serviceCanonicalName:" + serviceCanonicalName);
                    BinderBean bean = remoteBinderCache.remove(serviceCanonicalName);
                    //实际上这里是还没实现线程同步,但是并不会影响执行结果,所以其实下面这句就没有同步的必要。
                    if (bean != null) {
                        emergencyHandler.handleBinderDied(Andromeda.getAppContext(), bean.getProcessName());
                    }
                }
            }, 0);
            remoteBinderCache.put(serviceCanonicalName, new BinderBean(binder, processName));
            Logger.d("ServiceDispatcher-->registerRemoteServiceLocked(),binder is not null");
        } else {
            Log.d(TAG, "ServiceDispatcher-->registerRemoteServiceLocked(),binder is null");
        }
    }

最后需要完成反向绑定,意思是Dispatcher注册可以传输的binder对象,传输中心也需要绑定Dispatcher对象

    /**
     * 注册和反向注册
     *
     * @param pid
     * @param transterBinder
     */
    private void registerAndReverseRegister(int pid, IBinder transterBinder) {
        Logger.d("DispatcherService-->registerAndReverseRegister,pid=" + pid + ",processName:" + ProcessUtils.getProcessName(pid));
        IRemoteTransfer remoteTransfer = IRemoteTransfer.Stub.asInterface(transterBinder);
        
        Dispatcher.getInstance().registerRemoteTransfer(pid, transterBinder);

        if (remoteTransfer != null) {
            Logger.d("now register to RemoteTransfer");
            try {
                remoteTransfer.registerDispatcher(Dispatcher.getInstance().asBinder());
            } catch (RemoteException ex) {
                ex.printStackTrace();
            }
        } else {
            Logger.d("IdspatcherRegister IBinder is null");
        }
    }

《[Android]你不知道的Android进程化(6)--进程通信Andromeda框架》 获取远端服务的binder.png

在调用远程的时候getRemoteSevice获取目标的binder对象

IBuyApple buyApple = IBuyApple.Stub.asInterface(Andromeda.with(this).getRemoteService(IBuyApple.class));

远程管理RemoteManager

    @Override
    public IBinder getRemoteService(Class<?> serviceClass) {
        if (null == serviceClass) {
            return null;
        }
        return getRemoteService(serviceClass.getCanonicalName());
    }

    @Override
    public synchronized IBinder getRemoteService(String serviceCanonicalName) {
        Logger.d(this.toString() + "-->getRemoteService,serviceName:" + serviceCanonicalName);
        if (TextUtils.isEmpty(serviceCanonicalName)) {
            return null;
        }
        BinderBean binderBean = RemoteTransfer.getInstance().getRemoteServiceBean(serviceCanonicalName);
        String commuStubServiceName = ConnectionManager.getInstance().bindAction(appContext, binderBean.getProcessName());
        commuStubServiceNames.add(commuStubServiceName);
        return binderBean.getBinder();
    }

RemoteDispatcher会调用DipatchProvider来获取远程的binder对象

    @Override
    public synchronized BinderBean getRemoteServiceBean(String serviceCanonicalName) {
        Logger.d("RemoteTransfer-->getRemoteServiceBean,pid=" + android.os.Process.myPid() + ",thread:" + Thread.currentThread().getName());
        //获取binder包装的对象
        BinderBean cacheBinderBean = serviceTransfer.getIBinderFromCache(context, serviceCanonicalName);
        if (cacheBinderBean != null) {
            return cacheBinderBean;
        }
        if (null == dispatcherProxy) {
            IBinder dispatcherBinder = getIBinderFromProvider();
            if (null != dispatcherBinder) {
                Logger.d("the binder from provider is not null");
                dispatcherProxy = IDispatcher.Stub.asInterface(dispatcherBinder);
                registerCurrentTransfer();
            }
        }
        if (null == dispatcherProxy) {
            sendRegisterInfo();
            try {
                wait(MAX_WAIT_TIME);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        if (serviceTransfer == null || dispatcherProxy == null) {
            return null;
        }
        return serviceTransfer.getAndSaveIBinder(serviceCanonicalName, dispatcherProxy);
    }

private IBinder getIBinderFromProvider() {
        Logger.d("RemoteTransfer-->getIBinderFromProvider()");
        Cursor cursor = null;
        try {
            //查询出cursor对象
            cursor = context.getContentResolver().query(getDispatcherProviderUri(), DispatcherProvider.PROJECTION_MAIN,
                    null, null, null);
            if (cursor == null) {
                return null;
            }
            //使用DispatcherCursor解包
            return DispatcherCursor.stripBinder(cursor);
        } finally {
            IOUtils.closeQuietly(cursor);
        }
    }

DispatcherProvider使用的查询返回

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        Logger.d("DispatcherProvider-->query,uri:" + uri.getAuthority());
        //DispatcherCursor封装binder
        return DispatcherCursor.generateCursor(Dispatcher.getInstance().asBinder());
    }

    //通过
    public static DispatcherCursor generateCursor(IBinder binder) {
        try {
            DispatcherCursor cursor;
            cursor = cursorCache.get(binder.getInterfaceDescriptor());
            if (cursor != null) {
                return cursor;
            }
            cursor = new DispatcherCursor(DEFAULT_COLUMNS, binder);
            cursorCache.put(binder.getInterfaceDescriptor(), cursor);
            return cursor;
        } catch (RemoteException ex) {
            return null;
        }
    }
    //通过BinderWrapper来封装binder
    public DispatcherCursor(String[] columnNames, IBinder binder) {
        super(columnNames);
        binderExtras.putParcelable(KEY_BINDER_WRAPPER, new BinderWrapper(binder));
    }
  @Override
    public synchronized IBinder getRemoteService(String serviceCanonicalName) {
        Logger.d(this.toString() + "-->getRemoteService,serviceName:" + serviceCanonicalName);
        if (TextUtils.isEmpty(serviceCanonicalName)) {
            return null;
        }
        //获取binder信息
        BinderBean binderBean = RemoteTransfer.getInstance().getRemoteServiceBean(serviceCanonicalName);
        //在binder绑定启动的进程service
        String commuStubServiceName = ConnectionManager.getInstance().bindAction(appContext, binderBean.getProcessName());
        commuStubServiceNames.add(commuStubServiceName);
        return binderBean.getBinder();
    }

一开始介绍插入了CommuStubService对象,这里通过StubServiceMatcher通过进程名来找到启动的进程的service,然后将binder和service绑定到一起

 //这里不能按照serviceCanonicalName来区分,而是要按照target service来划分,如果targetService一样,那就没必要再绑定
    public synchronized String bindAction(Context context, String serverProcessName) {
        Logger.d("ConnectionManager-->bindAction,serverProcessName:" + serverProcessName);
        //匹配对应的binder对应的Service(CommuStubService$0)
        Intent intent = StubServiceMatcher.matchIntent(context, serverProcessName);
        if (null == intent) {
            Logger.d("match intent is null");
            return null;
        }

        String commuStubServiceName = getCommuStubServiceName(intent);
        ConnectionBean bean = connectionCache.get(commuStubServiceName);
        if (null == bean) {
            //服务连接
            ServiceConnection connection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    Logger.d("onServiceConnected,name:" + name.getShortClassName());
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {
                    Logger.d("onServiceDisconnected,name:" + name.getShortClassName());
                }
            };
            bean = new ConnectionBean(connection);
            connectionCache.put(commuStubServiceName, bean);
            Logger.d("really start to bind");
            //启动服务
            context.bindService(intent, connection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
        } else {
            bean.increaseRef();
        }
        return commuStubServiceName;
    }

1.通过gradle插件来动态添加配置的四大组件资料
2.通过分发DispatchService服务来管理binder对象
3.通过Parcelable序列化传输binder
4.活用IBinder.Stub对象

《[Android]你不知道的Android进程化(6)--进程通信Andromeda框架》 Android进程化学习

    原文作者:CangWang
    原文地址: https://www.jianshu.com/p/426527ace584
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞