Ims 是3GPP提出的概念,全称为IP Multimedia Subsystem(ip多媒体子系统),是为了满足IP多媒体业务的需求,基于PS域的一个子系统。
WCDMA网络从R99版本开始,与2G/2.5G网络相比,最大的变化在于空口技术的改变,空口变化直接造成接入带宽的提高,同时核心网分为CS域和PS域两个部分,CS域(电路域)负责语音业务,PS域(分组域)负责Internet访问业务。
从R4版本开始,CS域从原来的TDM承载变成IP承载,同时引入软交换系统,实现呼叫控制和承载相分离。R4版本由于对PS域和CS域都统一承载在IP网络上,同时由于软交换架构,目前成为WCDMA建网的主要选择。
随着用户需求的不断变化,单纯的语音通信和Internet访问业务已经不能满足需求。3GPP从R5版本开始,在原有的PS域的基础上,引入IMS来提供IP多媒体业务。
WCDMA 即3G网络使用PS域实现internet访问业务,CS域(电路域)负责语音业务,所以我们在3G网络时,打电话时,不能同时上网。4G时PS域和CS域都统一由ip网络承载,即volte高清通话,所以我们在4G时开启了volte,通话时还能同时上网。
如果开启volte,则会通过csfb(电路域落回)技术,在2G\3G进行语音业务。
Android 9 引入了一个名为 ImsService 的新 SystemApi 接口,可以帮助实现IP多媒体子系统。ImsService API 是在 Android 平台与供应商或运营商提供的 IMS 实现之间明确定义的接口。即IMS的具体实现是由供应商或运营商实现。 android提供了相关的系统SystemApi接口。
与普通的CS通话一致,由Dialer拨号应用,到Telecom,TeleService。区别在于,在GsmCdmaPhone#diale()中,判断是否支持ims通话。
从App侧一直到Telephony Framework,是不区分CS流程还是PS流程的。到了Telephony Framework模块,会依据IMS相关的状态信息(Registration Status,Service Status等)和用户设置相关信息(Volte Enable?Wifi Calling Enable?UT Enable?等)进而判断出,Call,SMS等是否需要优先走IMS的流程。整体来看,IMS架构如下图:
通常由Phone对象或者ImsPhoneCallTracker对象直接得到ImsManager对象,
ImsManager imsManager = ImsManager.getInstance(mContext, mPhoneId);
接着再通过ImsManager对象间接地得到ImsConfig、ImsUt、ImsCall等重要对象,然后根据请求不同,走不同的通道与Vendor RIL通信,与Call相关的走ImsCall,与补充业务相关的走ImsUt、与IMS功能的能力、参数相关的走ImsConfig,所以分工是十分明确的。谷歌为了规范高通\MTK等芯片厂商的行为,所以定义了IImsService、IImsConfig、IImsCallSession和IImsUt等接口,再由芯片厂商来实现这些接口,谷歌只需要处理好上层调用接口的逻辑即可。
public Connection dial(String dialString, @NonNull DialArgs dialArgs,
Consumer<Phone> chosenPhoneConsumer) throws CallStateException {
if (!isPhoneTypeGsm() && dialArgs.uusInfo != null) {
throw new CallStateException("Sending UUS information NOT supported in CDMA!");
}
String possibleEmergencyNumber = checkForTestEmergencyNumber(dialString);
// Record if the dialed number was swapped for a test emergency number.
boolean isDialedNumberSwapped = !TextUtils.equals(dialString, possibleEmergencyNumber);
if (isDialedNumberSwapped) {
logi("dialString replaced for possible emergency number: " + dialString + " -> "
+ possibleEmergencyNumber);
dialString = possibleEmergencyNumber;
}
TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
boolean isEmergency = tm.isEmergencyNumber(dialString);
/** Check if the call is Wireless Priority Service call */
//检查呼叫是否为无线优先服务呼叫
boolean isWpsCall = dialString != null ? (dialString.startsWith(PREFIX_WPS)
|| dialString.startsWith(PREFIX_WPS_CLIR_ACTIVATE)
|| dialString.startsWith(PREFIX_WPS_CLIR_DEACTIVATE)) : false;
ImsPhone.ImsDialArgs.Builder imsDialArgsBuilder;
imsDialArgsBuilder = ImsPhone.ImsDialArgs.Builder.from(dialArgs)
.setIsEmergency(isEmergency)
.setIsWpsCall(isWpsCall);
mDialArgs = dialArgs = imsDialArgsBuilder.build();
Phone imsPhone = mImsPhone;
CarrierConfigManager configManager =
(CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
//确定是否通过IMS支持无线优先级服务呼叫。
boolean allowWpsOverIms = configManager.getConfigForSubId(getSubId())
.getBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL);
//确认紧急电话是否使用ims
boolean useImsForEmergency = isEmergency && useImsForEmergency();
String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(PhoneNumberUtils.
stripSeparators(dialString));
boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#"))
&& dialPart.endsWith("#");
boolean isSuppServiceCode = ImsPhoneMmiCode.isSuppServiceCodes(dialPart, this);
boolean isPotentialUssdCode = isMmiCode && !isSuppServiceCode;
boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled();
boolean useImsForCall = useImsForCall(dialArgs)
&& (isWpsCall ? allowWpsOverIms : true);
//绕过仅限WiFi的WFC检查这是否是紧急呼叫-如果可能,我们仍应尝试通过移动网拨打。
if (!isEmergency) {
Phone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mPhoneId, mContext);
}
if (imsPhone != null && !allowWpsOverIms && !useImsForCall && isWpsCall
&& imsPhone.getCallTracker() instanceof ImsPhoneCallTracker) {
logi("WPS call placed over CS; disconnecting all IMS calls..");
ImsPhoneCallTracker tracker = (ImsPhoneCallTracker) imsPhone.getCallTracker();
tracker.hangupAllConnections();
}
//是否使用IMS拨打电话
if ((useImsForCall && (!isMmiCode || isPotentialUssdCode))
|| (isMmiCode && useImsForUt)
|| useImsForEmergency) {
try {
chosenPhoneConsumer.accept(imsPhone);
//imsPhone.dial
return imsPhone.dial(dialString, dialArgs);
} catch (CallStateException e) {
...
}
}
...
}
Android只提供到ImsCallSession,后面的ImsCallSessionImpl具体实现则要供应商或运营商提供,即imsService的具体实现由供应商或运营商提供。
参考:Android P IMS 相关2