Android Telephony 分析【全】
11年下半年一直在做RIL的移植,主要解決第三方庫的一些bug,使之能更好的工作在公司的PAD上。但是后來發(fā)現(xiàn)遠(yuǎn)遠(yuǎn)不夠,有好多問題出現(xiàn)在Framework層。比方說我們想讓PAD支持熱插拔,盡管底層做好了,但上層還會出現(xiàn)很多問題,如PIN/PUK解鎖功能,用戶把解鎖PIN/PUK的界面打開但同時(shí)他把卡拔掉了,此時(shí)是無法解鎖的,系統(tǒng)該如何響應(yīng)此時(shí)的情況,我們該怎么做,這都是需要了解Telephony Framework之后才知道如何實(shí)現(xiàn)的。
于是研究了一番Telephony的Java框架,剛開始接觸時(shí)感覺挺復(fù)雜很混亂,現(xiàn)在理清了關(guān)系,所以希望能幫到那些還在糾結(jié)中的同志。
我想大致以網(wǎng)絡(luò)連接為例分析Android Telephony Framework層,關(guān)于ril及其移植的文章有很多所以就不贅述了。
以下部分內(nèi)容引自前段時(shí)期我關(guān)于Telephony的總結(jié)做的PPT,參考了不少前輩的文章,用英文寫的,懶得再譯回來了,湊合著看吧(當(dāng)時(shí)為了翻譯成英文還煞費(fèi)苦心- -!),需要PPT原件可以在此?http://wenku.baidu.com/view/bfe5361afad6195f312ba61c.html?下載,重要的和難理解的地方會做些解釋,文章較長,一篇日志不讓保存所以共分為四部分。
先來個(gè)整體結(jié)構(gòu)圖,有個(gè)大致印象,看完本文回頭再看應(yīng)該會有更深的理解。
?1.Telephony Framework
Telephony framework contains a set of telephony API for applications. There are two?categaries?of JAVA?pacakges?in telephony framework:
1.The internal telephony packages -??
??com.android.internal.telephony.*,
???source code:?frameworks/base/telephony/java/com/android/internal/telephony
2.The open telephony packages -
??android.telephony.*.
???source code:?frameworks/base/telephony/java/android/telephony
The internal packages are used for Android default telephony application -?Phone.apk, and the open packages are for any 3rd?party telephony applications.
?
Internal Telephony Packages:
frameworks/base/telephony/java/com/android/internal/telephony
The public interface?Phone?is used to control the phone. The abstract class?PhoneBase?implements this interface. And the class?GSMPhone?extends this abstract class.
Phone.java
44 public interface Phone{ 326 String getPhoneName(); 332 int getPhoneType(); 1118 void setPreferredNetworkType(int networkType, Message response); 1125 void getPreferredNetworkType(Message response); ...
The default telephony application could use?makeDefaultPhones()?and?getDefaultPhone()?in the class?PhoneFactory?to obtain the unique instance of Phone. The code below shows how this be done.
packages/apps/Phone/src/com/android/phone/PhoneApp.java
410???? public void onCreate() { ? ? ? ? ?? ... 425???????? if (phone == null) { 426???????????? // Initialize the telephonyframework 427???????????? PhoneFactory.makeDefaultPhones(this); 428 429???????????? // Get the default phone 430???????????? phone = PhoneFactory.getDefaultPhone();
PhoneFactory.java
56 public static void makeDefaultPhone(Context context) { ... 130 sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); 132 int phoneType = getPhoneType(networkMode); if (phoneType == Phone.PHONE_TYPE_GSM) { 135 sProxyPhone = new PhoneProxy(new GSMPhone(context, sCommandsInterface, sPhoneNotifier)); 137 } else if (phoneType == Phone.PHONE_TYPE_CDMA) {
Let’s suppose the current network mode is in GSM/GPRS, so the default telephony application could obtain a?PhoneProxy?to a?GSMPhone, and use its API to achieve telephony functionalities.ProxyPhone?is also extended from?Phone. It is used to abstract the specific instance of a specific network mode.
PhoneProxy.java
?57?????public PhoneProxy(Phone phone) {
?58?????????mActivePhone = phone;
????????????...
?66?????????mCommandsInterface = ((PhoneBase)mActivePhone).mCM;
?67?????????mCommandsInterface.registerForRadioTechnologyChanged(
?68?????????????????this, EVENT_RADIO_TECHNOLOGY_CHANGED, null);
?69?????}?
????????...
549?????public void getPreferredNetworkType(Message response) {
550?????????mActivePhone.getPreferredNetworkType(response);
551?????}????????
The class?PhoneBase?has a member?mCM?of the type?CommandsInterface. And this is assigned in the constructor of?GSMPhone.
GSMPhone.java
130?????GSMPhone (Context context,?CommandsInterface ci, PhoneNotifier notifier,
???????????????????????????????boolean unitTestMode) {
131?????????super(notifier, context,?ci, unitTestMode);
????????????...
PhoneBase.java
114?????public CommandsInterface mCM;
????????...
203?????protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,
204?????????????boolean unitTestMode) {
207?????????mLooper = Looper.myLooper();
208?????????mCM = ci;????????...
757?????public void getPreferredNetworkType(Message response) {
758?????????mCM.getPreferredNetworkType(response);
759?????}
All the telephony functionalities which need sending AT command to RIL daemon should be achieved by the?the?interface?CommandsInterface. And the class?RIL?implements this interface.??Moreover,?RILalso extends the abstract class?BaseCommands?to provide unsolicited result code to default telephony application.
CommandsInterface.java
27?????public interface CommandsInterface {
1332?????void getPreferredNetworkType(Message response);
BaseCommands.java
36 public abstract class BaseCommands implements CommandsInterface {??????
RIL.java
199 public final class RIL extends BaseCommands implements CommandsInterface {
1861?????public void getPreferredNetworkType(Message response)?{
1862?????????RILRequest rr = RILRequest.obtain(
1863?????????????????RILConstants.RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, response);
1867?????????send(rr); //call sender and send to target
我想說說為何網(wǎng)絡(luò)需要用狀態(tài)機(jī)來管理,DcDefaultState是下面所有狀態(tài)的父狀態(tài),子狀態(tài)無法處理的EVENT都由他來處理,這是狀態(tài) 機(jī)的機(jī)制,是大前提。
圖中初始狀態(tài)為紅色部分,在狀態(tài)未切換的時(shí)候,事件均由它來處理,無法處理的交給父狀態(tài)處理,當(dāng)來一個(gè)EVENT_CONNECT的事件的時(shí)候,狀態(tài)切換到DcActivingState,此時(shí)若有事件發(fā)給狀態(tài)機(jī),均在此狀態(tài)下處理,無法處理的交給父狀態(tài)處理,當(dāng)網(wǎng)絡(luò)連接成功(SetupResult==SUCCESS),切換到綠色表示的狀態(tài),綠色部分DcActiveState是表示網(wǎng)絡(luò)連接成功了,比如在此狀態(tài)下來個(gè)EVENT_CONNECT事件(此事件在網(wǎng)絡(luò)斷開的狀態(tài)下會發(fā)起網(wǎng)絡(luò)連接)它不會自己處理(因?yàn)?/span>此時(shí)網(wǎng)絡(luò)已經(jīng)連接成功了,無需再連,此狀態(tài)下只會處理EVENT_DISCONNECT事件),而把該事件交由父狀態(tài)DcDefaultState來處理。
通過此機(jī)制,可以讓網(wǎng)絡(luò)狀態(tài)得到穩(wěn)定有序的管理。
下圖展示了如何發(fā)起一個(gè)網(wǎng)絡(luò)連接 (最后為連接成功狀態(tài))?
下圖以HUAWEI-RIL 2.3為例,展示了第三方庫是如何對網(wǎng)絡(luò)請求響應(yīng)的(ril的機(jī)制要有基本了解)
?
感覺Telephony有點(diǎn)復(fù)雜,事件多,Telephony不僅包括對Call,MMS,SIM?card,網(wǎng)絡(luò)連接等的管理,還包括運(yùn)營商,電話薄,解鎖等功能揉在一塊,感覺非常龐大?,其實(shí)事件雖多,但框架都基本類似,也就是觸類旁通,掌握一個(gè),自然能夠順藤摸瓜,解決其他的問題。 上面的圖根據(jù)ANDROID ICS的源碼畫的,華為模塊的RIL_VERSION 2.3。
下面的內(nèi)容就是通知機(jī)制了,以網(wǎng)絡(luò)狀態(tài)變化為例,status?bar上信號一會2格一會滿格,其原理是怎么實(shí)現(xiàn)的呢
Telephony framework needs to track the network return value and events???happened in RIL daemon. At the same time, default telephony application should also be able to be notified by telephony framework.
In the constructor of?GSMPhone, a?GsmServiceStateTracker?would be created to track the network status. And in the?contructor?of?GsmServiceStateTracker, it would register to?RIL?for network status message.?
gsm/GSMPhone.java
101?????GsmServiceStateTracker mSST;
130?????public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier,
??????????????????boolean unitTestMode) {
????????????...
139?????????mSST = new GsmServiceStateTracker (this);
gsm/GsmServiceStateTracker.java
186?????public GsmServiceStateTracker(GSMPhone phone) {
189????????this.phone = phone;
190????????cm = phone.mCM;
204????????cm.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
It registers into a registrant list of?BaseCommands.
BaseCommands.java
58??????protected RegistrantList mVoiceNetworkStateRegistrants = new RegistrantList();
????????...
324?????public void registerForVoiceNetworkStateChanged(Handler h, int what, Object obj) {
325?????????Registrant r =?new Registrant (h, what, obj);
327?????????mVoiceNetworkStateRegistrants.add(r);
328?????}
When network state changes, the endless loop waiting for the message in telephony framework will be notified by RIL daemon. And the message is?deliverred?to registrant.
RIL.java
2395?????private void
2396?????processUnsolicited (Parcel p) {
?????????????????...
2467?????????????case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED:
2468?????????????????if (RILJ_LOGD) unsljLog(response);
2469
2470?????????????????mVoiceNetworkStateRegistrants
2471?????????????????????.notifyRegistrants(new?AsyncResult(null, null, null));
GsmServiceStateTracker?is a subclass of Handler.
When RILJ call?notifyRegistrants(), the?registed?handler?obj?will call?sendMessage(msg), thenhandleMessage() will be call.
gsm/GsmServiceStateTracker.java
260?????public void handleMessage (Message msg) {
261?????????AsyncResult ar;
262?????????int[] ints;
263?????????String[] strings;
264?????????Message message;
265
266?????????switch (msg.what) {
????????????????...
304?????????????case?EVENT_NETWORK_STATE_CHANGED:
305?????????????????pollState();
306?????????????????break;
Open telephony packages:
frameworks/base/telephony/java/android/telephony
??????
TelephonyManager?provides a way for 3rd application??interacting with internal telephony packages.
Class Overview (from android?sdk?document)
Provides access to information about the telephony services on the device. Applications can use the methods in this class to determine telephony services and states, as well as to access some types of subscriber information. Applications can also register a listener to receive notification of telephony state changes.
You do not instantiate this class directly; instead, you retrieve a reference to an instance throughContext.getSystemService(Context.TELEPHONY_SERVICE).
Note that access to some telephony information is?permission-protected. Your application cannot access the protected information unless it has the appropriate permissions declared in its manifest file. Where permissions apply, they are noted in the?the?methods through which you access the protected information.
?這個(gè)圖我想詳細(xì)的說一下,這個(gè)圖演示了第三方應(yīng)用,Phone Service及Telephony的關(guān)系。
第一條主線,以TelephonyManager為軸的上半部分,PhoneApp是一個(gè)非常特殊的app,由它通過調(diào)用PhoneFactory'創(chuàng)建一個(gè)Telephony(Internal),同時(shí)給第三方application暴露接口,供其通過TelephonyManager調(diào)用,TelephonyManager通過ITelephony(android的AIDL機(jī)制)獲得PhoneInterfaceManager的遠(yuǎn)程對象,然后第三方application通過這個(gè)遠(yuǎn)程對象來調(diào)用service里的方法,這里的調(diào)用是兩個(gè)獨(dú)立進(jìn)程之間進(jìn)行的(如果不清楚aidl,可以假想為3rd?application直接調(diào)用了PhoneInterfaceManager里的方法,但實(shí)際上是需要通過TelephonyManager才能調(diào)用的)
第二條主線,以TelephonyManager為軸的右半部分,TelephonyRegistry,顧名思義,是什么東西的注冊,這種注冊的一般都是為了實(shí)現(xiàn)回調(diào)功能,這個(gè)類的主要作用就是把第三方App里new的PhoneStateListener和需要監(jiān)聽的動作通過調(diào)用TelephonyManager注冊到TelephonyRegistry,當(dāng)底層狀態(tài)變化通知GSMPhone時(shí),GSMPhone里的DefaultPhoneNotifier會通知TelephonyRegistry,然后注冊到TelephonyRegistry的PhoneStateListener監(jiān)聽的事件會被觸發(fā)(此時(shí)TelephonyRegistry還會發(fā)個(gè)boardCast),然后回調(diào)上層APP復(fù)寫的方法。
(要理清關(guān)系的最好辦法就是結(jié)合圖閱讀源碼,那樣會有更深的理解)
如果上面的機(jī)制看不懂也沒關(guān)系,作為SDK開發(fā)只要知道以下部分就行,
If we want to track telephony state in 3rd?application:
1??We should?retrive?an instance of?TelephonyManager?and get Phone service. ? ? ?//needed 2 ?Implement a?PhoneStateListener?what you want to listen. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //not needed 3 ?You can also register a?BroadCastReceiver?to receive broadcast if you want. ? ? ? //not needed 4 ?Don’t forget add permission in manifest file. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//neededTake Settings as example to show how to achieve these.
packages/apps/Settings/src/com/android/settings/deviceinfo/ Status.java
111?????private TelephonyManager mTelephonyManager;
???????
169?????private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
170?????????@Override
171?????????public void?onDataConnectionStateChanged(int state) {
???????????????UpdateDataState();??//you can override with your own code here
???????
178?????protected void onCreate(Bundle icicle) {????????????
184?????????mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
268?????protected void onResume() {
278?????????????mTelephonyManager.listen(mPhoneStateListener,
279???????????????????????PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
337?????private void updateDataState() {
338?????????int state = mTelephonyManager.getDataState();
341?????????switch (state) {
總結(jié)
以上是生活随笔為你收集整理的Android Telephony 分析【全】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Camrea测试-- CTS测试
- 下一篇: Android telephony整体结