Android Telephony分析(七) ---- 接口扩展(异步转同步)
本文是基于上一篇《Android Telephony分析(六) —- 接口扩展(实践篇)》来写的。
上一篇介绍的接口扩展的方法需要实现两部分代码:
1. 从APP至RIL,发送请求;
2. 从RIL至APP,上报结果。
由于这是一个异步请求,所以两部分流程都不能少,导致流程过于复杂。
而本文的目的就是为了将异步请求转换成同步请求,节省第二部分“上报结果”的流程,从而简化整个接口扩展的流程和代码量。(当然,虽然《Android Telephony分析(六) —- 接口扩展(实践篇)》代码流程复杂了些,但是它综合较多的知识点,其自身的价值还是有的。)
本文来自http://blog.csdn.net/linyongan ,转载请务必注明出处。
1. 具体的代码实现
1.1 扩展CommandsInterface接口
同《Android Telephony分析(六) —- 接口扩展(实践篇)》1.1小节。
1.2 扩展PhoneInternalInterface接口
同《Android Telephony分析(六) —- 接口扩展(实践篇)》1.2小节。
假如现在Phone.java (frameworks\opt\telephony\src\java\com\Android\internal\telephony)中已有两个可用的接口:
@Overridepublic void setValueToModem(int input,Message resp){mCi.setValueToModem(input,resp);}@Overridepublic void getValueFromModem(Message resp){mCi.getValueFromModem(resp);}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
1.3 扩展ITelephony接口
先在ITelephony.aidl(frameworks\base\telephony\java\com\android\internal\telephony)中新增接口:
boolean setValueToModem (int input);
String getValueFromModem();
- 1
- 2
- 1
- 2
请注意,此时接口的返回值已不再是void。
在PhoneInterfaceManager.java (packages\services\telephony\src\com\android\phone)中实现该接口:
@Overridepublic String getValueFromModem() {//本小节的最后会讲解sendRequest()方法String value = (String)sendRequest(CMD_GET_VALUE,null);return value;}@Overridepublic boolean setValueToModem(int input) {Boolean success = (Boolean)sendRequest(CMD_SET_VALUE,input);return success;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
同时需要定义四个消息:
private static final int CMD_GET_VALUE = 100;private static final int EVENT_GET_VALUE_DONE = 101;private static final int CMD_SET_VALUE = 102;private static final int EVENT_SET_VALUE_DONE = 103;
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
以及在内部类MainThreadHandler的handleMessage()方法中添加对这四个消息的处理:
//发送get请求时的处理
case CMD_GET_VALUE:request = (MainThreadRequest) msg.obj;//将在sendRequest()方法中创建的MainThreadRequest对象封装进新的Message中。onCompleted = obtainMessage(EVENT_GET_VALUE_DONE, request);//在这里调用Phone中的接口mPhone.getValueFromModem(onCompleted);break;//对于get请求modem返回结果的处理
case EVENT_GET_VALUE_DONE:ar = (AsyncResult) msg.obj;//取出发送请求时创建的MainThreadRequest对象request = (MainThreadRequest) ar.userObj;//如果没有出现异常且返回的结果不为空if (ar.exception == null && ar.result != null) {request.result = ar.result;// String} else {//get请求出现异常,返回默认值request.result = "";if (ar.result == null) {loge("getValueFromModem: Empty response");} else if (ar.exception instanceof CommandException) {loge("getValueFromModem: CommandException: " +ar.exception);} else {loge("getValueFromModem: Unknown exception");}}synchronized (request) {//唤醒所有正在等待该对象的线程,退出wait的状态request.notifyAll();}break;//get请求,同理
case CMD_SET_VALUE:request = (MainThreadRequest) msg.obj;onCompleted = obtainMessage(EVENT_SET_VALUE_DONE, request);mPhone.setValueToModem((Integer) request.argument, onCompleted);break;case EVENT_SET_VALUE_DONE:ar = (AsyncResult) msg.obj;request = (MainThreadRequest) ar.userObj;if (ar.exception == null) {request.result = true;} else {request.result = false;if (ar.exception instanceof CommandException) {loge("setValueToModem: CommandException: " + ar.exception);} else {loge("setValueToModem: Unknown exception");}}synchronized (request) {request.notifyAll();}break;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
在PhoneInterfaceManager.java中的代码是本文的核心。在sendRequest()方法中会进入死循环,调用object.wait()强行阻塞线程,直到modem返回结果上来后,object的notifyAll()才停止,最后直接把结果返回给APP,所以这就是将异步请求强行转换成同步的解决方案。
sendRequest()方法是android原生的,不用我们添加代码:
/*** Posts the specified command to be executed on the main thread,* waits for the request to complete, and returns the result.*/private Object sendRequest(int command, Object argument, Integer subId) {if (Looper.myLooper() == mMainThreadHandler.getLooper()) {throw new RuntimeException("This method will deadlock if called from the main thread.");}//创建Request对象MainThreadRequest request = new MainThreadRequest(argument, subId);Message msg = mMainThreadHandler.obtainMessage(command, request);msg.sendToTarget();//锁住request对象synchronized (request) {//进入死循环while (request.result == null) {try {//让线程进入等待状态,直到它被notifyAll唤醒request.wait();} catch (InterruptedException e) {//就算异常也不退出,不return。}}}return request.result;}//其中MainThreadRequest只是一个普通的内部类,不是线程。//所以上面request.wait()调用的时Object类wait()方法。private static final class MainThreadRequest {/** The argument to use for the request */public Object argument;/** The result of the request that is run on the main thread */public Object result;// The subscriber id that this request applies to. Defaults to// SubscriptionManager.INVALID_SUBSCRIPTION_IDpublic Integer subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;public MainThreadRequest(Object argument) {this.argument = argument;}public MainThreadRequest(Object argument, Integer subId) {this.argument = argument;if (subId != null) {this.subId = subId;}}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
接着在TelephonyManager.java (frameworks\base\telephony\java\android\telephony)中封装Phone Service的方法:
/**@hide*/public String getValueFromModem() {try {ITelephony telephony = getITelephony();if (telephony != null)return telephony.getValueFromModem();} catch (RemoteException ex) {Rlog.e(TAG, "getValueFromModem RemoteException", ex);} catch (NullPointerException ex) {Rlog.e(TAG, "getValueFromModem NPE", ex);}return "";
}/**@hide*/public boolean setValueToModem(int input) {try {ITelephony telephony = getITelephony();if (telephony != null)return telephony.setValueToModem(input);} catch (RemoteException ex) {Rlog.e(TAG, "setValueToModem RemoteException", ex);} catch (NullPointerException ex) {Rlog.e(TAG, "setValueToModem NPE", ex);}return false;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
整个过程的时序图如下:
2. APP如何使用接口
在APP中可以这样调用并调试接口:
//set值
boolean setResult = TelephonyManager.getDefault().setValueToModem(1);
//get值
String getResult = TelephonyManager.getDefault().getValueToModem();
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
在APP侧来看,确实简单省事了很多,调用接口就可以马上得到返回值,但是有点需要注意的是,为了防止这种接口阻塞主线程,所以最好在子线程中调用这类接口。
3. 总结
将异步请求转换成同步请求,紧紧依赖着Object类的wait和notifyAll方法才能实现。当然Android代码中不仅仅只有PhoneInterfaceManager.java这个地方使用了这种方法,高通也实现了类似的代码提供API给APP侧调用,进而可以动态修改某些NV的值,这里只能点到为止。最后附上wait和notifyAll方法的详解:
void wait() :
导致线程进入等待状态,直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
void notifyAll() :
解除所有那些在该对象上调用wait方法的线程的阻塞状态。该方法只能在同步方法或同步块内部调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
原文地址: http://blog.csdn.net/linyongan/article/details/52189217
Android Telephony分析(七) ---- 接口扩展(异步转同步)相关推荐
- Android Telephony分析(六) ---- 接口扩展(实践篇)
本文将结合前面五篇文章所讲解的知识,综合起来,实现一个接口扩展的功能. 如果还没有阅读过前面五篇文章的内容,请先阅读: <Android Telephony分析(一) - Phone详解 & ...
- Android Telephony分析(三) ---- RILJ详解
前言 本文主要讲解RILJ工作原理,以便更好地分析代码,分析业务的流程. 这里说的RILJ指的是RIL.java (frameworks\opt\telephony\src\java\com\And ...
- Android Telephony分析(五) ---- TelephonyRegistry详解
本文紧接着上一篇文章<Android Telephony分析(四) -- TelephonyManager详解 >的1.4小节. 从TelephonyRegistry的大部分方法中: ...
- Android Telephony分析(二) ---- RegistrantList详解
前言 本文主要讲解RegistrantList的原理,以及如何快速分析RegistrantList相关的代码流程. 在Telephony模块中,在RIL.Tracker(ServiceStateTr ...
- Android Telephony分析(四) ---- TelephonyManager详解
前言 TelephonyManager主要提供Telephony相关信息的查询/修改功能,以及Phone状态监听功能,封装的方法主要是提供给APP上层使用. TelephonyManager.jav ...
- Android Telephony 分析【全】
11年下半年一直在做RIL的移植,主要解决第三方库的一些bug,使之能更好的工作在公司的PAD上.但是后来发现远远不够,有好多问题出现在Framework层.比方说我们想让PAD支持热插拔,尽管底层做 ...
- Android Telephony分析(一) ---- Phone详解
本文主要讲解Telephony中Phone相关的知识. 1. Android N中Phone的改变 Android 6.0时,Phone的继承关系: 在Android N中,Phone的继承关系: 变 ...
- 利用Future接口实现异步线程同步回滚
项目场景: 一个RBAC的权限管理架构 问题描述 大致就是在一个方法中开子线程进行异步数据处理, 如果业务处理失败肯定是要回退的, 而且这种父子线程相关连的业务肯定是要一起回退的, 那么问题来了, 异 ...
- 【Android 异步操作】FutureTask 分析 ( Future 接口解析 | Runnable 接口解析 | Callable 接口解析 )
文章目录 一.Future 接口 1.Future 接口简介 2.取消任务方法 3.Future 接口源码注释 二.Callable 接口 三.Runnable 接口 上一篇博客 [Android 异 ...
最新文章
- easyexcel写入数据为空_如何解决Redis缓存和MySQL数据一致性的问题?
- 【ETL】ETL讲解(很详细!!!)
- .NET中常见的 IL 指令集
- Mysql Errcode: 24 - Too many open files
- 主题:大胆预测下JS框架的走势(ZT)
- Bailian2888 字符串中的数字【字符串】
- 数字签名工具signtool
- 双层pdf怎么制作(可以复制里面文字)纸质书如何制作扫描图片书签目录?
- 【雨滴风格 时间倒计时置顶显示小工具】
- QT 弹出pdf 或者网页【软件 help/about按钮】
- QQ音乐接口api,包括付费音乐、无损音乐、高品质音乐地址解析接口api
- 微软商店无法连接网络的问题解决
- android button 图片与文字一起
- Fiddler替换HTTP Request Host
- 2020哔哩哔哩大数据面试题整理
- 名称、系统服务-windows系统进程解析 -by小雨
- (与运算)、|(或运算)、^(异或运算)的含义
- 2018-2019-2学号20189220余超《移动平台应用程序开发实践》课程总结
- RBD存储模式为RWX时kubernetes多次挂载该PV不报错
- 《易经》对中华文化的影响
热门文章
- web在线聊天系统。非ajax轮询
- 光脚丫学LINQ(025):如何验证DBML和外部映射文件
- ASP.NET 3.5 Extensions预览版即将发布
- csdn编辑器模板2
- java web 进程通信_RMI网络编程开发之一 JAVA“进程间”通信方式
- 【Matlab】for循环进度条显示百分比进程和剩余时间
- 科大星云诗社动态20210429
- 学长毕业日记 :本科毕业论文写成博士论文的神操作20170322
- (Q 2)netstat命令 检测TCP/IP 网络链接是否存在异常
- 第15课:卷积神经网络(CNN)