Android系统源码学习-SIM卡(三) Android 4.2中与SIM/USIM 管理流程

原文:http://blog.csdn.net/guoleimail/article/details/8738041


 Android在经过几次更新后,在与卡相关的管理出现的重大的改变。谨以些文,给自己做下学习该块的笔记。既然作为开源的,我们第一步当然是从代码入手,分析该处的关系。

Uicc的架构图如下:

从图中可以看出,UiccController是用来控制所有与卡相关的操作,通过UiccController,我们可以访问IccRecords(SIM卡相关), CatService(STK相关),IccFileHandle(读取SIM卡文件)。

与前面几个版相比,变化最大的就是IccCard.java这个文件,在4.2以前的版本中,该IccCard是一个类,而在4.2中,它却是一个接口,代码如下:

[html]  view plain
  1. public interface IccCard   
所以就不会存在以前版本中的SimCard, UsimCard, 现在统一用IccCardProxy来替代他们所有功能。

下面我将会展现卡相关的怎么样初始化的,UiccController是被PhoneFacotry中的makeDefaultPhone去初始化的,代码如下:

[html]  view plain
  1. sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);  
  2.   
  3. // Instantiate UiccController so that all other classes can just call getInstance()  
  4. UiccController.make(context, sCommandsInterface);  
  5.   
  6. int phoneType = TelephonyManager.getPhoneType(networkMode);  
  7. if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {  
  8.     Log.i(LOG_TAG, "Creating GSMPhone");  
  9.     sProxyPhone = new PhoneProxy(new GSMPhone(context,  
  10.             sCommandsInterface, sPhoneNotifier));  

可以看到,第一步先实例化RIL,我们会得到一个RIL的实例,然后,把这个实例调用UiccControl的make函数。这个函数会实例UiccController中一个成员变量,其它使用时,直接使用getInstance方向即可, 从这个地方可以看,它是个单例的模式,只用创建一次。代码如下:

[java]  view plain
  1.     public static UiccController make(Context c, CommandsInterface ci) {  
  2.         synchronized (mLock) {  
  3.             if (mInstance != null) {  
  4.                 throw new RuntimeException("UiccController.make() should only be called once");  
  5.             }  
  6.             mInstance = new UiccController(c, ci);  
  7.             return mInstance;  
  8.         }  
  9.     }  
  10.     public static UiccController getInstance() {  
  11.         synchronized (mLock) {  
  12.             if (mInstance == null) {  
  13.                 throw new RuntimeException(  
  14.                         "UiccController.getInstance can't be called before make()");  
  15.             }  
  16.             return mInstance;  
  17.         }  
  18.     }  
  19.     private UiccController(Context c, CommandsInterface ci) {  
  20.         if (DBG) log("Creating UiccController");  
  21.         mContext = c;  
  22.         mCi = ci;  
  23.         mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);  
  24.         // TODO remove this once modem correctly notifies the unsols  
  25.         mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);  
  26.     }  

2. 在UiccController初始化完成后,从它的构造函数中,我们可以看到该类还注册了一个监控事件,分别为EVENT_ICC_STATUS_CHANGED,该事件是用来监控SIM卡的状态有变化的,由上层主动给FRAMEWORK上报消息。当接收到这个消息后,UiccController会通过RIL给MODEM发送消息,查询下SIM卡的状态。

[java]  view plain
  1.     public void handleMessage (Message msg) {  
  2.         synchronized (mLock) {  
  3.             switch (msg.what) {  
  4.                 case EVENT_ICC_STATUS_CHANGED:  
  5.                     if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");  
  6.                     mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));  
  7.                     break;  
  8.                 case EVENT_GET_ICC_STATUS_DONE:  
  9.                     if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");  
  10.                     AsyncResult ar = (AsyncResult)msg.obj;  
  11.                     onGetIccCardStatusDone(ar);  
  12.                     break;  
  13.                 default:  
  14.                     Log.e(LOG_TAG, " Unknown Event " + msg.what);  
  15.             }  
  16.         }  
  17.     }  
  18.   
  19.     private synchronized void onGetIccCardStatusDone(AsyncResult ar) {  
  20.         if (ar.exception != null) {  
  21.             Log.e(LOG_TAG,"Error getting ICC status. "  
  22.                     + "RIL_REQUEST_GET_ICC_STATUS should "  
  23.                     + "never return an error", ar.exception);  
  24.             return;  
  25.         }  
  26.   
  27.         IccCardStatus status = (IccCardStatus)ar.result;  
  28.   
  29.         if (mUiccCard == null) {  
  30.             //Create new card  
  31.             mUiccCard = new UiccCard(mContext, mCi, status);  
  32.         } else {  
  33.             //Update already existing card  
  34.             mUiccCard.update(mContext, mCi , status);  
  35.         }  
  36.   
  37.         if (DBG) log("Notifying IccChangedRegistrants");  
  38.         mIccChangedRegistrants.notifyRegistrants();  
  39.     }  
  40.   
  41.    

当发送查询请求,待到查询结果上来后,会初始化UiccController的成员变量mUiccCard,如果是mUiccCard是空,即还没有初始化过,就重新NEW一个UiccCard的实例。如果是实例化过的,就重新更新下UiccCard的信息。到这个时候时,就算有SIM卡了,需要向其它注册了 监控SIM卡状态的注册者通知。以便其它应用能做知道SIM卡已经好了。

3. 我们接下往下走,刚说到在初始化UiccCard的时候,会重新NEW一个实例,这个NEW的过程到底干了什么,请看下面的代码:

[java]  view plain
  1.     public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics) {  
  2.         if (DBG) log("Creating");  
  3.         mCardState = ics.mCardState;  
  4.         update(c, ci, ics);  
  5.     }  
  6.   
  7.     public void update(Context c, CommandsInterface ci, IccCardStatus ics) {  
  8.         synchronized (mLock) {  
  9.             if (mDestroyed) {  
  10.                 loge("Updated after destroyed! Fix me!");  
  11.                 return;  
  12.             }  
  13.             CardState oldState = mCardState;  
  14.             mCardState = ics.mCardState;  
  15.             mUniversalPinState = ics.mUniversalPinState;  
  16.             mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;  
  17.             mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;  
  18.             mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;  
  19.             mContext = c;  
  20.             mCi = ci;  
  21.             //update applications  
  22.             if (DBG) log(ics.mApplications.length + " applications");  
  23.             for ( int i = 0; i < mUiccApplications.length; i++) {  
  24.                 if (mUiccApplications[i] == null) {  
  25.                     //Create newly added Applications  
  26.                     if (i < ics.mApplications.length) {  
  27.                         mUiccApplications[i] = new UiccCardApplication(this,  
  28.                                 ics.mApplications[i], mContext, mCi);  
  29.                     }  
  30.                 } else if (i >= ics.mApplications.length) {  
  31.                     //Delete removed applications  
  32.                     mUiccApplications[i].dispose();  
  33.                     mUiccApplications[i] = null;  
  34.                 } else {  
  35.                     //Update the rest  
  36.                     mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);  
  37.                 }  
  38.             }  
  39.   
  40.             if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {  
  41.                 // Initialize or Reinitialize CatService  
  42.                 mCatService = CatService.getInstance(mCi,  
  43.                                                      mContext,  
  44.                                                      this);  
  45.             } else {  
  46.                 if (mCatService != null) {  
  47.                     mCatService.dispose();  
  48.                 }  
  49.                 mCatService = null;  
  50.             }  
  51.   
  52.             sanitizeApplicationIndexes();  
  53.   
  54.             RadioState radioState = mCi.getRadioState();  
  55.             if (DBG) log("update: radioState=" + radioState + " mLastRadioState="  
  56.                     + mLastRadioState);  
  57.             // No notifications while radio is off or we just powering up  
  58.             if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {  
  59.                 if (oldState != CardState.CARDSTATE_ABSENT &&  
  60.                         mCardState == CardState.CARDSTATE_ABSENT) {  
  61.                     if (DBG) log("update: notify card removed");  
  62.                     mAbsentRegistrants.notifyRegistrants();  
  63.                     mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));  
  64.                 } else if (oldState == CardState.CARDSTATE_ABSENT &&  
  65.                         mCardState != CardState.CARDSTATE_ABSENT) {  
  66.                     if (DBG) log("update: notify card added");  
  67.                     mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));  
  68.                 }  
  69.             }  
  70.             mLastRadioState = radioState;  
  71.         }  
  72.     }  
从上面的代码看,最终都是调用update方法来更新状态。这个update的方法做了以下工作:

第一:更新SIM卡的信息,第二,判断下当前状态转换是怎么样, 即更新mUiccApplications的数组信息。第三,更新STK的SERVICE,这个看过我的前面STK讲解的童鞋,看到这个应该会很熟悉,对这个正是给STK提供服务的SERVICE,从这里可以看到,STK初始化跟以前不一样,这样的话,STK服务启动的较慢,这个时候,和STK上层的一个STK SERVICE RUNNING这个是配合,只有CAT SERVICE向下面报告了CAT SERVICE好了,下面才可以向上报STK的相关命令。第四,通过状态判断,向外面发送CARD REMOVE还是CARDADD消息。

4. 细心点的童鞋有可能会注意到,我在开始的提到的IccCard这个东东怎么没有看到呢,其它,他是在Phone创建后,用phoneproxy来替换phone(包括GSMPHONE,CDMAPHONE等等),这样做的好处是为了屏蔽这些PHONE之间的差异点。对外来说,都是一样的接口。好,既然这样的话,我要去看看phoneproxy怎么初始化的。代码如下:

[java]  view plain
  1. // Instantiate UiccController so that all other classes can just call getInstance()  
  2. UiccController.make(context, sCommandsInterface);  
  3.   
  4. int phoneType = TelephonyManager.getPhoneType(networkMode);  
  5. if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {  
  6.     Log.i(LOG_TAG, "Creating GSMPhone");  
  7.     sProxyPhone = new PhoneProxy(new GSMPhone(context,  
  8.             sCommandsInterface, sPhoneNotifier));  
  9. else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {  
  10.     switch (TelephonyManager.getLteOnCdmaModeStatic()) {  
  11.         case PhoneConstants.LTE_ON_CDMA_TRUE:  
  12.             Log.i(LOG_TAG, "Creating CDMALTEPhone");  
  13.             sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,  
  14.                 sCommandsInterface, sPhoneNotifier));  
  15.             break;  
  16.         case PhoneConstants.LTE_ON_CDMA_FALSE:  
  17.         default:  
  18.             Log.i(LOG_TAG, "Creating CDMAPhone");  
  19.             sProxyPhone = new PhoneProxy(new CDMAPhone(context,  
  20.                     sCommandsInterface, sPhoneNotifier));  
  21.             break;  
  22.     }  
  23. }  
在上面这段代码,请大家注意NEW  PHONEPROXY的时候,会根据PHONE的类型创建不同的PHONE,但然后再用PHONEPROXY把所有PHONE之间的区别不一样的给屏蔽掉,以便对外面的接口来说,都是一致的。PHONEPROXY的初始化,如下:

[java]  view plain
  1. public PhoneProxy(PhoneBase phone) {  
  2.     mActivePhone = phone;  
  3.     mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(  
  4.             TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);  
  5.     mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy(  
  6.             phone.getIccSmsInterfaceManager());  
  7.     mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(  
  8.             phone.getIccPhoneBookInterfaceManager());  
  9.     mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo());  
  10.     mCommandsInterface = ((PhoneBase)mActivePhone).mCM;  
  11.   
  12.     mCommandsInterface.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);  
  13.     mCommandsInterface.registerForOn(this, EVENT_RADIO_ON, null);  
  14.     mCommandsInterface.registerForVoiceRadioTechChanged(  
  15.                          this, EVENT_VOICE_RADIO_TECH_CHANGED, null);  
  16.     mIccCardProxy = new IccCardProxy(phone.getContext(), mCommandsInterface);  
  17.     if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {  
  18.         // For the purpose of IccCardProxy we only care about the technology family  
  19.         mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);  
  20.     } else if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {  
  21.         mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);  
  22.     }  
  23. }  
至于细节东东,只有去看代码了,在创建GSMPHONE的时候做了好多的事。需要自己去体会。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值