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

大家好,我系苍王。

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

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

Google爸爸,听说要将一些插件化hook系统的变量属性禁用,Android P之后很可能将会不再有插件化、热更新、主题变换、资源加固等骚操作。试图hook,你将会看到 NoSuchFieldException 或者 NoSuchMethodException 等错误提示。
可见文章Android P 调用隐藏API限制原理中对api隐藏说明
具体通过@hide的注释让属性提示变量不存在。
这样就会要求app上线前测试更加严谨,而不是在上线后通过各种修复替换功能等方式,每周发版的日子,将不会出现了,不停歇的加班。
RN技术其原理涉及到view的渲染,暂时并未受到波及。
现在国内,有继续走RN的,各大厂有走类似小程序方向的快应用,都是使用js语法,写web还能拯救一堆程序猿啊。

接下来说一下进程通信,其实任何的进程通信方式,都可以在组件化开发中使用。
Android中进程间通信的方式
1.Aidl
2.Messenger
3.Content provider
4.Socket
5.文件共享

前三个都是基于binder机制实现的。
本节想要介绍的是使用aidl做的进程通信,单单使用aidl进行通信其实并不难。原理也有很多文章介绍过,但是如何设计一个通用的aidl通信架构,就需要考究了。
这里介绍的是ModularizationArchitecture中使用的aidl的通信架构。


ModularizationArchitecture通信架构

这里ModularizationArchitecture架构使用了aidl作为路由传输的实现。

文件结构

1.每个需要通信的module,都需要继承MaProvider类,然后在BaseApplicationLogic启动的时候注册。
2.MaAction作为触发的事件,继承出来改写其方法,invoke方法是事件实现。需要在MaProvider中注册事件。
3.MaActionResult是事件结果回调。
4.LocalRouter是当前进程调用MaAction中的invoke执行方法。
5.WideRouter是跨进程调用时使用,需要在MaApplication启动的时候注册将module中的的LocalRouterConnectService。

注册提供内容



注册进程路由信息到广域路由中

public class MyApplication extends MaApplication {//注册进程路由信息到广域路由@Overridepublic void initializeAllProcessRouter() {WideRouter.registerLocalRouter("com.spinytech.maindemo",MainRouterConnectService.class);WideRouter.registerLocalRouter("com.spinytech.maindemo:music",MusicRouterConnectService.class);WideRouter.registerLocalRouter("com.spinytech.maindemo:pic",PicRouterConnectService.class);}//初始化进程启动@Overrideprotected void initializeLogic() {registerApplicationLogic("com.spinytech.maindemo",999, MainApplicationLogic.class);registerApplicationLogic("com.spinytech.maindemo",998, WebApplicationLogic.class);registerApplicationLogic("com.spinytech.maindemo:music",999, MusicApplicationLogic.class);registerApplicationLogic("com.spinytech.maindemo:pic",999, PicApplicationLogic.class);}//是否使用多进程@Overridepublic boolean needMultipleProcess() {return true;}
}
复制代码

进程初始化的时候注册MaProvider到进程路由中

public class MainApplicationLogic extends BaseApplicationLogic {@Overridepublic void onCreate() {super.onCreate();//注册ProviderLocalRouter.getInstance(mApplication).registerProvider("main",new MainProvider());}
}
复制代码

为每个Provider绑定可以触发的Action任务

public class MainProvider extends MaProvider {@Overrideprotected void registerActions() {registerAction("sync",new SyncAction());registerAction("async",new AsyncAction());registerAction("attachment",new AttachObjectAction());}
}
复制代码

下面是进程内同步通信


进程内同步通信

进程内调用

RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())  //进程中单例LocalRouter.route(MainActivity.this, RouterRequest.obtain(MainActivity.this) //在缓存池中获取请求.provider("main")   //设定provider.action("sync")     //设定调用的action.data("1", "Hello")   //设定数据.data("2", "World"));
复制代码

通过注册的内容找到相应的action,然后调用action中的invoke方法

public RouterResponse route(Context context, @NonNull RouterRequest routerRequest) throws Exception {Logger.d(TAG, "Process:" + mProcessName + "\nLocal route start: " + System.currentTimeMillis());RouterResponse routerResponse = new RouterResponse();// Local request//检查domain是不是在同一个进程if (mProcessName.equals(routerRequest.getDomain())) {HashMap<String, String> params = new HashMap<>();Object attachment = routerRequest.getAndClearObject();params.putAll(routerRequest.getData());Logger.d(TAG, "Process:" + mProcessName + "\nLocal find action start: " + System.currentTimeMillis());//通过provider索引到actionMaAction targetAction = findRequestAction(routerRequest);routerRequest.isIdle.set(true);Logger.d(TAG, "Process:" + mProcessName + "\nLocal find action end: " + System.currentTimeMillis());routerResponse.mIsAsync = attachment == null ? targetAction.isAsync(context, params) : targetAction.isAsync(context, params, attachment);// Sync result, return the result immediately// 同步调用.if (!routerResponse.mIsAsync) {//调用action的实现MaActionResult result = attachment == null ? targetAction.invoke(context, params) : targetAction.invoke(context, params, attachment);//包装responserouterResponse.mResultString = result.toString();routerResponse.mObject = result.getObject();Logger.d(TAG, "Process:" + mProcessName + "\nLocal sync end: " + System.currentTimeMillis());}
复制代码

下面是进程内异步通信


进程内异步通信[图片上传中...(屏幕快照 2018-03-30 下午12.36.03.png-c9d7e7-1522384627443-0)]

route方法中在mIsAsync设定是否异步

public RouterResponse route(Context context, @NonNull RouterRequest routerRequest) throws Exception {Logger.d(TAG, "Process:" + mProcessName + "\nLocal route start: " + System.currentTimeMillis());RouterResponse routerResponse = new RouterResponse();// Local request//检查domain是不是在同一个进程if (mProcessName.equals(routerRequest.getDomain())) {...// Sync result, return the result immediately// 同步调用.if (!routerResponse.mIsAsync) {...}// Async result, use the thread pool to execute the task.//异步调用else {//创建异步任务LocalTask task = new LocalTask(routerResponse, params,attachment, context, targetAction);//通过线程池调用routerResponse.mAsyncResponse = getThreadPool().submit(task);}
复制代码

异步调用任务是使用Callback任务

    //使用Future Callable的方式使用线程池private class LocalTask implements Callable<String> {private RouterResponse mResponse;private HashMap<String, String> mRequestData;private Context mContext;private MaAction mAction;private Object mObject;public LocalTask(RouterResponse routerResponse, HashMap<String, String> requestData,Object object, Context context, MaAction maAction) {this.mContext = context;this.mResponse = routerResponse;this.mRequestData = requestData;this.mAction = maAction;this.mObject = object;}@Overridepublic String call() throws Exception {//调用action中的invoke方法MaActionResult result = mObject == null ? mAction.invoke(mContext, mRequestData) : mAction.invoke(mContext, mRequestData, mObject);mResponse.mObject = result.getObject();Logger.d(TAG, "Process:" + mProcessName + "\nLocal async end: " + System.currentTimeMillis());return result.toString();}}
复制代码

下面是跨进程通信


跨进程通信

使用aidl调用广域的WideRouter

//检查domain是不是在同一个进程if (mProcessName.equals(routerRequest.getDomain())) {...}// IPC requestelse {//获取进程domainString domain = routerRequest.getDomain();String routerRequestString = routerRequest.toString();routerRequest.isIdle.set(true);//检查是不已经绑定了广域路由WideRouterif (checkWideRouterConnection()) {Logger.d(TAG, "Process:" + mProcessName + "\nWide async check start: " + System.currentTimeMillis());//If you don't need wide async check, use "routerResponse.mIsAsync = false;" replace the next line to improve performance.//检查是同步还是异步routerResponse.mIsAsync = mWideRouterAIDL.checkResponseAsync(domain, routerRequestString);Logger.d(TAG, "Process:" + mProcessName + "\nWide async check end: " + System.currentTimeMillis());}// Has not connected with the wide router.else {//调用连接广域路由WideRouterrouterResponse.mIsAsync = true;ConnectWideTask task = new ConnectWideTask(routerResponse, domain, routerRequestString);routerResponse.mAsyncResponse = getThreadPool().submit(task);return routerResponse;}//同步调用if (!routerResponse.mIsAsync) {//aidl传输给相关进程的LocalRouterConnectServicerouterResponse.mResultString = mWideRouterAIDL.route(domain, routerRequestString);Logger.d(TAG, "Process:" + mProcessName + "\nWide sync end: " + System.currentTimeMillis());}// Async result, use the thread pool to execute the task.//异步调用else {//设定广域调用任务WideTask task = new WideTask(domain, routerRequestString);routerResponse.mAsyncResponse = getThreadPool().submit(task);}}//返回ReouterResponsereturn routerResponse;
复制代码

广域路由连接检测,调用aidl连接到WideRouterConnectService

    private class ConnectWideTask implements Callable<String> {private RouterResponse mResponse;private String mDomain;private String mRequestString;public ConnectWideTask(RouterResponse routerResponse, String domain, String requestString) {this.mResponse = routerResponse;this.mDomain = domain;this.mRequestString = requestString;}@Overridepublic String call() throws Exception {Logger.d(TAG, "Process:" + mProcessName + "\nBind wide router start: " + System.currentTimeMillis());//绑定WideRouterConnectServiceconnectWideRouter();int time = 0;while (true) {//等待广域路由绑定完成if (null == mWideRouterAIDL) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}time++;} else {break;}//超过30秒就放弃,抛出错误if (time >= 600) {ErrorAction defaultNotFoundAction = new ErrorAction(true, MaActionResult.CODE_CANNOT_BIND_WIDE, "Bind wide router time out. Can not bind wide router.");MaActionResult result = defaultNotFoundAction.invoke(mApplication, new HashMap<String, String>());mResponse.mResultString = result.toString();return result.toString();}}Logger.d(TAG, "Process:" + mProcessName + "\nBind wide router end: " + System.currentTimeMillis());//调用关于路由传输到对应的进程路由String result = mWideRouterAIDL.route(mDomain, mRequestString);Logger.d(TAG, "Process:" + mProcessName + "\nWide async end: " + System.currentTimeMillis());return result;}}
复制代码

WideRouterConnectService对对应的进程路由分发通信,监听返回。

//广域路由处理IWideRouterAIDL.Stub stub = new IWideRouterAIDL.Stub() {@Overridepublic boolean checkResponseAsync(String domain, String routerRequest) throws RemoteException {//检查是否异步调动return WideRouter.getInstance(MaApplication.getMaApplication()).answerLocalAsync(domain, routerRequest);}@Overridepublic String route(String domain, String routerRequest) {try {//广域路由分发到对应的进程路由中return WideRouter.getInstance(MaApplication.getMaApplication()).route(domain, routerRequest).mResultString;} catch (Exception e) {e.printStackTrace();return new MaActionResult.Builder().code(MaActionResult.CODE_ERROR).msg(e.getMessage()).build().toString();}}@Overridepublic boolean stopRouter(String domain) throws RemoteException {//停止连接进程路由return WideRouter.getInstance(MaApplication.getMaApplication()).disconnectLocalRouter(domain);}};
复制代码

根据domain分发到对应进程的ILocalRouterAIDL

public RouterResponse route(String domain, String routerRequest) {Logger.d(TAG, "Process:" + PROCESS_NAME + "\nWide route start: " + System.currentTimeMillis());RouterResponse routerResponse = new RouterResponse();//是否已经被要求停止任务if (mIsStopping) {MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_WIDE_STOPPING).msg("Wide router is stopping.").build();routerResponse.mIsAsync = true;routerResponse.mResultString = result.toString();return routerResponse;}//广域路由不能作为调用对象if (PROCESS_NAME.equals(domain)) {MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_TARGET_IS_WIDE).msg("Domain can not be " + PROCESS_NAME + ".").build();routerResponse.mIsAsync = true;routerResponse.mResultString = result.toString();return routerResponse;}//获取对应进程路由的对象ILocalRouterAIDL target = mLocalRouterAIDLMap.get(domain);if (null == target) {//是否已经绑定了本地路由,没有就启动绑定if (!connectLocalRouter(domain)) {MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_ROUTER_NOT_REGISTER).msg("The " + domain + " has not registered.").build();routerResponse.mIsAsync = false;routerResponse.mResultString = result.toString();Logger.d(TAG, "Process:" + PROCESS_NAME + "\nLocal not register end: " + System.currentTimeMillis());return routerResponse;} else {// Wait to bind the target process connect service, timeout is 30s.Logger.d(TAG, "Process:" + PROCESS_NAME + "\nBind local router start: " + System.currentTimeMillis());int time = 0;//等待完成绑定进程连接while (true) {target = mLocalRouterAIDLMap.get(domain);if (null == target) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}time++;} else {Logger.d(TAG, "Process:" + PROCESS_NAME + "\nBind local router end: " + System.currentTimeMillis());break;}//设定30s超时if (time >= 600) {MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_CANNOT_BIND_LOCAL).msg("Can not bind " + domain + ", time out.").build();routerResponse.mResultString = result.toString();return routerResponse;}}}}try {Logger.d(TAG, "Process:" + PROCESS_NAME + "\nWide target start: " + System.currentTimeMillis());//对应进程调用返回String resultString = target.route(routerRequest);routerResponse.mResultString = resultString;Logger.d(TAG, "Process:" + PROCESS_NAME + "\nWide route end: " + System.currentTimeMillis());} catch (RemoteException e) {e.printStackTrace();MaActionResult result = new MaActionResult.Builder().code(MaActionResult.CODE_REMOTE_EXCEPTION).msg(e.getMessage()).build();routerResponse.mResultString = result.toString();return routerResponse;}return routerResponse;}
复制代码

基本原理就介绍到这里了。
1.aidl是google为Android进程通信提供的方式,使用了代理模式,其内部集成了IBinder,使用了Binder的方式通信,已经成为套路的规则,维护成本低。
2.当序列化后的数据单元过大时,就会出问题,报出android.os.TransactionTooLargeException。其数据量限制为1M
3.原理上说就是binder只拷贝一次,使用虚拟内存和物理内存页映射,比socket高效,也安全。
4.这里介绍的框架,其中是通过本地路由和广域路由间的传送和切换来完成。只能交流变量和调用方法,无法通过aidl获取资源。本地路由能力并未有ARouter使用的方便,进程内对无法提供获取Fragment View等资源获取,可以考虑拓展。但是此本地和广域路由设计非常优秀。
5.wutongke有出了一个框架加上编译时注解的优化版github.com/wutongke/Mo…

下一节将会继续介绍Messenger进程通信框架,敬请期待。


Android进程化学习


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/255071.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在未启动程序情况 点击视图设计器 弹出未将对象引用窗体的解决方案

请问下 在未运行程序情况 点击视图设计器 弹出未将对象引用窗体 解决方案&#xff1a;1.看后台进程是不是相关的进程在启动&#xff0c;如果有关闭进程&#xff1b;重启vs,即可2.重启电脑转载于:https://www.cnblogs.com/yang12311/p/5593838.html

图像配准的步骤

目前&#xff0c;很难找到一种普适的方法能够应对所有的配准情况&#xff0c;任何一种配准算法都必须考虑图像的成像原理、几何变形、噪声影响、配准精度等因素。不过&#xff0c;从原理上将&#xff0c;配准算法可以大致分为以下四个步骤&#xff1a; &#xff08;1&#xff0…

Jm86中的encode_one_macroblock注释

Jm86中的encode_one_macroblock注释 /*! ************************************************************************************** /brief* Mode Decision for a macroblock* //该函数的作用是编码一个宏块&#xff08;包括帧间、帧内、帧内预测的方式&#xff09;。*…

Python之路【第十七篇】:装饰器

写代码的时候有一个原则&#xff0c;开放封闭原则(面向对象)&#xff1a;对某些东西开放&#xff0c;对某些封闭&#xff0c;在装饰器这里&#xff0c;函数内部是封闭的&#xff0c;不允许改变函数的内部。 装饰器用来装饰函数&#xff0c;可以让函数在执行之前或者执行之后&am…

HALCON示例程序measure_chip.hdev芯片封装检测

HALCON示例程序measure_chip.hdev芯片封装检测 示例程序源码&#xff08;加注释&#xff09; 关于显示类函数解释 dev_update_off () read_image (Image, ‘die_on_chip’) get_image_size (Image, Width, Height) dev_close_window () dev_open_window (0, 0, Width * 2, He…

工业机器人智能发展:视觉和触觉感应简化

机器人工业协会&#xff08;Robotic Industries Association&#xff09;指出&#xff0c;从2003到2005年间&#xff0c;北美机器人工业以20%的平均年增长率发展。在汽车市场需求疲软以及外国厂商的压力不断增加的背景下&#xff0c;这一成就是如何取得的&#xff1f;成本的普遍…

ASP站点无法访问怎么办

确保启用了目录浏览功能 转载于:https://www.cnblogs.com/acetaohai123/p/6571257.html

五、案例-指令参考-freemarker指令、表达式

案例-指令参考描述&#xff1a;本人自己测试写了一遍&#xff0c;如有错的地方&#xff0c;懂freemarker的朋友望指点指点&#xff01; 案例-指令参考 表达式 一、 Assign 1、<#assign name1"北京" name2"上海" name3"广东"> 调用&#xf…

PartitionMotionSearch()函数

encode_one_macroblock()函数中的运动估计分为两大块&#xff0c;对于宏块级的三种模式&#xff0c;分块后直接对patition依次调用PartitionMotionSearch()函数&#xff1b;而对于亚宏块级的&#xff08;含8x8, 8x4,4x8,4x4&#xff09;模式&#xff0c;首先将宏块拆分为4个88子…

201521123017 《Java程序设计》第4周学习总结

1. 本周学习总结 2. 书面作业 Q1.注释的应用 使用类的注释与方法的注释为前面编写的类与方法进行注释&#xff0c;并在Eclipse中查看。(截图) Q2.面向对象设计(大作业1&#xff0c;非常重要) 2.1 将在网上商城购物或者在班级博客进行学习这一过程&#xff0c;描述成一个故事。…

完整的VAL3程序

start() begin//延时10秒 delay(5)//初始化变量call init()//清空原有运动堆栈resetMotion()//建立上电任务taskCreate "robotpower",100,robotpower()wait(isPowered())//建立生产任务taskCreate "ProductionCycle",10,ProductionCycle()//建立安全区域…

iOS WebView 加载本地资源(图片,文件等)

NSString *path [[NSBundle mainBundle] pathForResource:"关于.docx" ofType:nil]; NSURL *url [NSURL fileURLWithPath:path]; NSLog("%", [self mimeType:url]); //webview加载本地文件&#xff0c;可以使用加载数据的方式 //第一个诶参数是一个N…

本文以H264视频流为例,讲解解码流数据的步骤。

本文以H264视频流为例&#xff0c;讲解解码流数据的步骤。 为突出重点&#xff0c;本文只专注于讨论解码视频流数据&#xff0c;不涉及其它&#xff08;如开发环境的配置等&#xff09;。如果您需要这方面的信息&#xff0c;请和我联系。 准备变量 定义AVCodecContext。如…

2008-2021年商业银行数据(农商行、城商行、国有行、股份制银行)

2008-2021年商业银行数据&#xff08;农商行、城商行、国有行、股份制银行&#xff09; 1、时间&#xff1a;2008-2021年 2、范围&#xff1a;1700银行 3 、指标&#xff1a;证券简称、year、证券代码、资产总计、负债合计、所有者权益合计、利润总额、净利润、贷款总额、存…

EPSON 任务同步 改写

有时需要在多个任务执行之前来使它们同步。如果预先知道执行每项任务所需要的时间&#xff0c;它们就可以通过简单地等待由最慢的任务产生的信号来实现同步。然而&#xff0c;如果不知道那个任务是最慢的&#xff0c;就需要使用一个更复杂的同步化机制&#xff0c;如下所示VAL …

线程池的简单使用

创建指定线程数量的线程池 private static ExecutorService scheduledTaskFactoryExecutor null;private boolean isCancled false;private static class ThreadFactoryTest implements ThreadFactory { Overridepublic Thread newThread(Runnable r) { Thread threa…

异常--自定义异常类

为什么要调用父类构造器? http://blog.csdn.net/rockpk008/article/details/52951856 转载于:https://www.cnblogs.com/dwj-ngu/p/6576382.html

利用ffmpeg来进行视频解码的完整示例代码

&#xff08;转&#xff09;利用ffmpeg来进行视频解码的完整示例代码&#xff08;H.264&#xff09; Decode() { FILE * inpf; int nWrite; int i,p; int nalLen; unsigned char * Buf; int got_picture, consumed_bytes; unsigned char *DisplayBuf; Displ…

安卓观看免费视频

http://www.imooc.com/search/course?wordsAndroid%E6%94%BB%E5%9F%8E%E7%8B%AE%E7%AC%AC%E4%B8%80%E8%AF%BE&page3 http://www.imooc.com/course/list?candroid&src360onebox http://www.bilibili.com/video/av2788563/index_4.html http://www.imooc.com/course/pr…

EtherCAT 网站链接

http://www.ethercat.org.cn/cn.htm EtherCAT技术介绍 EtherCAT系统组成和工作原理 EtherCAT采用主从式结构&#xff0c;主站PC机采用标准的100Base-TX以太网卡&#xff0c;从站采用专用芯片。系统控制周期由主站发起&#xff0c;主站发出下行电报&#xff0c;电报的最大有效数…