39Go
前言本技术规范是由第三代合作伙伴计划(3GPP)制定的
Foreword This Technical Specification has been produced by the 3rd Generation Partnership Project (3GPP)
什么是mmi(Man-Machine-Interface):
从功能上来看,有一些从拨号盘拨出去的字符串,它的实际作用不是建立一个通话而是为了完成某种服务,这个就是MMI;从格式上来看,每一个从拨号盘输入的字符串,如果包含有*或者#,都可以称之为MMI.
MMI包括SS, USSD,Manufacturer defined MMI codes, SIM control codes等等。
Some dial strings in GSM are defined to do non-call setup
things, such as modify or query supplementary service settings (eg, call
forwarding). These are generally referred to as “MMI codes”.
We look to see if the dial string contains a valid MMI code (potentially
with a dial string at the end as well) and return info here.
If the dial string contains no MMI code, we return an instance with
only “dialingNumber” set
GSM中的某些拨号字符串已定义为进行非呼叫设置
诸如修改或查询补充服务设置(例如呼叫
转发)。 这些通常称为“ MMI代码”。
我们看一下拨号字符串是否包含有效的MMI代码(可能
末尾还有拨号字符串),然后在此处返回信息。
We need to request to open these codes MMI to use with the One Net service
These codes are dialled in the phone, to get informations or do changes in a VPN service.
#21#MSISDN*
#22#MSISDN*
#23#MSISDN*
#31*
#31#COMPANY*
#32*
#32#COMPANY*
#45#MSISDN*
#46#MSISDN*
#51#INTERNATIONAL MSISDN*
#111#MSISDN*
#112#MSISDN*
#114#MSISDN*
#121#HUNT MEMBER*
#132#MSISDN*
#141*
#142*
#143*
#154*
#155*
#155#HUNT NUMBER*
#156*
#157*
#157#POSITION NUMBER*
#191PIN USER#
#194PIN USER#
已*结尾的都是拨通的方式打出去的,已#结尾的都是USSD格式
Every Short String USSD command will end with #-key
USSD(Unstructured Supplementary Service Data)
33PIN# SEND
#33# SEND
#35# SEND
已开头#结尾的字符是已MMICode (SS)Supplementary Service补充服务,比如控制号码显示,呼叫转移等服务的号码串。这些号码串是每部GSM/UMTS/LTE手机中的固定服务号码,运营商是不能对它进行修改的。当手机系统接受到这些服务号码后,先在手机内部进行处理后,再传给网络。
比如你随便拿个手机,在拨号盘输入21*123456789#然后点击发送,这个时候你所有的来电都会直接转移到123456789。
USSD从字面上看,是非结构化的补充字符单从字符串格式上是没法区分SS和USSD
一,USSD基本都是运营商根据自己的服务自己定制的,而SS就像上面说的是每个手机固有的;
二,SS在发送给网络前,手机首先会自己处理一下,而USSD是完全透明的传送给网络。
SIM control codes
比如用来修改SIM卡PIN码的命令,在拨号键盘输入**0412346789*6789#,这将会将SIM卡的PIN码从1234修改成为6789.
目前这个码还没有客户还有提到
Manufacturer defined MMI codes
一些嵌在手机里的服务码,比如你要查询一个手机的IMEI号码,你可以在拨号键盘输入*#06#,手机的IMEI码会自动弹出来。
从源码中看到MMICode包含
// Supp Service codes from TS 22.030 Annex B
//Called line presentation
protected static final String SC_CLIP = "30";
protected static final String SC_CLIR = "31";
// Call Forwarding
protected static final String SC_CFU = "21";
protected static final String SC_CFB = "67";
protected static final String SC_CFNRy = "61";
protected static final String SC_CFNR = "62";
protected static final String SC_CF_All = "002";
protected static final String SC_CF_All_Conditional = "004";
// Call Waiting
protected static final String SC_WAIT = "43";
// Call Barring
protected static final String SC_BAOC = "33";
protected static final String SC_BAOIC = "331";
protected static final String SC_BAOICxH = "332";
protected static final String SC_BAIC = "35";
protected static final String SC_BAICr = "351";
protected static final String SC_BA_ALL = "330";
protected static final String SC_BA_MO = "333";
protected static final String SC_BA_MT = "353";
// Supp Service Password registration
protected static final String SC_PWD = "03";
// PIN/PIN2/PUK/PUK2
protected static final String SC_PIN = "04";
protected static final String SC_PIN2 = "042";
protected static final String SC_PUK = "05";
protected static final String SC_PUK2 = "052";
*#33* SEND
下面就是客户反馈某些USSD不可用。
alps/frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java
alps/frameworks/opt/telephony/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
alps/vendor/mediatek/proprietary/frameworks/opt/telephony/src/java/com/mediatek/internal/telephony/MtkGsmCdmaPhone.java
alps/vendor/mediatek/proprietary/frameworks/opt/telephony/src/java/com/mediatek/internal/telephony/imsphone/MtkImsPhone.java
为什么在这里修改,因为这个方法就是用来处理输入拨号盘的号码
@Override
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
Bundle intentExtras, ResultReceiver wrappedCallback)
throws CallStateException {
// Need to make sure dialString gets parsed properly
String newDialString = PhoneNumberUtils.stripSeparators(dialString);
if (isPhoneTypeGsm()) {
// handle in-call MMI first if applicable
if (handleInCallMmiCommands(newDialString)) {
return null;
}
//Redmine182596 modified for MMI Codes not working muyuanyuan 2019/8/22 begin
String pattern = "([#|(\\*)]{1,2}(\\d{2,3})[#|(\\*)](\\d{2,15}[#|(\\*)]){0,1})";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(newDialString);
boolean isSpecialPhoneNumber = m.matches();
//android.util.Log.d("myy","vendor mtkgsmcdmaphone isSpecialPhoneNumber = "+isSpecialPhoneNumber+"isSpecialPhoneNumber1 = "+isSpecialPhoneNumber1);
android.util.Log.d("myy","vendor mtkgsmcdmaphone isSpecialPhoneNumber = "+isSpecialPhoneNumber);
if(!isSpecialPhoneNumber){
//Redmine182596 modified for MMI Codes not working 2019/8/22 end
return mCT.dial(newDialString, uusInfo, intentExtras);
}
//Redmine150423 One Net MMI codes 20190120 end
// Only look at the Network portion for mmi
String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
MtkGsmMmiCode mmi = MtkGsmMmiCode.newFromDialString(networkPortion, this,
mUiccApplication.get(), wrappedCallback);
if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'...");
if (mmi == null) {
/// M: CC: For 3G VT only @{
if (videoState == VideoProfile.STATE_AUDIO_ONLY) {
android.util.Log.d("myy","11111111111111111");
return mCT.dial(newDialString, uusInfo, intentExtras);
} else {
if (!is3GVTEnabled()) {
throw new CallStateException("cannot vtDial for non-3GVT-capable device");
}
return ((MtkGsmCdmaCallTracker) mCT).vtDial(newDialString, uusInfo,
intentExtras);
}
/// @}
} else if (mmi.isTemporaryModeCLIR()) {
/// M: CC: For 3G VT only @{
if (videoState == VideoProfile.STATE_AUDIO_ONLY) {
android.util.Log.d("myy","222222222222");
return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
} else {
if (!is3GVTEnabled()) {
throw new CallStateException("cannot vtDial for non-3GVT-capable device");
}
return ((MtkGsmCdmaCallTracker) mCT).vtDial(mmi.mDialingNumber,
mmi.getCLIRMode(), uusInfo, intentExtras);
}
/// @}
} else {
mPendingMMIs.add(mmi);
/* Print MMI content */
Rlog.d(LOG_TAG, "dialInternal: " + dialString + ", mmi=" + mmi);
dumpPendingMmi();
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
mmi.processCode();
return null;
}
} else {
android.util.Log.d("myy","33333333333333");
return mCT.dial(newDialString);
}
}
这个码走的是11111111111111111这里,说明mmi=null
39GO/alps-release-o1.mp1-default/alps/vendor/mediatek/proprietary/frameworks/opt/telephony/src/java/com/mediatek/internal/telephony/gms/MtkGsmMmiCode.java
public static MtkGsmMmiCode newFromDialString(String dialString, MtkGsmCdmaPhone phone,
UiccCardApplication app, ResultReceiver wrappedCallback) {
Matcher m;
MtkGsmMmiCode ret = null;
m = sPatternSuppService.matcher(dialString);
// Is this formatted like a standard supplementary service code?
if (m.matches()) {
ret = new MtkGsmMmiCode(phone, app);
ret.mPoundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING));
ret.mAction = makeEmptyNull(m.group(MATCH_GROUP_ACTION));
ret.mSc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
ret.mSia = makeEmptyNull(m.group(MATCH_GROUP_SIA));
ret.mSib = makeEmptyNull(m.group(MATCH_GROUP_SIB));
ret.mSic = makeEmptyNull(m.group(MATCH_GROUP_SIC));
ret.mPwd = makeEmptyNull(m.group(MATCH_GROUP_PWD_CONFIRM));
ret.mDialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER));
ret.mCallbackReceiver = wrappedCallback;
// According to TS 22.030 6.5.2 "Structure of the MMI",
// the dialing number should not ending with #.
// The dialing number ending # is treated as unique USSD,
// eg, *400#16 digit number# to recharge the prepaid card
// in India operator(Mumbai MTNL)
android.util.Log.d("myy","ccccccccccccccc");
if(ret.mDialingNumber != null &&
ret.mDialingNumber.endsWith("#") &&
dialString.endsWith("#")){
android.util.Log.d("myy","dddddddddddddd");
ret = new MtkGsmMmiCode(phone, app);
ret.mPoundString = dialString;
}
} else if (dialString.endsWith("#")) {
// TS 22.030 sec 6.5.3.2
// "Entry of any characters defined in the 3GPP TS 23.038 [8] Default Alphabet
// (up to the maximum defined in 3GPP TS 24.080 [10]), followed by #SEND".
android.util.Log.d("myy","eeeeeeeeeeeee");
ret = new MtkGsmMmiCode(phone, app);
ret.mPoundString = dialString;
} else if (isTwoDigitShortCode(phone.getContext(), dialString)) {
android.util.Log.d("myy","fffffffffffff");
//Is a country-specific exception to short codes as defined in TS 22.030, 6.5.3.2
ret = null;
//modify for dialling 08 as normal call being initiated about GCF FT 40.2.1.1 begin
//} else if (isShortCode(dialString, phone)) {
} else if (isShortCode(dialString, phone) && !dialString.equals("08")) {
//modify for dialling 08 as normal call being initiated about GCF FT 40.2.1.1 end
// this may be a short code, as defined in TS 22.030, 6.5.3.2
android.util.Log.d("myy","gggggggggggggggg");
ret = new MtkGsmMmiCode(phone, app);
ret.mDialingNumber = dialString;
//如果加上此处的判断它会已USSD来处理了
}/*else if (dialString.endsWith("*")) {
android.util.Log.d("myy","aaaaaaaaaaaaaaaaa");
ret = new MtkGsmMmiCode(phone, app);
ret.mPoundString = dialString;
}*/
android.util.Log.d("myy","bbbbbbbbbbbbb");
return ret;
}
查看源代码发现它走的是"bbbbbbbbbbbbb"的路径,什么码都不是
/39O/alps/frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
// See TS 22.030 6.5.2 "Structure of the MMI"
protected static Pattern sPatternSuppService = Pattern.compile(
"((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
/* 1 2 3 4 5 6 7 8 9 10 11 12
1 = Full string up to and including #
2 = action (activation/interrogation/registration/erasure)
3 = service code
5 = SIA
7 = SIB
9 = SIC
10 = dialing number
*/
https://www.etsi.org/deliver/etsi_ts/122000_122099/122030/10.00.00_60/ts_122030v100000p.pdf
正则表达式:
“\",不用多说,用来匹配一个"“字符。
使用”(\d{2,3})”,匹配一个2位或者3位的数字(其中,"\d"用来匹配数字,{2,3}表示最少匹配2次,至多匹配3次)
如何查看你的MmiCode起作用的部分log:
./mtklog_Wrong APN supp serv/mobilelog/APLog_2019_1014_144406__1/radio_log_2__2019_1014_144704:10-14 14:44:37.967791 1049 1049 D MtkImsPhoneMmiCode: Service was enabled.
./mtklog_Wrong APN supp serv/mobilelog/APLog_2019_1014_144406__1/radio_log_2__2019_1014_144704:10-14 14:45:43.810206 1049 1049 D MtkImsPhoneMmiCode: isSupportedOverImsPhone(), return true!
./mtklog_Wrong APN supp serv/mobilelog/APLog_2019_1014_144406__1/radio_log_2__2019_1014_144704:10-14 14:45:45.649181 1049 1049 D MtkImsPhoneMmiCode: onSetComplete: mmi=ImsPhoneMmiCode {State=COMPLETE action=# sc=33 sia=1234 poundString=[****]} message=Call barring
./mtklog_Wrong APN supp serv/mobilelog/APLog_2019_1014_144406__1/radio_log_2__2019_1014_144704:10-14 14:45:45.649181 1049 1049 D MtkImsPhoneMmiCode: Service has been disabled.