Uicc之CatService
来源:互联网 发布:淘宝刷好评买家封号 编辑:程序博客网 时间:2024/04/25 04:49
CatService主要负责STK菜单的相关事宜,是Stk架构在Framework层的核心类。
作用:
1,解析自RIL上报的SIM卡中的数据然后以广播的形式上报给Stk app,方法为handleCommand()
2,上层Stk app持有CatService实例ie,通过调用其onCmdResponse()方法向RIL传递用户操作。
一、CatService的创建过程
在前面我们分析过,在UiccCard的更新过程中,会初始化CatService对象:
UiccCard.java public void update(Context c, CommandsInterface ci, IccCardStatus ics) { synchronized (mLock) { //[L51_porting] s: Angela if (mDestroyed) { loge("Updated after destroyed! Fix me!"); return; } //[L51_porting] e: Angela CardState oldState = mCardState; mCardState = ics.mCardState; mUniversalPinState = ics.mUniversalPinState; mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex; mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex; mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex; mContext = c; mCi = ci; .... createAndUpdateCatService(); } protected void createAndUpdateCatService() { // [JB_422_PORTING] s: Mavis if (mDestroyed) { loge("createAndUpdateCatService after destroyed! Fix me!"); return; } // [JB_422_PORTING] e: Mavis if (mUiccApplications.length > 0 && mUiccApplications[0] != null) { // Initialize or Reinitialize CatService if (mCatService == null) { //创建CatService mCatService = CatService.getInstance(mCi, mContext, this, mPhoneId); } else { ((CatService)mCatService).update(mCi, mContext, this); } } else { if (mCatService != null) { mCatService.dispose(); } mCatService = null; } }
那什么时候更新UiccCard啦?这的从Phone应用启动开始说起。
Phone应用开机启动进入PhoneGlobals.onCreate()创建Phone对象
public void onCreate() { if (VDBG) Log.v(LOG_TAG, "onCreate()..."); ContentResolver resolver = getContentResolver(); // Cache the "voice capable" flag. // This flag currently comes from a resource (which is // overrideable on a per-product basis): sVoiceCapable = getResources().getBoolean(com.android.internal.R.bool.config_voice_capable); // ...but this might eventually become a PackageManager "system // feature" instead, in which case we'd do something like: // sVoiceCapable = // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS); if (mCM == null) { // Initialize the telephony framework PhoneFactory.makeDefaultPhones(this); .... }
public static void makeDefaultPhone(Context context) { .... // Instantiate UiccController so that all other classes can just // call getInstance() sUiccController = UiccController.make(context, sCommandsInterfaces); .... }
这里就会去创建UiccController对象,该对象只有一个
public static UiccController make(Context c, CommandsInterface[] ci) { synchronized (mLock) { if (mInstance != null) { throw new RuntimeException("MSimUiccController.make() should only be called once"); } mInstance = new UiccController(c, ci); return (UiccController)mInstance; } }
private UiccController(Context c, CommandsInterface []ci) { if (DBG) log("Creating UiccController"); mContext = c; mCis = ci; for (int i = 0; i < mCis.length; i++) { Integer index = new Integer(i); mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index); // TODO remove this once modem correctly notifies the unsols // If the device has been decrypted or FBE is supported, read SIM when radio state is // available. // Else wait for radio to be on. This is needed for the scenario when SIM is locked -- // to avoid overlap of CryptKeeper and SIM unlock screen. if (DECRYPT_STATE.equals(SystemProperties.get("vold.decrypt")) || StorageManager.isFileEncryptedNativeOrEmulated()) { mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index); } else { mCis[i].registerForOn(this, EVENT_ICC_STATUS_CHANGED, index); } mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index); mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index); } mLauncher = new UiccStateChangedLauncher(c, this); }
可以看到在创建UiccController的时候根据index的不同分别想不同的RIL实例中注册的监听,这里主要就是mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
之后在RIL收到Modem主动上报的SIM状态改变的消息后就会一层层上报:
RIL.java private void processUnsolicited (Parcel p, int type) { int response; Object ret; response = p.readInt(); switch(response) { case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: if (RILJ_LOGD) unsljLog(response); if (mIccStatusChangedRegistrants != null) { mIccStatusChangedRegistrants.notifyRegistrants(); } break;}
mIccStatusChangedRegistrants.notifyRegistrants()这里就会通知前面注册的UiccController
public void handleMessage (Message msg) { synchronized (mLock) { Integer index = getCiIndex(msg); if (index < 0 || index >= mCis.length) { Rlog.e(LOG_TAG, "Invalid index : " + index + " received with event " + msg.what); return; } AsyncResult ar = (AsyncResult)msg.obj; switch (msg.what) { case EVENT_ICC_STATUS_CHANGED: if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus, index=" + index); mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index)); break; case EVENT_GET_ICC_STATUS_DONE: if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE, index=" + index); onGetIccCardStatusDone(ar, index); break; }
调用mCis[index].getIccCardStatus()去获得卡的状态在回到case EVENT_GET_ICC_STATUS_DONE:
private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) { if (ar.exception != null) { Rlog.e(LOG_TAG,"Error getting ICC status. " + "RIL_REQUEST_GET_ICC_STATUS should " + "never return an error", ar.exception); return; } if (!isValidCardIndex(index)) { Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index); return; } IccCardStatus status = (IccCardStatus)ar.result; if (mUiccCards[index] == null) { //Create new card // [L_50_PORTING] s: Mavis 20140923 // mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index); mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index, mPhone[index]); // [L_50_PORTING] e: Mavis 20140923 } else { //Update already existing card mUiccCards[index].update(mContext, mCis[index] , status); } if (DBG) log("Notifying IccChangedRegistrants"); mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); }
这里就回到了开头说的UiccCard.update()会去创建CatService。
其中,Phone,RIL,UiccCard,CatService的实例数量与SIM卡数量相同,一一对应。UiccController只有一个,里面管理一个UiccCard数组。
二、CatService的消息机制
先来看看CatService的构造方法
private CatService(CommandsInterface ci, UiccCardApplication ca, IccRecords ir, Context context, IccFileHandler fh, UiccCard ic, int slotId) { if (ci == null || ca == null || ir == null || context == null || fh == null || ic == null) { throw new NullPointerException( "Service: Input parameters must not be null"); } mCmdIf = ci; mContext = context; mSlotId = slotId; mHandlerThread = new HandlerThread("Cat Telephony service" + slotId); mHandlerThread.start(); // Get the RilMessagesDecoder for decoding the messages. mMsgDecoder = RilMessageDecoder.getInstance(this, fh, slotId); if (null == mMsgDecoder) { CatLog.d(this, "Null RilMessageDecoder instance"); return; } mMsgDecoder.start(); // Register ril events handling. mCmdIf.setOnCatSessionEnd(this, MSG_ID_SESSION_END, null); mCmdIf.setOnCatProactiveCmd(this, MSG_ID_PROACTIVE_COMMAND, null); mCmdIf.setOnCatEvent(this, MSG_ID_EVENT_NOTIFY, null); mCmdIf.setOnCatCallSetUp(this, MSG_ID_CALL_SETUP, null); //mCmdIf.setOnSimRefresh(this, MSG_ID_REFRESH, null); mCmdIf.registerForIccRefresh(this, MSG_ID_ICC_REFRESH, null); mCmdIf.setOnCatCcAlphaNotify(this, MSG_ID_ALPHA_NOTIFY, null); mIccRecords = ir; mUiccApplication = ca; // Register for SIM ready event. mIccRecords.registerForRecordsLoaded(this, MSG_ID_ICC_RECORDS_LOADED, null); CatLog.d(this, "registerForRecordsLoaded slotid=" + mSlotId + " instance:" + this); mUiccController = UiccController.getInstance(); mUiccController.registerForIccChanged(this, MSG_ID_ICC_CHANGED, null); // Check if STK application is available mStkAppInstalled = isStkAppInstalled(); // + HTC_PHONE registerHtcReceiver(true, mContext); // - HTC_PHONE CatLog.d(this, "Running CAT service on Slotid: " + mSlotId + ". STK app installed:" + mStkAppInstalled); }
我们看到在CatService的初始化过程中主要完成了一下三个任务:
1、获取RilMessageDecoder对象mMsgDecoder;
2、向RIL注册相关的通知监听;
3、向UiccCardApplication、IccRecords注册SIM卡和Record的监听;
在上面的CatService构造函数中我们看到,CatService注册了六个主要的监听器,有四个是比较重要的,按照接收的先后顺序分别是:
MSG_ID_ICC_CHANGED —-在7.0以后取代了
MSG_ID_SIM_READY,由RIL发出,通知CatService,SIM卡已经就绪,需要CatService反馈是否就绪
MSG_ID_PROACTIVE_COMMAND —-CatService拿到SIM卡中的STK信息
MSG_ID_RIL_MSG_DECODED —-RilMessageDecoder解析完STK数据后给CatService发送通知
MSG_ID_SESSION_END —-RIL上传当前消息已经传输完毕
2.2、 MSG_ID_ICC_CHANGED
@Override public void handleMessage(Message msg) { CatLog.d(this, "handleMessage[" + msg.what + "]"); switch (msg.what) { case MSG_ID_ICC_CHANGED: CatLog.d(this, "MSG_ID_ICC_CHANGED"); updateIccAvailability(); break; }}
void updateIccAvailability() { if (null == mUiccController) { return; } CardState newState = CardState.CARDSTATE_ABSENT; UiccCard newCard = mUiccController.getUiccCard(mSlotId); if (newCard != null) { newState = newCard.getCardState(); } CardState oldState = mCardState; mCardState = newState; CatLog.d(this,"New Card State = " + newState + " " + "Old Card State = " + oldState); if (oldState == CardState.CARDSTATE_PRESENT && newState != CardState.CARDSTATE_PRESENT) { broadcastCardStateAndIccRefreshResp(newState, null); } else if (oldState != CardState.CARDSTATE_PRESENT && newState == CardState.CARDSTATE_PRESENT) { // Card moved to PRESENT STATE. mCmdIf.reportStkServiceIsRunning(null); } }
在这里会判断当前SIM卡的状态,如果SIM卡不是PRESENT就会发出广播broadcastCardStateAndIccRefreshResp(newState, null),如果是PRESENT就调用 mCmdIf.reportStkServiceIsRunning(null),RIL将会向Modem发送RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING的消息,从而告诉Modem,CatService已经准备好接受STK的数据了。
2.2、MSG_ID_PROACTIVE_COMMAND
Modem接收到CatService已经启动的消息后,就会上报MSG_ID_PROACTIVE_COMMAND的消息,该消息中包含了SIM卡中存储的STK信息,此时CatService需要将这些信息解析并保存,用于构建STK菜单。
public void handleMessage(Message msg) { switch (msg.what) { case MSG_ID_SESSION_END: case MSG_ID_PROACTIVE_COMMAND: case MSG_ID_EVENT_NOTIFY: case MSG_ID_REFRESH: String data = null; if (msg.obj != null) { AsyncResult ar = (AsyncResult) msg.obj; if (ar != null && ar.result != null) { try { data = (String) ar.result; } catch (ClassCastException e) { break; } } } //通过RilMessageDecoder去解析数据 mMsgDecoder.sendStartDecodingMessageParams(new RilMessage(msg.what, data)); break; default: throw new AssertionError("Unrecognized CAT command: " + msg.what); } }
我们看到,对于拿到的数据时通过mMsgDecoder去解析的,也就是RilMessageDecoder的对象,这个对象是在CatService的构造函数中被创建的。
当数据解析完成后CatService中将会收到MSG_ID_RIL_MSG_DECODED的消息。
2.3、MSG_ID_RIL_MSG_DECODED
这个消息并不是从Ril上传上来的,而是在6.2.1中,对MSG_ID_PROACTIVE_COMMAND消息处理之后,由RilMessageDecoder发送过来的,它标志着刚才从Modem接收到的数据已经被解析完毕。而这个消息要做的任务就是将解析后的数据传递给RIL和StkAppService.java。
@CatService.java public void handleMessage(Message msg) { switch (msg.what) { case MSG_ID_RIL_MSG_DECODED: handleRilMsg((RilMessage) msg.obj); break; default: throw new AssertionError("Unrecognized CAT command: " + msg.what); } }
接着往下看:
private void handleRilMsg(RilMessage rilMsg) { CommandParams cmdParams = null; switch (rilMsg.mId) { case MSG_ID_PROACTIVE_COMMAND: try { //拿到解析后的数据 cmdParams = (CommandParams) rilMsg.mData; } catch (ClassCastException e) { } if (cmdParams != null) { if (rilMsg.mResCode == ResultCode.OK) { //处理当前的数据 handleCommand(cmdParams, true); } else { sendTerminalResponse(cmdParams.mCmdDet, rilMsg.mResCode, false, 0, null); } } break; } }
private void handleCommand(CommandParams cmdParams, boolean isProactiveCmd) { CharSequence message; CatCmdMessage cmdMsg = new CatCmdMessage(cmdParams); switch (cmdParams.getCommandType()) { case SET_UP_MENU: if (removeMenu(cmdMsg.getMenu())) { mMenuCmd = null; } else { mMenuCmd = cmdMsg; } sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, null); break; case DISPLAY_TEXT: if (!cmdMsg.geTextMessage().responseNeeded) { sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, null); } break; case SELECT_ITEM: case GET_INPUT: case GET_INKEY: break; case SEND_DTMF: case SEND_SMS: case SEND_SS: case SEND_USSD: if ((((DisplayTextParams)cmdParams).mTextMsg.text != null) && (((DisplayTextParams)cmdParams).mTextMsg.text.equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string.sending); ((DisplayTextParams)cmdParams).mTextMsg.text = message.toString(); } break; case PLAY_TONE: break; case SET_UP_CALL: if ((((CallSetupParams) cmdParams).mConfirmMsg.text != null) && (((CallSetupParams) cmdParams).mConfirmMsg.text.equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string.SetupCallDefault); ((CallSetupParams) cmdParams).mConfirmMsg.text = message.toString(); } break; default: CatLog.d(this, "Unsupported command"); return; } mCurrntCmd = cmdMsg; Intent intent = new Intent(AppInterface.CAT_CMD_ACTION); intent.putExtra("STK CMD", cmdMsg); mContext.sendBroadcast(intent);
我们看到,在handleCommand()中,对于主要的几种数据类型,比如SET_UP_MENU、DISPLAY_TEXT的最后都有sendTerminalResponse()的操作,而这个操作的作用就是将数据封装后发送给RIL。并且在handleCommand()的最后,通过广播mContext.sendBroadcast(intent);的形式将当前解析的结果发送出来,发送之后就有STK应用的StkAppService.java负责接收,并构建STK菜单。
2.4、MSG_ID_SESSION_END
这个消息主要是RIL用于告诉CatService,当前的会话已经传输完毕,和MSG_ID_PROACTIVE_COMMAND的消息流程类似,只是更加的简单,略。
至此,CatService的主要作用分析完毕!
- Uicc之CatService
- Uicc之CatService
- Uicc之CatService
- Uicc之CatService(原)
- UICC之UICC框架
- Uicc之UiccCardApplication(转)
- Android之Uicc框架
- Uicc之UiccController
- Uicc之UiccCard
- Uicc之UiccCardApplication
- Uicc之IccFileHandler
- Uicc之IccRecords
- UICC之UiccController
- UICC之UiccCard
- UICC之UiccCardApplication
- UICC之UsimFileHandler
- Uicc之IccRecords
- UICC
- LaTeX快速指南(一)安装LaTeX
- 基于HTML5 Canvas 实现地铁站监控
- poj 3087 Shuffle'm Up
- Visual Studio 2017 无法连接Linux服务端问题
- 高级指针
- Uicc之CatService
- iOS仿支付宝车牌号码输入键盘
- virtualenv教程
- hdu 4911 Inversion
- HDFS基于路由的Federation方案
- 分解质因数-java
- hdu 4907 Task schedule
- 【Machine Learning】模型融合之Stacking
- 免费开放接口API