Android Telephony 分析【全】

11年下半年一直在做RIL的移植,主要解决第三方库的一些bug,使之能更好的工作在公司的PAD上。但是后来发现远远不够,有好多问题出现在Framework层。比方说我们想让PAD支持热插拔,尽管底层做好了,但上层还会出现很多问题,如PIN/PUK解锁功能,用户把解锁PIN/PUK的界面打开但把卡拔掉了,此时无法解锁的,系统如何响应此时情况,怎么做,这都是需要了解Telephony Framework之后知道如何实现的。

于是研究了一番Telephony的Java框架,刚开始接触时感觉挺复杂很混乱,现在理清了关系,所以希望能帮到那些还在纠结中的同志。

大致网络连接分析Android Telephony Framework层,关于ril及其移植的文章有很多所以就不赘述了。

以下部分内容引自前段时期我关于Telephony的总结做的PPT,参考了不少前辈的文章,用英文写的,懒得再译回来了,凑合着看吧(当时为了翻译成英文还煞费苦心- -!),需要PPT原件可以在此 http://wenku.baidu.com/view/bfe5361afad6195f312ba61c.html 下载,重要的和难理解的地方会做些解释,文章较长,一篇日志不让保存所以共分为四部分。

先来个整体结构图,有个大致印象,看完本文回头再看应该会有更深的理解。

 Android Telephony 分析【全】_第1张图片

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.

Android Telephony 分析【全】_第2张图片
 

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 getPreferredNetworkTypeMessage 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

Android Telephony 分析【全】_第3张图片

Android Telephony 分析【全】_第4张图片

 
Android Telephony 分析【全】_第5张图片
想说说为何网络需要状态机管理,DcDefaultState下面所有状态状态,子状态无法处理的EVENT都由他来处理,这是状态 机机制,大前提。

图中初始状态红色部分,状态切换时候,事件均由处理,无法处理交给父状态处理,一个EVENT_CONNECT事件时候,状态切换到DcActivingState,此时若有事件发给状态此状态处理,无法处理交给父状态处理,网络连接成功(SetupResult==SUCCESS)切换到绿色表示状态,绿色分DcActiveState表示网络连接成功了,比如此状态来个EVENT_CONNECT事件(此事件网络断开状态发起网络连接)不会自己处理因为此时网络已经连接成功了,连,状态只会处理EVENT_DISCONNECT事件),事件交由父状态DcDefaultState处理。

通过此机制,可以让网络状态得到稳定有序管理。

展示了如何发起一个网络连接 (最后为连接成功状态)
Android Telephony 分析【全】_第6张图片
 
下图以HUAWEI-RIL 2.3为例,展示第三方如何网络请求响应的(ril的机制要有基本了解)
Android Telephony 分析【全】_第7张图片
 


感觉Telephony有点复杂,事件多,Telephony不仅包括Call,MMS,SIM card,网络连接管理包括运营商,电话薄,解锁功能一块,感觉非常庞大 ,其实事件虽多,框架基本类似,也就是触类旁通,掌握一个,自然能够顺藤摸瓜,解决其他问题。
上面的图根据ANDROID ICS的源码画的,华为模块的RIL_VERSION 2.3。


下面内容就是通知机制了,网络状态变化为例,status bar信号一会2一会满格,其原理怎么实现



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.


Android Telephony 分析【全】_第8张图片

 这个详细一下,这个演示第三方用,Phone Service及Telephony关系。

第一条主线,TelephonyManager上半部分PhoneApp一个非常特殊app,通过调用PhoneFactory'创建一个Telephony(Internal),同时第三方application暴露接口,通过TelephonyManager调用,TelephonyManager通过ITelephonyandroid的AIDL机制)获得PhoneInterfaceManager远程对象然后第三方application通过这个远程对象调用service方法这里调用两个独立进程之间进行如果不清楚aidl可以3rd application直接调用了PhoneInterfaceManager方法,实际上需要通过TelephonyManager才能调用


第二条主线,TelephonyManager右半部分,TelephonyRegistry,顾名思义,什么东西注册,这种注册一般都是为了实现回调功能这个类主要作用就是第三方Appnew的PhoneStateListener需要监听动作通过调用TelephonyManager注册到TelephonyRegistry,底层状态变化通知GSMPhone时,GSMPhone的DefaultPhoneNotifier通知TelephonyRegistry,然后注册到TelephonyRegistry的PhoneStateListener监听事件会被触发(此时TelephonyRegistry还会发个boardCast),然后回调上层APP复写方法。

(要理清关系的最好办法就是结合图阅读源码,那样会有更深的理解)

如果上面机制看不懂也没关系,作为SDK开发只要知道以下部分行,


If we want to track telephony state in 3rd application:

 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.                                                                //needed

Take 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) {



你可能感兴趣的:(Android,Telephony)