STK工作流程简介

 

1. STK整体工作流程的结构图

从图中可以得到,查看方向,由MODEM向JAVA查看,MODEM会使用两种方式给RIL.JAVA上报数据,分别是Unsolicited and Terminalresponse Solicited(request/response) . 在RIL.JAVA中常用的有

solicited response

RIL_REQUEST_STK_GET_PROFILE    用来GET PROFILE

RIL_REQUEST_STK_SET_PROFILE   设置PROFILE

RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND  用于发送SELECT ITEM 等

RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE  发送STK TERMINAL RESPONSE 

RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM   能于从STK打CALL,通知JAVA界面,相关CALL的消息。

Unsolicited response

RIL_UNSOL_STK_SESSION_END     结束会话

RIL_UNSOL_STK_PROACTIVE_COMMAND   SETUP MENU 显示STK的主菜单

RIL_UNSOL_STK_EVENT_NOTIFY                 主要用于EVENTDOWNLOAD

RIL_UNSOL_STK_CALL_SETUP                     打CALL后的相关通知消息。

上图中的Baseband 一般由平台厂商进行开发,根据ANDROID的开源默认的机制,可以使用AT COMMAND 来操作MODEM,也有其它的厂商会进行自己的MODEM开发,来达到提高MODEM的速度和效率。

但对于RIL.java这个抽象层来说,不管采用哪种类型的MODEM,上层都是一样的,这样便于更好的移植.

 

2. 应用层与telephony层交互流程图

请求发到StkService.java(即CatService.java),它是telephony service,将二进制的流进行解析,得到对应的类的结构,并将请求发送给StkAppService.java.

大部分STK的协议是在MODEM这边实现的,比如TermianlProfile, USSD,SS,而在ANDROID上层,只对部分的协议进行了支持,主要是和用户有交互的操作,比如DISPLAYTEXT。

 (备注:上面1,2点内容,出自博客http://blog.csdn.net/guoleimail/article/details/6683458,借用来分析STK工作原理)

 

3. STK应用的启动

       应用目录:mediatek/packages/apps/Stk1/

       (1). 设备开机,STK应用的安装

文件路径:com.android.stk.BootCompleteReceiver

       //每次设备开机完成后,系统广播Intent.ACTION_BOOT_COMPLETED,STK应用接到广播进行STK启动,现以单卡情况下进行分析STK流程

                     public void onReceive(Context context,Intent intent) {

                       String action = intent.getAction();

                             //初始化应用安装者实例,应用服务实例

                      StkAppInstaller appInstaller =StkAppInstaller.getInstance();

                      StkAppService appService =StkAppService.getInstance();

       

                      //(a).开机完成广播.

                      if(action.equals(Intent.ACTION_BOOT_COMPLETED)) {

                                   ……

                                   //开启STK后台应用服务,用于UI和Telephony之间交互

                                   context.startService(newIntent(context, StkAppService.class).putExtras(args));

                                   ……

                                   //根据当前是单卡,或者是双卡,或者是多卡,进行STK应用的卸载

                                   ……

mHasBootComplete = true;

} else if(action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {

//(b).从基带芯片开始上电,然后SIM卡上电,再协议栈开启,再基带初始化完成,以致基带正常工作起来,这过程中伴随SIM STATE的改变

     ……

     //判断STK应用安装状态,若没安装,则进行安装

     int app_state =appInstaller.getIsInstalled(SIMID);

   if (app_state == -1)

   {

        appInstaller.install(context, SIMID);

             //如果基带工作非正常,以及处于飞行模式,则卸载STK应用

        if (checkSimRadioState(context, SIMID)!= true || true == isOnFlightMode(context))

        {

             /* The SIM card is off souninstall it */

             SystemClock.sleep(100);

             appInstaller.unInstall(context,SIMID);

        }                             

   }

     ……

     //检查SIM卡不同状态下,STK安装情况,然后进行正确安装

     ……

}                         

}

 

(2). 单击启动STK,到显示视图菜单

       文件路径:AndroidManifest.xml

       <activityandroid:name="StkLauncherActivity"

                android:excludeFromRecents="true"

                     android:label="@string/appI_name"

            android:theme="@android:style/Theme.NoDisplay"

                     android:enabled="false" 

                     android:taskAffinity="android.task.stk.StkLauncherActivity">

                     <intent-filter>

                            <actionandroid:name="android.intent.action.MAIN" />

                     </intent-filter>

       </activity>

文件路径:com.android.stk.StkLauncherActivity

protected void onCreate(Bundle savedInstanceState) {

        ……

              //操作类型为StkAppService.OP_LAUNCH_APP,并启动StkAppService进行启动处理

        Bundle args = newBundle();

        int[] op = new int[2];

        op[0] = StkAppService.OP_LAUNCH_APP;

        /* TODO: GEMINI+ */

        op[1] =PhoneConstants.GEMINI_SIM_1;

       args.putIntArray(StkAppService.OPCODE, op);

       args.putInt(StkAppService.CMD_SIM_ID, PhoneConstants.GEMINI_SIM_1);

        startService(newIntent(this, StkAppService.class).putExtras(args));

              finish();

}

       文件路径:com.android.stk.StkAppService

    public void onStart(Intentintent, int startId) {

              ……

              //对启动Service的Intent参数的检查,合法则继续往下进行

              ……

              //对Intent参数作判断,区分STK操作类型(操作:命令,下载,响应,启动app,结束会话,开机,拔出SIM卡),然后交给ServiceHandler进行处理

              Message msg =mServiceHandler.obtainMessage();

        msg.arg1 = op[0];

        msg.arg2 = sim_id;

        switch(msg.arg1) {

        case OP_CMD:

            msg.obj =args.getParcelable(CMD_MSG);

            break;

        caseOP_EVENT_DOWNLOAD:

            msg.obj = args;

            break;

        case OP_RESPONSE:

            msg.obj = args;

            /* falls through*/

        case OP_LAUNCH_APP:

        case OP_END_SESSION:

        caseOP_BOOT_COMPLETED:

        case OP_REMOVE_STM:

            break;

        default:

            return;

        }

       mServiceHandler.sendMessage(msg);

}

//服务处理Handler,对不同操作进行处理

                private finalclass ServiceHandler extends Handler {

             public voidhandleMessage(Message msg) {

                              switch(opcode) {

                            case OP_LAUNCH_APP:

                                  if(mStkContext[sim_id].mCurrentMenu ==mStkContext[sim_id].mMainCmd.getMenu() || mStkContext[sim_id].mCurrentMenu == null) {

                                                    //当前无菜单时,则加载STK根菜单

                                      launchMenuActivity(null, sim_id);

                                 } else {

                                                    //当前有菜单时,则加载其子菜单

                                     launchMenuActivity(mStkContext[sim_id].mCurrentMenu,sim_id);

                                 }

                                             //设置STK应用为可访问状态

                                 setUserAccessState(true, sim_id);

                                 break;

}

                        }

}

private void launchMenuActivity(Menu menu, int sim_id) {

    IntentnewIntent = new Intent(Intent.ACTION_VIEW);

                 String targetActivity =STK1_MENU_ACTIVITY_NAME;

                       ……

                       //其中STK1_MENU_ACTIVITY_NAME为StkMenuActivity

newIntent.setClassName(PACKAGE_NAME, targetActivity);

    ……

    mContext.startActivity(newIntent);

}

                     文件路径:com.android.stk.StkMenuActivity

                     //菜单视图的构建

                     publicvoid onCreate(Bundle icicle) {

                       ……

                     setContentView(R.layout.stk_menu_list);

                     mTitleTextView = (TextView)findViewById(R.id.title_text);

                     mTitleIconView =(ImageView) findViewById(R.id.title_icon);

                     mProgressView =(ProgressBar) findViewById(R.id.progress_bar);

                      ……

                  }

(3). 单击菜单视图中一项

文件路径:com.android.stk.StkMenuActivity

//单击事件的处理

                     protectedvoid onListItemClick(ListView l, View v, int position, long id) {

                     super.onListItemClick(l,v, position, id);

                     mMenuInstance.handleListItemClick(position,mProgressView);

                  }

                     文件路径:com.android.stk.StkMenuInstance

                     publicvoid handleListItemClick(int position, ProgressBar bar)

                   {

                            ……

                       sendResponse(StkAppService.RES_ID_MENU_SELECTION,item.id, false);

                            ……

                  }

                     //把单击菜单项信息封装,传给StkAppService处理

                     voidsendResponse(int resId, int itemId, boolean help) {

                      ……

                     Bundle args = newBundle();

                   int[]op = new int[2];

                     op[0] =StkAppService.OP_RESPONSE;

                     op[1] = mSimId;

                     args.putIntArray(StkAppService.OPCODE,op);

                     args.putInt(StkAppService.RES_ID,resId);

                     args.putInt(StkAppService.MENU_SELECTION,itemId);

                     args.putBoolean(StkAppService.HELP,help);

                     mContext.startService(newIntent(mContext, StkAppService.class).putExtras(args));

                  }

                     文件路径:com.android.stk.Stk.StkAppService

private final class ServiceHandler extends Handler {

             public voidhandleMessage(Message msg) {

                              switch(opcode) {

                                caseOP_RESPONSE:   

                              if (mStkContext[sim_id].responseNeeded) {

                                 handleCmdResponse((Bundle) msg.obj, sim_id);

                               }                           

                                     ……

}

                        }

}

//处理有响应的命令

private void handleCmdResponse(Bundle args, int sim_id) {

       ……

       CatResponseMessageresMsg = new CatResponseMessage(mStkContext[sim_id].mCurrentCmd);

       ……

switch(args.getInt(RES_ID)) {

        caseRES_ID_MENU_SELECTION:

            ……

            intmenuSelection = args.getInt(MENU_SELECTION);

           switch(mStkContext[sim_id].mCurrentMenuCmd.getCmdType()) {

            caseSET_UP_MENU:

               //have already handled setup menu

               mStkContext[sim_id].mSetUpMenuHandled = true;

            caseSELECT_ITEM:

               resMsg = new CatResponseMessage(mStkContext[sim_id].mCurrentMenuCmd);

                mStkContext[sim_id].lastSelectedItem= getItemName(menuSelection, sim_id);

                if(helpRequired) {

                   resMsg.setResultCode(ResultCode.HELP_INFO_REQUIRED);

                }else {

                   resMsg.setResultCode(ResultCode.OK);

                }

               resMsg.setMenuSelection(menuSelection);

               break;

            }

            break;

                     ……

}

    ……

       //调用Telephone层提供的接口,将响应命令交到Telephony层进行处理。

mStkService[sim_id].onCmdResponse(resMsg);

}

 

         4. Telephony层处理STK应用发来的请求

               文件路径:frameworks/opt/telephony/src/java/com/android/internal/telephony/cat/CatService.java

               CatService继承了Handler,实现了AppInterface接口,用来提供上层应用调用的接口方法

               public synchronized voidonCmdResponse(CatResponseMessage resMsg) {

               ……

              Messagemsg = this.obtainMessage(MSG_ID_RESPONSE, resMsg);

              msg.sendToTarget();

            }

               发送给自身消息处理中心

               public void handleMessage(Message msg) {

               ……

              switch (msg.what) {

                            ……

case MSG_ID_RESPONSE:

                    handleCmdResponse((CatResponseMessage)msg.obj);

                       break;

                            ……

}

}

处理响应命令

private voidhandleCmdResponse(CatResponseMessage resMsg) {

       ……

       switch (resMsg.resCode) {

            ……

            case OK:

            case PRFRMD_WITH_PARTIAL_COMPREHENSION:

            case PRFRMD_WITH_MISSING_INFO:

            casePRFRMD_WITH_ADDITIONAL_EFS_READ:

            case PRFRMD_ICON_NOT_DISPLAYED:

            case PRFRMD_MODIFIED_BY_NAA:

            case PRFRMD_LIMITED_SERVICE:

            case PRFRMD_WITH_MODIFICATION:

            case PRFRMD_NAA_NOT_ACTIVE:

            case PRFRMD_TONE_NOT_PLAYED:

                switch(AppInterface.CommandType.fromInt(cmdDet.typeOfCommand)) {

                    case SET_UP_MENU:

                        CatLog.d("CatService","SET_UP_MENU");

                        helpRequired =resMsg.resCode == ResultCode.HELP_INFO_REQUIRED;

                       sendMenuSelection(resMsg.usersMenuSelection, helpRequired);

                        return;

                                  …..

                          }

}

//根据协议的规定,组装成报文,然后交给RIL.java去发送

private voidsendMenuSelection(int menuId, boolean helpRequired) {

            ……

//组装成报文

            ……

//调用RIL的接口进行发送

       mCmdIf.sendEnvelope(hexString, null);

}

文件路径:frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java

public void sendEnvelope(String contents, Message response) {

        RILRequest rr = RILRequest.obtain(

               RILConstants.RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, response);

 

        if (RILJ_LOGD)riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

 

        rr.mp.writeString(contents);

             //通过socket发给RILD守护进程

        send(rr);

}

到这里为止,一条菜单请求命令,就已经通过Telephony层发送到RIL层了,RIL层根据命令标示号,组装成响应AT命令,然后下发给基带,

基带从运营商那里得到子菜单内容,上报给Telephony解析,然后传给STK应用进行显示。

 

总结:第1点整体上了解STK工作原理,第2点侧重了解StkAppService(应用层)和CatService(Telephony层)的交互流程,

      第3,4点从代码上了解STK应用的启动,以及菜单的加载,还有单击一项加载子菜单,从应用层到Telephony层,Telephony层到RIL层的流程。

                    

 

 

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值