日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android Telephony分析(七) ---- 接口扩展(异步转同步)

發布時間:2025/3/15 Android 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android Telephony分析(七) ---- 接口扩展(异步转同步) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文是基于上一篇《Android Telephony分析(六) —- 接口擴展(實踐篇)》來寫的。?
上一篇介紹的接口擴展的方法需要實現兩部分代碼:?
1. 從APP至RIL,發送請求;?
2. 從RIL至APP,上報結果。

APPAPPTelephonyManagerTelephonyManagerPhonePhoneRILRIL發送Requestmodem處理返回結果返回結果

由于這是一個異步請求,所以兩部分流程都不能少,導致流程過于復雜。?
而本文的目的就是為了將異步請求轉換成同步請求,節省第二部分“上報結果”的流程,從而簡化整個接口擴展的流程和代碼量。(當然,雖然《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分析(七) ---- 接口扩展(异步转同步)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。