1. 一些概念知识

补充业务(Supplementary service)简称SS,包括呼叫等待、呼叫转移、呼叫限制、三方通话、USSD等,补充业务可以在VoLTE网络中使用,也可以在3G网络中使用。

XCAP协议(XML Configuration Access Protocol,XML配置访问协议):是一种应用层协议,它允许一个客户端来读,写,修改和删除应用程序配置数据存储在服务器上的XML格式。XCAP映射XML文件子树和元素属性到HTTP URIs,使这些组件可以直接使用HTTP协议的客户端访问。

具体应用:在很多通信应用程序中,如VoIP,IM和presence,需要网络服务器去获取个性化用户信息给服务请求的进程。这些个性化用户信息存在于网络中,但由终端用户自己管理。这些管理可通过各种获取终端完成,包括web,无线手机,或pc应用程序。个性化用户信息的例子包括presence,授权策略和presence lists。

详细可以查看

UT:3GPP中规定的IMS UE 与VoLTE AS之间的接口,双方使用XCAP协议来交互。

VoLTE AS:VoLTE Application Server,VoLTE应用服务器,提供各种VoLTE业务。

USSD:(Unstructured Supplementary Service Data)即非结构化补充数据业务,是一种新型基于GSM网络的交互式数据业务。 当你使用手机键盘输入一些网络已预先制定的数字或者符号比如*#等,再按send也就是拨号键就可以向网络发送一条指令,网络根据你的指令选择你需要的服务提供给你。

呼叫等待(Call Waiting):当用户电话正在通话,遇第三用户呼入时,可保留一方,与另一方通话的功能。当接到新的入呼叫时收到提醒,从而避免漏接重要人士的来电。

如具有此功能的甲用户与乙用户正在通话,如遇两用户呼入时,甲、乙两用户耳机中会听到“等待音”,丙用户可听到“回铃音”,此时甲用户可以有以下三种选择:①拒绝丙用户呼入,此时不需任何操作,过一定时间后丙与甲的接续中断,“等待音”消失,“回铃音”转为“忙音”;②保留原通话用户乙,改与呼入用户丙通话,并能轮流与乙、丙用户通话;③结束与乙用户通话,改与用户通话

呼叫限制(Call Barring):呼叫限制是在不同的条件下,判断是否允许用户进行出呼叫,以及是否允许用户接入一个呼叫的过程。客户可以灵活地控制手机的服务权限,防止被人误打、盗打电话,特别是国际长途电话,以避免不必要的经济损失。呼叫限制是指您可按一定条件设定密码,限制电话打入及手机打出的业务。如:1.BAOC(Barring of All Outgoing Calls,限制所有的出呼叫)设置此项功能后,该移动电话只能接听来话呼叫,而不能拨打电话。2.BOIC(Barring of Outgoing International Calls,限制所有的国际出呼叫)签约此业务的情况下,用户将不能呼出任何国际号码,可以发短信和接收短信。3. 限制除归属PLMN外的国际出呼叫(Barring of Outgoing International calls except those directed to the Home PLMN country)漫游分为国内漫游和国际漫游。

呼叫转移(Call Fowarding):呼叫转移是指您的电话无法接听或您不愿接电话,可以将来电转移到其它电话号码上。分为:1、无条件转移;2、遇忙转移;3、无应答转移;4、不可及(无信号或关机)转移

固定拨号(Fixed Dialing Number):

固定拨号(Fixed Dialing Number, FDN) 这个功能是为了在手机借给第三方的时候防止非授权使用的。即A用户把手机借给B用户,只限定B用户拨打A用户指定的号码,非指定的号码不能拨出,这个功能同时也适用于在集体条件下(比如放在集体宿舍充电)防止别人使用,而且不耽误来话,但是经过使用发现,SIM中的存储固定号码的空间太小了,普通的32K SIM卡只能存一个电话号码,动感地带32K SIM卡只能存两个号码,64K 大容量SIM卡也只能存两个。当启动固定拨号的时候,SIM卡电话簿被禁止访问,同时在电话簿里出现“FDN电话簿”,FDN里显示你设定的固定拨号的号码。这时,你无法拨出FDN以外的电话号码。

在启用(取消)这个功能和添加(更改、删除)FDN号码的时候需要用到PIN2

2. IMS 补充业务流程

UE发起IMS补充业务过程为,

  1. UE 向DNS网关查询xcap服务器的地址;
  2. UE向DNS 网关查询bsf 服务器的地址;
  3. UE在BSF服务器的引导下完成GBA认证;
  4. UE向NAF发起业务认证;
  5. UE查询、设置补充业务。

GBA两次认证

GBA架构流程包括两个步骤。第一步是UE的BSF引导认证,第二步是UE补充业务访问的认证。类似于第一步完成鉴权,获得密钥、BTID,第二步是业务执行过程中的二次认证,看UE是否合法、是否在有效生命周期内。

UE 与 BSF 完成引导认证流程

  1. UE 向BSF 发起HTTP请求(不带AUTH),携带MPI (用户标识);
  2. BSF 向HSS 请求用户认证向量五元组(RAND/AUTN/XRES/CK/IK);
  3. HSS 返回用户认证向量组给BSF;
  4. BSF 向UE 发送401 认证请求,携带RAND/AUTN;
  5. UE通过AUTN 计算得到RES和Ks;
  6. UE 发送HTTP请求给BSF ,携带RES;
  7. BSF 计算RES 和Ks,与UE发过来的RES 对比;
  8. 计算B-TID,BSF 向UE发送HTTP 200 OK,携带btid和lifetime。

PS:B-TID是本次引导认证成功后产生的标识,用于此次会话中后续与BSF交互。

UE 与 AP/NAF 完成业务访问流程

  1. UE通过 Ks 派生出业务访问标识 Ks_NAF ,向NAF 发起业务访问请求,携带B-TID(http get/put);
  2. NAF 向 BSF 发起认证请求,携带B-TID;
  3. BSF 认证通过,则返回prof、有效周期等给NAF;
  4. NAF 处理补充业务请求,然后向UE 发送应答(http 200ok)。

UT整体流程

wireshark抓包中的UT 过程

下图是一次补充业务查询和设置的http过程:

Ut接口参数

3. 安卓中ss的核心代码

补充业务(Supplementary Service) MMI Code的核心代码都在frameworks/opt/telephony仓库下的GsmMmiCode.java文件中。

// See TS 22.030 6.5.2 "Structure of the MMI"static Pattern sPatternSuppService = Pattern.compile("((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
/*   1  2                    3          4  5       6   7         8    9     10  11             121 = Full string up to and including #2 = action (activation/interrogation/registration/erasure)3 = service code5 = SIA7 = SIB9 = SIC10 = dialing number
*/

首先,使用"(\\*|#|\\*#|\\*\\*|##)",匹配以"*"   "#"   "*#"   "**"   或   "##"  开头的字符串(其中,"\"为转义字符,"|"代表"或")。

第二步,使用"(\\d{2,3})",匹配一个2位或者3位的数字(其中,"\d"用来匹配数字,{2,3}表示最少匹配2次,至多匹配3次)。

第三步,使用(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#,匹配最多连续四组以*开头,其余部分为除了*或#以外的字符串。这一部分的结尾匹配一个"#"。

这里有一点儿不太容易看明白,但其实,可以观察到,这里其实是由好几个"\\*([^*#]*)"嵌套在一起组成的,拆分来说明一下:

"\\*",不用多说,用来匹配一个"*"字符。

([^*#]*),其中前半部分的"[^*#]"用来匹配除了*或#以外的任意单个字符;最后面的"*"表示,对前面的[^*#]匹配零次或多次。

由此,我们可知,当"[^*#]"匹配了3次时,"\\*([^*#]*)"匹配到的字符串诸如"*XYZ";而当且仅当"[^*#]"匹配零次时,"\\*([^*#]*)"匹配到的字符串为"*"。

而每一组后面的"?",则表示,前面的匹配可以出现零次或一次。

第四步,使用(.*),匹配一个除了"\r\n"外,任意长度的字符串(字符串长度可以为0)。

按照3GPP协议,正则表达式所匹配出来的每一部分,都有一个名字,我们来按照名字来写一下:

**SERVICE_CODE*SIA*SIB*SIC*PWD_CONFIRM#DIALING_NUMBER

其中,最前面的部分叫做ACTION,为了体现出格式,我们用"**"表示(也可以是"*"   "#"   "*#"   或   "##"中的任意一种)。

而上面我们第三步中所讲的,即这里的"*SIA*SIB*SIC*PWD_CONFIRM#",我们也说了,后面的"?"表示,他们可以出现零次或一次,所以,其实这里可以是如下的任意一种形式:

  • *SIA*SIB*SIC*PWD_CONFIRM#
  • *SIA*SIB*SIC#
  • *SIA*SIB**PWD_CONFIRM#
  • *SIA**SIC*PWD_CONFIRM#
  • **SIB*SIC*PWD_CONFIRM#
  • *SIA*SIB#
  • *SIA**SIC#
  • **SIB*SIC#
  • ***SIC*PWD_CONFIRM#
  • **SIB**PWD_CONFIRM#
  • *SIA***PWD_CONFIRM#
  • *SIA#
  • **SIB#
  • ***SIC#
  • ****PWD_CONFIRM#

之所以这样设计,是因为,并不是所有的MMI Code中都会同时使用到SIA、SIB、SIC和PWD_CONFIRM这四个值,有可能只需要其中的一个或者两个。

关于正则表达式的匹配,我们就说到这里,这里确实比较乱,如果对正则表达式不是特别熟悉,可以先去看看最基本的正则表达式规则(注意: Java中的正则表达式与其他地方用的正则表达式略有不同,学习的时候不要混淆),而后在纸上或者Notepad中将正则表达式分成一小块一小块来进行解析,慢慢阅读其含义。

好,那么我们回到主题,如何使用MMI Code来设置/取消/查询呼叫转移呢?

首先我们查看代码中的一些定义:

// From TS 22.030 6.5.2
static final String ACTION_ACTIVATE = "*";            // 激活呼叫转移业务
static final String ACTION_DEACTIVATE = "#";          // 去激活呼叫转移业务
static final String ACTION_INTERROGATE = "*#";        // 查询呼叫转移
static final String ACTION_REGISTER = "**";           // 注册呼叫转移
static final String ACTION_ERASURE = "##";            // 取消呼叫转移// Call Forwarding
static final String SC_CFU     = "21";                // 无条件转移
static final String SC_CFB     = "67";                // 遇忙转移
static final String SC_CFNRy   = "61";                // 不可及转移
static final String SC_CFNR    = "62";                // 无应答转移static final String SC_CF_All = "002";                // 所有呼叫转移
static final String SC_CF_All_Conditional = "004";    // 所有条件呼叫转移(不包含无条件转移)

我们一般在使用电话设置的UI向运营商注册呼叫转移时,所使用的是ACTION_REGISTER,即"**";取消时所使用的是ACTION_ERASURE,即"##";而查询时,则是ACTION_INTERROGATE,即"*#"。

我们查看GsmMmiCode.java中processCode()方法对CF的处理:

1. 匹配到的ServiceCode:"**"代表注册呼叫转移,"##"代表取消呼叫转移,"*#"代表查询呼叫转移

2. 匹配到的SIA:要转移给哪个号码

3. 匹配到的SIB:对哪个ServiceClass设置呼叫转移

4. 匹配到的SIC:在何种情况下进行呼叫转移(即无条件转移、遇忙转移等)

/** Process a MMI code or short code...anything that isn't a dialing number */
public void
processCode() throws CallStateException {try {......// 使用匹配到的Service Code,判断是否为上面所列出的呼叫转移相关的值} else if (isServiceCodeCallForwarding(mSc)) {Rlog.d(LOG_TAG, "processCode: is CF");// 匹配到的SIA,是要转移给哪一个号码String dialingNumber = mSia;// 匹配到的SIB,是ServiceClassint serviceClass = siToServiceClass(mSib);// 匹配到的SIC,为何种情况下进行转移(即无条件转移、遇忙转移等)int reason = scToCallForwardReason(mSc);int time = siToTime(mSic);if (isInterrogate()) {mPhone.mCi.queryCallForwardStatus(reason, serviceClass,  dialingNumber,obtainMessage(EVENT_QUERY_CF_COMPLETE, this));} else {int cfAction;if (isActivate()) {// 3GPP TS 22.030 6.5.2// a call forwarding request with a single * would be// interpreted as registration if containing a forwarded-to// number, or an activation if notif (isEmptyOrNull(dialingNumber)) {cfAction = CommandsInterface.CF_ACTION_ENABLE;mIsCallFwdReg = false;} else {cfAction = CommandsInterface.CF_ACTION_REGISTRATION;mIsCallFwdReg = true;}} else if (isDeactivate()) {cfAction = CommandsInterface.CF_ACTION_DISABLE;} else if (isRegister()) {cfAction = CommandsInterface.CF_ACTION_REGISTRATION;} else if (isErasure()) {cfAction = CommandsInterface.CF_ACTION_ERASURE;} else {throw new RuntimeException ("invalid action");}int isEnableDesired =((cfAction == CommandsInterface.CF_ACTION_ENABLE) ||(cfAction == CommandsInterface.CF_ACTION_REGISTRATION)) ? 1 : 0;Rlog.d(LOG_TAG, "processCode: is CF setCallForward");mPhone.mCi.setCallForward(cfAction, reason, serviceClass,dialingNumber, time, obtainMessage(EVENT_SET_CFF_COMPLETE,isVoiceUnconditionalForwarding(reason, serviceClass) ? 1 : 0,isEnableDesired, this));}}......} catch (RuntimeException exc) {mState = State.FAILED;mMessage = mContext.getText(com.android.internal.R.string.mmiError);Rlog.d(LOG_TAG, "processCode: RuntimeException=" + exc);mPhone.onMMIDone(this);}
}

我们在电话设置的UI中,是无法指定serviceClass的,只能使用默认的SERVICE_CLASS_VOICE。但是,我们可以在这里通过SIB选择不同的serviceClass。在上述问题中,由于用户的Sim卡设置了SERVICE_CLASS_DATA_SYNC下的无条件呼叫转移,所以,根据以下代码,我们可以在MMI Code中,设置SIB的值为24(注意,SIB的值与CommandsInterface.java中定义的serviceClass的值并不一致),从而取消该呼叫转移的设置。

private static int
siToServiceClass(String si) {if (si == null || si.length() == 0) {return  SERVICE_CLASS_NONE;} else {// NumberFormatException should cause MMI failint serviceCode = Integer.parseInt(si, 10);switch (serviceCode) {......case 24: return SERVICE_CLASS_DATA_SYNC;......default:throw new RuntimeException("unsupported MMI service code " + si);}}
}

参考博客

安卓电话补充业务 SS相关推荐

  1. 安卓电话和网络开发全解:电话硬件检测、电话服务信息、sim信息、网络服务信息、数据连接和数据传输信息、电话状态监听

    全栈工程师开发手册 (作者:栾鹏) 安卓教程全解 安卓电话和网络开发全解,包括电话硬件检测.电话服务信息.sim信息.网络服务信息.数据连接和数据传输信息.通过phone state listener ...

  2. 安卓电话交互桥梁 Telecom【System进程】

    1. Telecom所处位置 由下图,Telecom的作用是起到交互桥梁,与IncallUI 和 Telephony[Phone进程.TeleService]交互 路径 统称 进程 packages/ ...

  3. 微软从安卓那里获取的盈利比重WinPhone 7还多

    为什么80%的码农都做不了架构师?>>> Microsoft Earns More from Android than Windows Phone 7 微软从安卓那里获取的盈利比重W ...

  4. 安卓开发大全、系列文章、精品教程

    全栈工程师开发手册 (作者:栾鹏) 安卓教程全解 安卓Intent的Action中的常值变量:窗口action常量(android.intent.action.+xxx),广播action常量(and ...

  5. 李彦宏清华经管学院演讲:11年创业心路历程与人生感悟

    李彦宏清华经管学院演讲:11年创业心路历程与人生感悟 浏览次数: 425次 2011年10月22日 腾讯科技 字号: 大 中 小 分享到: QQ空间 新浪微博 腾讯微博 人人网 豆瓣网 开心网 更多 ...

  6. wi-fi测试软件正确吗,几款Wi-Fi信号测试小工具

    原标题:几款Wi-Fi信号测试小工具 今天就为大家介绍几种测试WiFi信号强度方法,有了它们的帮助,还愁没有好WiFi吗? 方法一:小白都会用的Wi-Fi信号强度测量法 无论是智能手机,还是PAD,抑 ...

  7. 我的asterisk 接入电信ims之旅【把电信座机提取到手机上,实现手机不插卡也用打电话】

    第一步.配置光猫. 注意事项:登录光猫用超级管理员的账号密码,光猫后面的那个是普通用户的,创建不了网络连接. 1.进入光猫提取voip[就是座机的配置信息] 上图的主服务器地址.主用端口.outbou ...

  8. android wear 中文键盘,不用 鼠标和键盘用AndroidWear手表控制PC

    [导读]最新版本的Unified Remote(远程遥控器)增加了对Android Wear的支持,让你能够从手表上操纵PC的鼠标光标,同时能够通过语音命令控制具体应用程序及网站. 如果你连鼠标和键盘 ...

  9. 手表控android+wear,鼠标和键盘都不用 用Android Wear手表控制PC

    智东西(公众号:zhidxcom) 文|大禾 如果你连鼠标和键盘都懒得碰,现在有了新的方法,你可以通过Android Wear智能手表控制你的PC. 最新版本的Unified Remote(远程遥控器 ...

最新文章

  1. 业余时间用哪里,哪里就有发展的可能
  2. android 导入开源项目代码常见问题
  3. Ubuntu 下最简明的翻译词典(调用GoogleAPI,运行在终端)
  4. Spring Cache抽象-缓存注解
  5. LSQL Developer连接Oracle11g 64位数据库配置详解
  6. StringBuilder详解
  7. python生成requirements.txt的两种方法
  8. Angular 6+ 之新版service
  9. 思考:日期类型的数据应该用什么样的具体形式存储到数据库?
  10. java 执行查询_在单个语句中用Java执行多个查询
  11. pcfg 自然语言处理_自然语言处理:原理简明教程09-句法分析,语义分析和篇章分析...
  12. android 车牌输入键盘
  13. centos 搭建 SVN
  14. 【ARM】嵌入式 ARM Linux 下移植 USB 蓝牙、交叉编译 bluez 各种版本
  15. Sql查询某个字段是否包含小写字母或小写
  16. JAVA中Object类中的equal方法
  17. 共阴极和共阳极数码管显示的十六进制代码
  18. 超级推荐:网工必备模拟器PNETLab,附下载链接,全球第一篇最优质的帖子
  19. 费曼 计算机科学 讲义,《费曼物理讲义》3 物理学与其他科学的关系
  20. Python字典操作大全

热门文章

  1. Lisp语言:循环控制
  2. vscode-armgcc-openocd搭建STM32开发调试环境
  3. Delphi ...开源!
  4. 《大话处理器》相关主题汇总
  5. [excel]收藏夹-遇过问题的解决方法总览
  6. 智能+建筑>智能建筑
  7. [021] Android应用“易查查”上线推广,请同行多多指教、多多支持
  8. Github的远程项目如何下载到本地
  9. Mars3D中无人机航拍的数据想叠加到三维地图上,实现的流程和方法
  10. 五年企稳上升的阿里,还能再涨吗?