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架构如下图:

ims核心网架构 ims网络架构_5g


通常由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) {
            	...
            }
        }
        ...
  }

ims核心网架构 ims网络架构_IP_02


Android只提供到ImsCallSession,后面的ImsCallSessionImpl具体实现则要供应商或运营商提供,即imsService的具体实现由供应商或运营商提供。

参考:Android P IMS 相关2

IP多媒体子系统