我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android RIL介绍

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android RIL介绍

文章目录

一、需求

了解IMS相关知识体系
2、Volte
3、拨号相关流程
4、android电话发展背景
5、RILD 与 RILJ、IMS回调消息的机制

二、相关概念

2.1 IMS

        IMS全称是IP Multimedia Subsystem,中文意义为IP多媒体子系统。IMS是一种基于IP基础结构,能够融合数据、话音和移动等网络技术的系统。
         IP = 基于IP 的传输,基于IP的会话控制,基于IP的业务实现
        Multimedia = 语音、视频、图片、文本等多种媒体组合,在多种接入基础之上具有不同能力的终端组合
        Subsvstem = 依赖于现有网络技术和网络设备发展的网络,最大程度重用现有网络系统
(我个人理解IMS是一个很大的概念,它不单单特指:IMS服务、IMS PDN等。它类似GSM,WCDMA,LTE一样,是一种体系结构,包含了好多内容)

2.2 Volte

        VoLTE是Voice over LTE的缩写,是基于 IMS 的语音业务。VoLTE基于IP多媒体子系统(IMS)网络,在LTE上使用为控制层面和语音服务的媒体层面特制的配置文件,使语音服务作为数据流在LTE数据承载网络中进行传输,而不再需要维护和依赖传统的电路交换语音网络。通俗的来讲,就是语音通话建立在4G流量之上,无需再依托于2G/3G网,全部承载于4G网络中,最终实现数据与语音业务在同一网络下的统一,使4G网络不再仅仅提供流量数据业务支撑,还提供语音及视频通话支持,让4G网络利用最大化。
        移动用户肯定都遇到过这个问题,在玩网络游戏时一则电话打进来,游戏就断网了,这并非手机硬件问题,而是移动4G手机是通过2G信号进行语音通讯,所以通话过程中系统会自动将网络从4G切换到2G。

2.3 CS域与PS域

        我们了解到的数据传输有两个域,分别是CS域和PS域。我们常说的CS域就是电路交换域,通常用于语音通话,在2G和3G中都有应用到;我们常说的PS域就是分组交换域,通常用于数据业务,在3G、4G和5G中都有应用到。而还有一个IMS(IP多媒体子系统),相当于是PS域上的一个子系统,IMS的存在可以让用户在PS域上同时使用语音通话和数据业务

2.3.1 CS域

        CS(Circuit Switched)域,即电路交换域。首先需要建立一条传输数据的连接,建立完成之后开始数据的传输,此连接不会断开,直到数据传输完毕,才可以释放掉连接。所以一条链路只电路交换的特点是独占一条链路,一直用于数据传输。可靠性很高,但不高效。这就相当于是小时候玩的听筒游戏,两个纸杯子之间连着一条线,两个人通话过程中,这条链路是不能断开的,直到通话结束。

2.3.2 PS域

        PS域(Packet Switch)表面意思就是分组交换。PS 域不能直接进行语音业务,PS业务就是常见的数据业务,也包括流媒体业务、VOIP等等。具有高效的传输效率,但可靠性没有CS域那么高。

2.4 VOIP

        VOIP是一个很宽泛的概念,VOIP(Voice over IP)的缩写,只要是通过IP传输的语音电话,都可以称为VOIP。如互联网提供商提供(Skype、微信、teams等)、运营商提供的IMS(LTE时代公认的语音解决方案(VoLTE)。因为VoLTE是运营商在LTE层上附着IMS-PDN进行传输的,相对于纯IP网络的skype、微信网络电话,通话质量会好很多。

2.5 URC消息

        URC 是Unsolicited Result Code,即"非请求结果码"。 一般的 AT命令 流程都是控制端发出 命令 ,被控端响应结果码。 但当被控端有事件需要通知控制端时,就会主动发出 URC ,例如有呼叫打入、收到新短信息、自动关机等。

2.6 HIDL

        HIDL的全称是HAL interface definition language(硬件抽象层接口定义语言) ,是AndroidFramework 与Android HAL之间的接口。HIDL 旨在用于进程间通信(IPC)。Android O(8.0) 之前系统的升级牵扯多方协作,极为麻烦,HIDL机制的推出就是将 framework 与 hal 层分开,使得框架部分可以直接被覆盖、更新,而不需要重新对 HAL 进行编译,这样在系统升级时,OEM 厂商 跳过 SoC厂商,先对 framework 进行升级。

三、环境

  1. 芯片:高通Qcm2290
  2. 版本:Android 11

四、设计思路

4.1 RIL结构图

在这里插入图片描述

4.2 RIL相关模块介绍

模块进程介绍
Dialercom.android.dialer负责拨号、呼叫界面显示
TeleServicecom.android.phone负责通话逻辑,如实际向RIL拨号、挂电话,及电话状态如拨号、振铃、接通等的变更。
TelecomServicesystem_server负责逻辑控制,是沟通各个进程交互的桥梁。
telephony-common(RILJ)jar,看哪个进程引用,主要是com.android.phone主要是phone模块,hal层对应的java层客户端的代码,这个模块的代码就是跟hal下面的C/C++服务进行通信的
RILDRILD主要负责接发RILJ指令、Modem指令
MODEMModemModem是调制解调器的缩写,它是一种用于数字信号和模拟信号之间转换的设备。在手机中,Modem是一个硬件模块,它负责处理与无线网络通信相关的任务,包括数据传输、语音通信和短信等。

4.2.1 Dialer模块

源码: LINUX\android\packages\apps\Dialer

4.2.2 TeleService模块

源码: LINUX\android\packages\services\Telephony

4.2.2.1 TeleService启动

(1)设置persistent标记,此标记AMS会持续保证进程(com.android.phone)存活,意外挂掉也会自动重启。
LINUX\android\packages\services\Telephony/AndroidManifest.xml

    

(2)SystemServer启动后,ActivityManqgerService服务初始化完成后,启动persistent进程,即Phone模块被启动。
LINUX\android\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

 void startPersistentApps(int matchFlags) {        ...        synchronized (this) {            try {                final List apps = AppGlobals.getPackageManager()                        .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();                for (ApplicationInfo app : apps) {                    if (!"android".equals(app.packageName)) {                        addAppLocked(app, null, false, null ,    ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);                    }                }            } catch (RemoteException ex) {            }        }    }

4.2.3 TelecomService模块

源码: LINUX\android\packages\services\Telecomm

4.2.3.1 TelecomService启动

Android设备刚开机,SystemServer进程初始化完成启动完系统的核心服务如AMS、PMS后,就会加载系统其它服务,这其中就包含了一个与Telecom服务启动相关的系统服务专门用于加载Telecom:
LINUX\android\frameworks\base\services\java\com\android\server\SystemServer.java

private void run() {    ...    startBootstrapServices(t);    startCoreServices(t);    startOtherServices(t);    ...}private void startOtherServices(@NonNull TimingsTraceAndSlog t)    ...        //启动Telecom服务的加载类        t.traceBegin("StartTelecomLoaderService");        mSystemServiceManager.startService(TelecomLoaderService.class);=        t.traceEnd();        //启动telephony注册服务,用于注册监听telephony状态的接口        t.traceBegin("StartTelephonyRegistry");        telephonyRegistry = new TelephonyRegistry(context, new TelephonyRegistry.ConfigurationProvider());        ServiceManager.addService("telephony.registry", telephonyRegistry);        t.traceEnd();        ...        //AMS初始化完成,启动Telecom服务        mActivityManagerService.systemReady(() -> {            ...            mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY);            ...        }, t);    ...}

在TelecomLoaderService类实现Telecom服务的bind工作,完成Telecom的启动
LINUX\android\frameworks\base\services\core\java\com\android\server\telecom\TelecomLoaderService.java

    private static final ComponentName SERVICE_COMPONENT = new ComponentName(            "com.android.server.telecom",            "com.android.server.telecom.components.TelecomService");    private static final String SERVICE_ACTION = "com.android.ITelecomService";    @Override    public void onBootPhase(int phase) {        if (phase == PHASE_ACTIVITY_MANAGER_READY) {            ...            connectToTelecom();        }    }    //连接Telecom服务    private void connectToTelecom() {        synchronized (mLock) {            ...            TelecomServiceConnection serviceConnection = new TelecomServiceConnection();            Intent intent = new Intent(SERVICE_ACTION);            intent.setComponent(SERVICE_COMPONENT);            int flags = Context.BIND_IMPORTANT | Context.BIND_FOREGROUND_SERVICE                    | Context.BIND_AUTO_CREATE;            // Bind to Telecom and register the service            if (mContext.bindServiceAsUser(intent, serviceConnection, flags, UserHandle.SYSTEM)) {                mServiceConnection = serviceConnection;            }        }    }     private class TelecomServiceConnection implements ServiceConnection {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            try {                ITelecomLoader telecomLoader = ITelecomLoader.Stub.asInterface(service);//返回TelecomService代理对象                ITelecomService telecomService = telecomLoader.createTelecomService(mServiceRepo);//返回TelecomService实现类                SmsApplication.getDefaultMmsApplication(mContext, false);                ServiceManager.addService(Context.TELECOM_SERVICE, telecomService.asBinder());//将TelecomService实现类注册到serviceManager,以便后续方便引用            ...            }        ...    }
4.2.3.2 TeleComService消息处理模型

Telecom是Android的一个系统服务,其主要作用是管理Android系统当前的通话,如来电显示,接听电话,挂断电话等功能,在Telephony模块与上层UI之间起到了一个桥梁的作用。比如,Telephony有接收到新的来电时,首先会告知Telecom,然后由Telecom服务通知上层应用来电信息,并显示来电界面。

在这里插入图片描述

4.2.4 telephony-common模块

源码: LINUX\android\frameworks\opt\telephony
telephony-common模块最终编译会生成一个java library,主要是phone模块在引用,hal层对应的java层客户端的代码RILJ,这个模块的代码就是跟hal下面的C/C++服务进行通信的。
LINUX\android\frameworks\opt\telephony\Android.bp

java_library {    name: "telephony-common",    installable: true,    ...}

4.2.5 Telecom_Framewrok模块

源码:LINUX\android\frameworks\base\telecomm
android提供的phone的一些sdk的代码,最终编译完成打包进framework.jar
LINUX\android\frameworks\base\Android.bp

filegroup {    name: "framework-telecomm-sources",    class="lazy" data-srcs: [        "telecomm/java*.java",        "telecomm/java*.aidl",    ],    path: "telecomm/java",}framework-telecomm-sources => framework-non-updatable-sources => framework-non-updatable-sources => framework-minus-apex => framework

4.2.6 Telephony_Framewrok模块

源码: LINUX\android\frameworks\base\telephony
android提供的phone的一些sdk的代码,最终编译完成打包进framework.jar
LINUX\android\frameworks\base\Android.bp

filegroup {    name: "framework-telephony-sources",    class="lazy" data-srcs: [        "telephony/java*.java",        "telephony/java*.aidl",    ],    path: "telephony/java",}framework-telephony-sources => framework-non-updatable-sources => framework-non-updatable-sources => framework-minus-apex => framework

4.2.7 RIL模块

源码: LINUX\android\hardware\ril
RIL模块由rild守护进程、libril.so、librefrence.so三部分组成:

4.2.7.1 RILD守护进程

源码: LINUX\android\hardware\ril\rild
RILD主要起到承上启下的作用,作为modem和RILJ的通信的中转站。RILD可分为两部分,一是负责与RILJ通讯的部分,主要通过HIDL通信;另一个是负责与modem交互,主要通过AT指令。

4.2.7.1.1 RILD启动

(1)开机时,通过RC文件启动RILD进程

@LINUX\android\hardware\ril\rild\rild.rcservice vendor.ril-daemon /vendor/bin/hw/rild    class main    user radio    disabled    group radio cache inet misc audio log readproc wakelock    capabilities BLOCK_SUSPEND NET_ADMIN NET_RAW

(2)RILD启动后,会执行main啊方法,初始化RILD相关操作

@LINUX\android\hardware\ril\rild\rild.cint main(int argc, char **argv) {    ...    rilInit =        (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))        dlsym(dlHandle, "RIL_Init");    ...    //初始化reference,轮询modem指令    funcs = rilInit(&s_rilEnv, argc, rilArgv);    RLOGD("RIL_Init rilInit completed");    //在rild注册reference的回调函数    RIL_register(funcs);    ...}
4.2.7.2 libril共享库

源码: LINUX\android\hardware\ril\libril
libril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息送给调用进程

4.2.7.3 librefrence共享库

源码: LINUX\android\hardware\ril\reference-ril
librefrence_ril.so是共享库,是由各手机厂商自己实现,在rild进程运行中通过dlopen方式加载,主要负责跟modem硬件通信,转换来自libril的请求为AT命令,同时监听Modem的反馈信息给libril

4.3 RIL相关模块通讯

4.3.1 通讯架构图

在这里插入图片描述

五、详细设计

5.1 Dialer拨号

5.1.1 Dialer应用拨号时序图

在这里插入图片描述

5.1.2 Dialer拨号界面显示

Dialer应用为拨号提供了界面显示,同时也是拨号请求的触发点

@LINUX\android\packages\apps\Dialer\java\com\android\dialer\dialpadview\DialpadFragment.java  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {    ...    View fragmentView = inflater.inflate(R.layout.dialpad_fragment, container, false);//拨号界面布局加载    ...    return fragmentView;  }    @Override  public void onClick(View view) {    int resId = view.getId();    if (resId == R.id.dialpad_floating_action_button) {      view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);      handleDialButtonPressed();//拨号按钮点击事件    }     ...  }

5.1.3 Dialer权限检查

Dialer应用会进行权限检查,判断当前是否为默认拨号盘,且当前应用是否声明CALL_PHONE权限。

  public static boolean placeCall(Context context, Intent intent) {    if (hasCallPhonePermission(context)) {//权限检查      getTelecomManager(context).placeCall(intent.getData(), intent.getExtras());      return true;    }    return false;  }  @Deprecated  public static boolean hasCallPhonePermission(Context context) {    return isDefaultDialer(context) || hasPermission(context, Manifest.permission.CALL_PHONE);//判断当前是否为默认拨号盘,且当前应用是否声明CALL_PHONE权限  }

5.1.4 与TelecomService通信

Dialer应用通过TelecomManager对象,将拨号请求消息,通过binder的方式,通知TelecomService进程。

@LINUX\android\frameworks\base\telecomm\java\android\telecom\TelecomManager.java    @RequiresPermission(anyOf = {android.Manifest.permission.CALL_PHONE,            android.Manifest.permission.MANAGE_OWN_CALLS})    public void placeCall(Uri address, Bundle extras) {        ITelecomService service = getTelecomService();//获取服务端代理对象        if (service != null) {            if (address == null) {                Log.w(TAG, "Cannot place call to empty address.");            }            try {                service.placeCall(address, extras == null ? new Bundle() : extras,                        mContext.getOpPackageName(), mContext.getAttributionTag());//通过binder实现跨进程通信,将拨号请求发给TelecomService进程            } catch (RemoteException e) {                Log.e(TAG, "Error calling ITelecomService#placeCall", e);            }        }    }

5.2 TelecomService处理拨号流程

5.2.1 TelecomService处理拨号时序图

在这里插入图片描述

5.2.2 往InCallService发送请求

(1)startOutgoingCall开始呼叫请求
Dialer进程的拨号请求传递到TelecomService进程后,通过startOutgoingCall方法开始请求打开呼叫界面

@LINUX\android\packages\services\Telecomm\class="lazy" data-src\com\android\server\telecom\CallIntentProcessor.javastatic void processOutgoingCallIntent(            Context context,            CallsManager callsManager,            Intent intent,            String callingPackage,            DefaultDialerCache defaultDialerCache) {        ...        // Send to CallsManager to ensure the InCallUI gets kicked off before the broadcast returns        CompletableFuture callFuture = callsManager                .startOutgoingCall(handle, phoneAccountHandle, clientExtras, initiatingUser,                        intent, callingPackage);//开始呼叫请求        final Session logSubsession = Log.createSubsession();        callFuture.thenAccept((call) -> {            if (call != null) {                Log.continueSession(logSubsession, "CIP.sNOCI");                try {                    broadcaster.processCall(call, disposition);//发送广播,切换成异步请求                } finally {                    Log.endSession();                }            }        });    }

(2)绑定InCallService
InCallServiceImpl是InCallService的子类,在Dialer进程,而TelecomService进程与InCallServiceImpl也是通过bind实现跨进程通信。

@LINUX\android\packages\services\Telecomm\class="lazy" data-src\com\android\server\telecom\InCallController.javapublic static final String SERVICE_INTERFACE = "android.telecom.InCallService";public int connect(Call call) {            ...            Intent intent = new Intent(InCallService.SERVICE_INTERFACE);            intent.setComponent(mInCallServiceInfo.getComponentName());            ...            //绑定InCallService类型服务,最终绑定InCallServiceImpl            if (!mContext.bindServiceAsUser(intent, mServiceConnection,                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE |                        Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS |                        Context.BIND_ABOVE_CLIENT,                        UserHandle.CURRENT)) {                Log.w(this, "Failed to connect.");                mIsConnected = false;            }            ...        }

(3)启动InCallActivity呼叫界面
当InCallServiceImpl被TelecomService进程绑定后,会调用onBind函数,接着启动InCallActivity呼叫界面

@LINUX\android\packages\apps\Dialer\java\com\android\incallui\InCallServiceImpl.java  public IBinder onBind(Intent intent) {    ...    InCallPresenter.getInstance().onServiceBind();    InCallPresenter.getInstance().maybeStartRevealAnimation(intent);//开启显示动画    TelecomAdapter.getInstance().setInCallService(this);    ...    return iBinder;  }@LINUX\android\packages\apps\Dialer\java\com\android\incallui\InCallPresenter.java   public void maybeStartRevealAnimation(Intent intent) {    ...    //启动InCallActivity呼叫界面    final Intent activityIntent =        InCallActivity.getIntent(context, false, true, false );    activityIntent.putExtra(TouchPointManager.TOUCH_POINT, touchPoint);    context.startActivity(activityIntent);  }

5.2.3 广播下发消息

TelecomService进程发出一个定向广播,由TelecomService进程中的NewOutgoingCallBroadcastIntentReceiver对象接收。
(1)TelecomService进程发送广播

@LINUX\android\packages\services\Telecomm\class="lazy" data-src\com\android\server\telecom\NewOutgoingCallIntentBroadcaster.java    private void broadcastIntent(            Intent originalCallIntent,            String number,            boolean receiverRequired,            UserHandle targetUser) {        Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);        ...        //发送广播        mContext.sendOrderedBroadcastAsUser(                broadcastIntent,                targetUser,                android.Manifest.permission.PROCESS_OUTGOING_CALLS,                AppOpsManager.OP_PROCESS_OUTGOING_CALLS,                options.toBundle(),                receiverRequired ? new NewOutgoingCallBroadcastIntentReceiver() : null,                null,  // scheduler                Activity.RESULT_OK,  // initialCode                number,  // initialData: initial value for the result data (number to be modified)                null);  // initialExtras    }

(2)TelecomService进程接收广播

@LINUX\android\packages\services\Telecomm\class="lazy" data-src\com\android\server\telecom\NewOutgoingCallIntentBroadcaster.javapublic class NewOutgoingCallBroadcastIntentReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            ...                    placeOutgoingCallImmediately(mCall, resultHandleUri, gatewayInfo,mIntent.getBooleanExtra(        TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false),mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,        VideoProfile.STATE_AUDIO_ONLY));//继续下发呼叫请求            ...        }    }

同一个应用中为什么要使用广播来传递消息呢?因为Dialer进程发起拨号请求后,会将消息发给TelecomService进程,通过该进程的placeCall方法层层调用,此时方法是同步调用。直到调用了broadcastIntent,通过广播方式将同步方法转换成异步处理,即当前的呼叫请求下发给TelecomService进程处理,同Dialer进程的呼叫请求结束。

5.2.4 往TeleService下发请求

(1)placeOutgoingCall 下发呼叫请求
接收广播后,通过placeOutgoingCall方法继续下发拨号请求

    private void placeOutgoingCallImmediately(Call call, Uri handle, GatewayInfo gatewayInfo,            boolean speakerphoneOn, int videoState) {        ...        mCall.setNewOutgoingCallIntentBroadcastIsDone();        mCallsManager.placeOutgoingCall(call, handle, gatewayInfo, speakerphoneOn, videoState);    }

(2)绑定TeleService
binder绑定TeleService服务,实现跨进程通信,同时将将拨号请求分发给TeleService进程,由TeleService进程继续处理

@LINUX\android\packages\services\Telecomm\class="lazy" data-src\com\android\server\telecom\ConnectionServiceWrapper.javapublic void createConnection(final Call call, final CreateConnectionResponse response) {        BindCallback callback = new BindCallback() {            @Override            public void onSuccess() {                ...                    mServiceInterface.createConnection(...);//与TeleService绑定成功后,发起创建通话连接请求                ...            }            @Override            public void onFailure() {                ...            }        };        mBinder.bind(callback, call);//绑定TeleService    }}@LINUX\android\packages\services\Telecomm\class="lazy" data-src\com\android\server\telecom\ServiceBinder.javapublic static final String SERVICE_INTERFACE = "android.telecom.ConnectionService";void bind(BindCallback callback, Call call) {            ...            if (mServiceConnection == null) {                Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);//该对象为SERVICE_INTERFACE                ...                if (mUserHandle != null) {                    isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,mUserHandle);//绑定TeleService                }                ...             }         }

5.3 TeleService下发拨号请求

5.3.1 TeleService下发拨号请求时序图

在这里插入图片描述

5.3.2 TeleService类图

在这里插入图片描述

5.3.3 TelephonyConnectionService启动

@LINUX\android\packages\services\Telephony\AndroidManifest.xml        <service                android:singleUser="true"                android:name="com.android.services.telephony.TelephonyConnectionService"                android:label="@string/pstn_connection_service_label"                android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" >            <intent-filter>                <action android:name="android.telecom.ConnectionService" />            </intent-filter>        </service>

5.3.4 TeleService拨号请求下发(GsmCdmaPhone)

在teleService会获取当前呼叫的phone对象,如GsmCdmaPhone、ImsPhone、SipPhone,来决定要从用哪一种通讯方式进行呼叫。

@LINUX\android\packages\services\Telephony\class="lazy" data-src\com\android\services\telephony\TelephonyConnectionService.java    public Connection onCreateOutgoingConnection(            PhoneAccountHandle connectionManagerPhoneAccount,            final ConnectionRequest request) {        ...        if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {            // TODO: We don't check for SecurityException here (requires            // CALL_PRIVILEGED permission).            final Phone phone = getPhoneForAccount(request.getAccountHandle(),                    false , null );//获取Phone对象,决定采用的通讯方式            ...        }         ...        if (!isEmergencyNumber) {            ...                return placeOutgoingConnection(request, resultConnection, phone);//往RILD继续下发消息        }          ...    }

5.3.5 TeleService拨号请求下发(ImsPhone)

Android 9 引入了一个名为 ImsService 的新 SystemApi 接口,可以帮助实现IP多媒体子系统。ImsService API 是在 Android 平台与供应商或运营商提供的 IMS 实现之间明确定义的接口。即IMS的具体实现是由供应商或运营商实现。 android提供了相关的系统SystemApi接口。

5.3.5.1 时序图

在这里插入图片描述

5.3.5.2 IMS与CDMA、GSM时序切换

与普通的CS通话一致,由Dialer拨号应用,到Telecom,TeleService。区别在于,在GsmCdmaPhone#diale()中,判断是否支持ims通话。

    public Connection dial(String dialString, @NonNull DialArgs dialArgs)            throws CallStateException {        ...        boolean useImsForCall = useImsForCall(dialArgs)                && !shallDialOnCircuitSwitch(dialArgs.intentExtras)                && (isWpsCall ? allowWpsOverIms : true);//是否使用IMS通讯方式        ...        if ((useImsForCall && (!isMmiCode || isPotentialUssdCode))                || (isMmiCode && useImsForUt)                || useImsForEmergency) {            try {                if (DBG) logd("Trying IMS PS call");                return imsPhone.dial(dialString, dialArgs);//使用IMS通话            } ...        }        ...        if (isPhoneTypeGsm()) {            return dialInternal(dialString, new DialArgs.Builder<>()                    .setIntentExtras(dialArgs.intentExtras)                    .build());//使用GSM通话        } else {            return dialInternal(dialString, dialArgs);//其他通话方式        }    }

5.4 RILD处理拨号请求

5.4.1 RILD拨号请求消息下发时序图

在这里插入图片描述

5.4.2 RILJ往RILD发送指令

RILJ往RILD发送指令,请求拨号的消息下发如下:

@LINUX\android\frameworks\opt\telephony\class="lazy" data-src\java\com\android\internal\telephony\RIL.java    @Override    public void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo,                     boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo,                     Message result) {        ...        IRadio radioProxy = getRadioProxy(result);        if (radioProxy != null) {            RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result,                    mRILDefaultWorkSource);            ...            try {                radioProxy.dial(rr.mSerial, dialInfo);//请求拨号            } catch (RemoteException | RuntimeException e) {                handleRadioProxyExceptionForRR(rr, "dial", e);            }        }    }

5.4.3 RILD接收到RILJ指令

RILD接收到RILJ指令,JAVA层与HAL层通过HIDL方式绑定,即HAL也会有对应的dial映射方法。

@LINUX\android\hardware\ril\libril\ril_service.cpp#define CALL_ONREQUEST(a, b, c, d, e) \        s_vendorFunctions->onRequest((a), (b), (c), (d), ((RIL_SOCKET_ID)(e)))Return RadioImpl::dial(int32_t serial, const Dial& dialInfo) {    ...    CALL_ONREQUEST(RIL_REQUEST_DIAL, &dial, sizeOfDial, pRI, mSlotId);    memsetAndFreeStrings(2, dial.address, uusInfo.uusData);    return Void();}

5.4.4 RILD和reference侧消息传递

onRequest方法是在哪里被实现的?我们需要关注下s_vendorFunctions是在哪个地方赋值的。关于s_vendorFunctions全局变量,当我们调用reference中的RIL_Init完成初始化时,就会得到reference返回当前链接库提供的接口函数,通过该接口函数我们便可实现rild侧与reference侧的通讯(reference侧也是跑在rild进程,但是考虑到reference一般由modem厂商客制化,不清楚其内部实现,故以下将其称为reference侧,以便更好地区分该模块)。

@LINUX\android\hardware\ril\libril\ril.cppextern "C" voidRIL_register (const RIL_RadioFunctions *callbacks) {    ...    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));//对象拷贝    ...    radio::registerService(&s_callbacks, s_commands);//注册回调函数    ...}@LINUX\android\hardware\ril\libril\ril_service.cppvoid radio::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) {    ...    s_vendorFunctions = callbacks;//将回调函数对象赋值,以实现rild侧与reference侧的引用    s_commands = commands;    ...}

5.4.5 reference侧接收到消息

reference层接收到消息, 从onRequest可以看出,reference中对所有的命令请求进行判别,然后选择不同的处理方式。

@LINUX\android\hardware\ril\reference-ril\reference-ril.cstatic void onRequest (int request, void *data, size_t datalen, RIL_Token t){    ...    switch (request) {        ...        case RIL_REQUEST_DIAL:            requestDial(data, datalen, t);//拨号请求            break;        case RIL_REQUEST_HANGUP://挂断电话请求            requestHangup(data, datalen, t);            break;        ...           }}static void requestDial(void *data, size_t datalen __unused, RIL_Token t){    ...    ret = at_send_command(cmd, NULL);//往modem层发送指令    ...        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);}

5.4.6 reference侧将消息发送至modem侧

reference侧将消息发送至modem侧,at_send_command() -> at_send_command_full() -> at_send_command_full_nolock(),经过上面的操作,就将一条命令通过串口方式传输到了Modem侧。其间,完成了两个重要动作:1、通过writeline发送数据到Modem;2、阻塞当前线程,等待Modem回应。

@LINUX\android\hardware\ril\reference-ril\atchannel.cstatic int at_send_command_full_nolock (const char *command, ATCommandType type,                    const char *responsePrefix, const char *smspdu,                    long long timeoutMsec, ATResponse **pp_outResponse){    ...    err = writeline (command);//将命令通过AT指令方式写入modem侧    if (err < 0) {        goto error;    }    ...    while (sp_response->finalResponse == NULL && s_readerClosed == 0) {        if (timeoutMsec != 0) {            err = pthread_cond_timedwait(&s_commandcond, &s_commandmutex, &ts);//阻塞线程,直到modem侧消息返回        }         ...    }    ...    return err;}

5.4.7 modem侧发送消息至reference侧

modem侧发送消息至reference侧,我们需要如何唤醒阻塞的线程呢?当我们发送数据或命令给Modem的时候,阻塞了当前的线程,阻塞的目的就是等待Modem的回应,而如果Modem有数据上来,那么肯定是先被reference的ReaderLoop检测到并处理,因此,也应该是在ReaderLoop的消息处理中去唤醒当前阻塞的线程,而且应该把Modem的反馈传输给阻塞线程。

@LINUX\android\hardware\ril\reference-ril\atchannel.cstatic void *readerLoop(void *arg __unused){    for (;;) {        ...        line = readline();//读取modem返回数据        ...        if(isSMSUnsolicited(line)) {            ...        } else {            processLine(line);//解析消息        }    }    ...    return NULL;}static void processLine(const char *line){    ...    if (sp_response == NULL) {                handleUnsolicited(line);//处理URC消息    } else if (isFinalResponseSuccess(line)) {        sp_response->success = 1;        handleFinalResponse(line);//发送回应消息    }    ...}static void handleFinalResponse(const char *line){    sp_response->finalResponse = strdup(line);    pthread_cond_signal(&s_commandcond);//发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态}

5.4.8 reference侧轮询modem指令

reference侧轮询modem指令,ReaderLoop轮询modem消息又是在哪里实现的呢?RILD进程被创建后,会通过RIL_Init初始化相关的reference相关准备工作,其中涉及到打开与modem侧的AT通道,监听modem上报消息。

@LINUX\android\hardware\ril\reference-ril\atchannel.cconst RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv){    ...    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);//创建mainLoop线程    ...}static void *mainLoop(void *param __unused){    ...    for (;;) {        ...        ret = at_open(fd, onUnsolicited);//打开AT通道并把处理URC消息的方法onUnsolicited传进去         ...    }}@LINUX\android\hardware\ril\reference-ril\atchannel.cint at_open(int fd, ATUnsolHandler h){    ...    ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);//创建readerLooper线程,读取AT指令并处理modem侧消息    ...}

六、RIL指令

6.1 RILJ主动发送指令

源码: android\hardware\ril\libril\ril_commands.h

指令功能
RIL_REQUEST_GET_SIM_STATUS获取SIM卡状态
RIL_REQUEST_ENTER_SIM_PIN请求输入SIM的PIN码(PIN码是用来保护SIM卡安全的密码。PIN码的初始值一般是1234,可以进行更改)
RIL_REQUEST_ENTER_SIM_PUK请求PUK码和新的PIN码的输入(PUK码是用来解PIN码的解锁码,共8位长)
RIL_REQUEST_ENTER_SIM_PIN2请求输入SIM的PIN2码(进入某种特殊功能时,如设置固定号码、设置通话计费等,所要输入的个人识别码)
RIL_REQUEST_ENTER_SIM_PUK2请求PUK2码和新的PIN2码的输入(PUK2码就是专门用来为被锁上的PIN2码解锁的)
RIL_REQUEST_CHANGE_SIM_PIN请求更改PIN码
RIL_REQUEST_CHANGE_SIM_PIN2请求更改PIN2码
RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION请求输入网络个人码以便去激活
RIL_REQUEST_GET_CURRENT_CALLS请求获取当前呼叫列表
RIL_REQUEST_DIAL初始化一个语音呼叫
RIL_REQUEST_GET_IMSI取SIM卡中的国际移动用户识别码IMSI(区别移动用户的标志,储存在SIM卡中,可用于区别移动用户的有效信息)
RIL_REQUEST_HANGUP挂断某一激活的通话
RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND挂断所有等待的或者保持的通话
RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND释放所有激活的通话并激活保持的或者等待的通话
RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE话连接状态的转换,将所有激活的通话转为保持或等待状态(通话状态:IDLE、ACTIVE、HOLDING、WAITING等)
RIL__CONFERENCE请求加入电话会议
RIL_REQUEST_UDUB发送用户确定用户忙UDUB(user determined user busy)信号
RIL_REQUEST_LAST_CALL_FAIL_CAUSE请求最近一次通话中断的错误码
RIL_REQUEST_SIGNAL_STRENGTH请求当前的信号强度等相关信息
RIL_REQUEST_VOICE_REGISTRATION_STATE请求当前注册状态(描述的是信号柱的显示)
RIL_REQUEST_DATA_REGISTRATION_STATE请求当前注册状态(描述的是3G、4G的显示)
RIL_REQUEST_OPERATOR请求运营商名称
RIL_REQUEST_RADIO_POWER请求打开无线电通讯
RIL_REQUEST_DTMF发起DTMF请求(在手机中,常用的DTMF场景是使用手机拨打一些服务台电话,比如客服热线10086、10000之类;电话接入之后,有对应的语音提示输入不同的数字进入不同的菜单,或者要修改资料,对方要验证我们的账号和密码,这时打开手机拨号盘,输入数字信息,对方就知道我们输入的内容是什么。)
RIL_REQUEST_SEND_SMS发送短信
RIL_REQUEST_SEND_SMS_EXPECT_MORE发送短信,且支持串联短信
RIL_REQUEST_SETUP_DATA_CALL请求打开数据流量
RIL_REQUEST_SIM_IO获取SIM卡号
RIL_REQUEST_SEND_USSD请求一个USSD业务(ussd即非结构化补充数据业务,是一种全球移动通信系统 (GSM) 协议,用于发送消息和文本文件。USSD代码一般以*开头,以#结尾,可用于执行一些隐藏功能。)
RIL_REQUEST_CANCEL_USSD撤销一个USSD业务
RIL_REQUEST_GET_CLIR查询当前呼叫号码是否隐藏请求
RIL_REQUEST_SET_CLIR设置呼叫号码是否隐藏
RIL_REQUEST_QUERY_CALL_FORWARD_STATUS查询呼叫转移的状态
RIL_REQUEST_SET_CALL_FORWARD设置呼叫转移
RIL_REQUEST_QUERY_CALL_WAITING查询呼叫等待信息
RIL_REQUEST_SET_CALL_WAITING设置呼叫等待状态(当移动电话用户正在进行通话时,又有呼叫向您发来。这时发起新呼叫的一方被置于等待,待原通话结束后再将新呼叫接入。)
RIL_REQUEST_SMS_ACKNOWLEDGE用于短信消息的传送应答
RIL_REQUEST_GET_IMEI获取IMEI号
RIL_REQUEST_GET_IMEISV获取IMEISV号(MEI有15位,最后一位是Check digit,即检验位;IMEISV有16位,是去掉了Check digit,加上了两位SVN,即software version number。)
RIL_REQUEST_ANSWER接听电话请求
RIL_REQUEST_DEACTIVATE_DATA_CALL断开数据流量业务
RIL_REQUEST_QUERY_FACILITY_LOCK查询设备锁定状态
RIL_REQUEST_SET_FACILITY_LOCK设置设备锁定状态
RIL_REQUEST_CHANGE_BARRING_PASSWORD修改呼叫限制密码
RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE查询网络选择
RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC设置网络选择为自动
RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL设置网络选择为手动
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS查询可用网络列表
RIL_REQUEST_DTMF_START启动DTMF功能
RIL_REQUEST_DTMF_STOP关闭DTMF功能
RIL_REQUEST_BASEBAND_VERSION获取基带版本
RIL_REQUEST_SEPARATE_CONNECTION将所有激活的呼叫挂起
RIL_REQUEST_SET_MUTE设置静音
RIL_REQUEST_ALLOW_DATA设置双卡数据切换
RIL_REQUEST_GET_MUTE获取静音状态
RIL_REQUEST_QUERY_CLIP查询主叫号码(主叫号码识别显示补充业务。CLIP是指被叫移动用户的补充业务,移动用户接收呼叫时,网络向用户提示主叫用户的号码。)
RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE查询上一次数据连接失败原因
RIL_REQUEST_DATA_CALL_LIST查询数据连接信息
RIL_REQUEST_RESET_RADIO复位模块
RIL_REQUEST_OEM_HOOK_RAW???
RIL_REQUEST_OEM_HOOK_STRINGS???
RIL_REQUEST_SCREEN_STATE查询屏幕状态
RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION启用/禁用来自网络的补充服务相关通知
RIL_REQUEST_WRITE_SMS_TO_SIM复制短信到SIM卡中
RIL_REQUEST_DELETE_SMS_ON_SIM删除SIM卡短信
RIL_REQUEST_SET_BAND_MODE设置频段模式
RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE查询可用频段模式
RIL_REQUEST_STK_GET_PROFILE查询STK的配置信息
RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND请求打开STK子菜单
RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE获取STK子菜单信息
RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM接受或拒绝来自SIM卡的呼叫设置请求。
RIL_REQUEST_EXPLICIT_CALL_TRANSFER请求呼叫转接业务
RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE设置偏好的网络类型
RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE获取偏好的网络类型
RIL_REQUEST_GET_NEIGHBORING_CELL_IDS获取此设备上的相邻单元列表
RIL_REQUEST_SET_LOCATION_UPDATES位置更新
RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE请求设置CDMA订阅模式
RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE设置偏好漫游类型
RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE查询偏好漫游类型
RIL_REQUEST_SET_TTY_MODE设置为聋哑模式
RIL_REQUEST_QUERY_TTY_MODE查询聋哑模式状态
RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE设置首选语音隐私(VP)
RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE获取当前设置的首选语音隐私(VP)模式。
RIL_REQUEST_CDMA_FLASH???
RIL_REQUEST_CDMA_BURST_DTMF发起DTMS请求
RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY???
RIL_REQUEST_CDMA_SEND_SMSCDMA发送短信
RIL_REQUEST_CDMA_SMS_ACKNOWLEDGECDMA短信消息的传送应答
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG获取小区广播配置,通过小区广播信道(CBCH)将信息(如地理位置、天气状况等信息)传到手机,再由用户选择接收的一种功能,通过此功能可向用户提供位置信息,天气预报等服务;是向中国移动的手机客户按区域、按频道发送各种实时、动态的分类信息的业务。
RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG设置小区广播配置
RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION小区广播功能开关
RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIGCDMA获取小区广播配置
RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIGCDMA设置小区广播配置
RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATIONCDMA小区广播开关
RIL_REQUEST_CDMA_SUBSCRIPTION查询CDMA的实现模式(CDMA手机两实现模式:
机卡分离式:用户信息写在单独的UIM
卡机卡一体式:用户信息写在手机中的)
RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIMCDMA复制短息到uim卡,RUIM是应用在CDMA2000手机的一种智能卡
RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIMCDMA删除RUIM卡上短信
RIL_REQUEST_DEVICE_IDENTITY请求设备标识
RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE离开紧急回拨模式
RIL_REQUEST_GET_SMSC_ADDRESS获取SMSC地址,网络短信息服务中心地址
RIL_REQUEST_SET_SMSC_ADDRESS设置SMSC地址
RIL_REQUEST_REPORT_SMS_MEMORY_STATUS通知modem,SMS的存储情况
RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING通知modem,StkService已经启动
RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE设置CDMA的实现模式
RIL_REQUEST_ISIM_AUTHENTICATIONISIM认证
RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU确认收到成功或失败的最后一条传入短信,包括确认TPDU作为RP-ACK或RP-ERROR PDU的RP-User-Data元素发送。
RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS???
RIL_REQUEST_VOICE_RADIO_TECH获取当前的语音无线电技术。
RIL_REQUEST_GET_CELL_INFO_LIST获取当前的信元信息
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE设置信元信息的调用时间,即onCellInfoChanged的响应时间
RIL_REQUEST_SET_INITIAL_ATTACH_APN初始化APN
RIL_REQUEST_IMS_REGISTRATION_STATE查询IMS的注册状态
RIL_REQUEST_IMS_SEND_SMS请求IMS发送短信
RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC在基本频道上与SIM交换apdu
RIL_REQUEST_SIM_OPEN_CHANNEL打开SIM无线信道
RIL_REQUEST_SIM_CLOSE_CHANNEL关闭SIM无线信道
RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL在逻辑信道上与SIM交换APDU。
RIL_REQUEST_NV_READ_ITEM读取{@link RadioNVItems} / {@code ril_nv_items.h}中定义的NV项之一,用于部分CDMA运营商的设备配置。
RIL_REQUEST_NV_WRITE_ITEM写一个定义在{@link RadioNVItems} / {@code ril_nv_items.h}的NV项,用于部分CDMA运营商的设备配置。
RIL_REQUEST_NV_WRITE_CDMA_PRL更新无线电NV存储中的CDMA首选漫游列表(PRL)。用于部分CDMA运营商的设备配置。
RIL_REQUEST_NV_RESET_CONFIG执行modem配置复位。用于部分CDMA运营商的设备配置。
RIL_REQUEST_SET_UICC_SUBSCRIPTION???
RIL_REQUEST_ALLOW_DATA双卡数据切换
RIL_REQUEST_GET_HARDWARE_CONFIG获取RIL的硬件配置
RIL_REQUEST_SIM_AUTHENTICATIONSIM卡身份认证
RIL_REQUEST_GET_DC_RT_INFO???
RIL_REQUEST_SET_DC_RT_INFO_RATE???
RIL_REQUEST_SET_DATA_PROFILE发送当前运营商的数据配置文件到数据服务进行数据呼叫设置。这是仅适用于CDMA运营商,可通过OTA更改配置文件。数据服务应该总是使用最新的数据配置文件发送的框架。
RIL_REQUEST_SHUTDOWN关机
RIL_REQUEST_GET_RADIO_CAPABILITY获取电话无线电功能
RIL_REQUEST_SET_RADIO_CAPABILITY设置电话无线电类型和接入技术。
RIL_REQUEST_START_LCE启动LCE(链路容量估计)服务,并设置所需的报告间隔。
RIL_REQUEST_STOP_LCE停止LCE服务。
RIL_REQUEST_PULL_LCEDATA获取LCE服务获取容量数据。
RIL_REQUEST_GET_ACTIVITY_INFO请求modem的活动信息
RIL_REQUEST_SET_CARRIER_RESTRICTIONS???
RIL_REQUEST_GET_CARRIER_RESTRICTIONS???
RIL_REQUEST_SEND_DEVICE_STATE发送设备状态到Modem
RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER打开/关闭调制解调器的主动响应
RIL_REQUEST_SET_SIM_CARD_POWER设置SIM卡上电状态。 @param state SIM卡状态(断电、上电、通过)
RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION设置加密IMSI和IMPI所需的运营商信息。
RIL_REQUEST_START_NETWORK_SCAN扫描网络
RIL_REQUEST_STOP_NETWORK_SCAN停止扫描网络
RIL_REQUEST_START_KEEPALIVE启动长连接
RIL_REQUEST_STOP_KEEPALIVE停止长连接

6.2 RILJ被动接收指令

源码: android\hardware\ril\libril\ril_unsol_commands.h

指令功能
RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED无线通信模块状态改变
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED来电状态改变
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED信号状态改变
RIL_UNSOL_RESPONSE_NEW_SMS收到短信
RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT短信发送状态报告
RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM???
RIL_UNSOL_ON_USSD???
RIL_UNSOL_ON_USSD_REQUEST???
RIL_UNSOL_NITZ_TIME_RECEIVED通知更新终端系统的时间及时区
RIL_UNSOL_DATA_CALL_LIST_CHANGED数据连接状态改变
RIL_UNSOL_SUPP_SVC_NOTIFICATION???
RIL_UNSOL_STK_SESSION_END通知会话结束
RIL_UNSOL_STK_PROACTIVE_COMMAND插卡开机,Modem检测到有卡插入,这时候Modem会读取SIM中的相关信息,并把消息上报给RIL层,显示STK主菜单
RIL_UNSOL_STK_EVENT_NOTIFY用于STK事件分发
RIL_UNSOL_STK_CALL_SETUP发送来自modem的拨打电话的主动上报消息
RIL_UNSOL_SIM_SMS_STORAGE_FULL通知空间满了
RIL_UNSOL_SIM_REFRESHmodem请求更新卡对应的文件信息
RIL_UNSOL_CALL_RING有来电时上报
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGEDSIM卡状态改变
RIL_UNSOL_RESPONSE_CDMA_NEW_SMS接收到CDMA短信
RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS???
RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL???
RIL_UNSOL_RESTRICTED_STATE_CHANGED受限策略改变通知
RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE进入紧急回拨模式通知
RIL_UNSOL_CDMA_CALL_WAITING呼叫等待通知
RIL_UNSOL_CDMA_OTA_PROVISION_STATUS???
RIL_UNSOL_CDMA_INFO_REC???
RIL_UNSOL_OEM_HOOK_RAW???
RIL_UNSOL_RINGBACK_TONE电话铃声
RIL_UNSOL_RESEND_INCALL_MUTE???
RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED管理 机卡分离 Or 机卡一体的消息
RIL_UNSOL_CDMA_PRL_CHANGED优选漫游列表更新通知
RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE离开紧急回拨模式通知
RIL_UNSOL_RIL_CONNECTEDRIL连接成功通知
RIL_UNSOL_VOICE_RADIO_TECH_CHANGED???
RIL_UNSOL_CELL_INFO_LIST???
RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED???
RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED???
RIL_UNSOL_SRVCC_STATE_NOTIFY???
RIL_UNSOL_HARDWARE_CONFIG_CHANGED???
RIL_UNSOL_DC_RT_INFO_CHANGED???
RIL_UNSOL_RADIO_CAPABILITY???
RIL_UNSOL_ON_SS???
RIL_UNSOL_STK_CC_ALPHA_NOTIFY???
RIL_UNSOL_LCEDATA_RECV???
RIL_UNSOL_PCO_DATA???
RIL_UNSOL_MODEM_RESTARTmodem重启通知
RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION???
RIL_UNSOL_NETWORK_SCAN_RESULT通知网络扫描结果
RIL_UNSOL_KEEPALIVE_STATUS通知心跳状态

七、参考资料

https://source.android.google.cn/docs/core/connect/ims?hl=zh-cn
http://www.taodudu.cc/news/show-3144813.html?action=onClick
http://baike.jld5.cn/news/51009.html
https://wiki.mbalib.com/wiki/IMS
https://blog.csdn.net/guyuewangyue/article/details/122866358
电路交换和分组交换区别:
https://www.elecfans.com/d/1308634.html
TeleComService介绍:
https://blog.csdn.net/qq_40587575/article/details/113753895
TeleService介绍:
https://www.jianshu.com/p/ff51295b84a1
Rild介绍:
https://www.freesion.com/article/21011164222/
https://blog.csdn.net/u014386544/article/details/52594400
RIL指令:
https://www.mianshigee.com/note/detail/23890yjg/
https://blog.csdn.net/iteye_6233/article/details/82230745
https://blog.csdn.net/u010961631/article/details/9446377/
https://blog.csdn.net/sjz4860402/article/details/51182078
http://www.2sim.cn/article/13
https://zhuanlan.zhihu.com/p/117218424
https://blog.csdn.net/u014386544/article/details/56851616

来源地址:https://blog.csdn.net/u013320490/article/details/133126584

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android RIL介绍

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

android AsyncTask详细介绍

AsyncTask和Handler对比 1 ) AsyncTask实现的原理,和适用的优缺点 AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可
2022-06-06

android CursorLoader用法介绍

工作内容集中到Contact模块,这个应用查询数据的地方很多,其使用了CursorLoader这个工具大大简化了代码复杂度。android自3.0提供了Loader机制,当时google的API只是简单的介绍了一下没有给出用法,大家很少有关
2022-06-06

Android Bitmap详细介绍

代码如下: package com.testbitmapscale; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream;
2022-06-06

Android录屏 MediaRecorder介绍

Android录屏 MediaRecorder介绍 Android录屏的三种方案 1、adb shell命令screenrecord 2、MediaRecorder, MediaProjection 3、MediaCodec和MediaMu
2022-06-06

android之ContentResolver与ContentProvider介绍

android中对数据操作包含有: file, sqlite3, Preferences, ContectResolver与ContentProvider前三种数据操作方式都只是针对本应用内数据,程序不能通过这三种方法去操作别的应用内的数
2022-06-06

Android Handler的详细介绍

Handler的定义  主要接受子线程发送的数据, 并用此数据配合主线程更新UI.  解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发。比如说, 你要是点击一个
2022-06-06

Android Thread 介绍与实例

Android中很重要的一个机制就是线程+消息,当然线程并不是android独有的,下面,简单的说说使用线程的时候应该注意的地方 我们采用最简单的方法来建立一个android的线程+消息的例子 1.Thread + Handler [jav
2022-06-06

Android View Binding使用介绍

前言 Android Studio稳定版发布了3.6版本,带来了一些新变化:首先外观,启动页变了,logo改了,更显现代化;增加Multi Preview功能,能同时预览多个尺寸屏幕的显示效果;模拟器支持多屏;也终于支持全新的视图绑定组件V
2022-06-06

android WebView加载html5介绍

Android设备多分辨率的问题 Android浏览器默认预览模式浏览 会缩小页面 WebView中则会以原始大小显示 Android浏览器和WebView默认为mdpi。hdpi相当于mdpi的1.5倍 ldpi相当于0.75倍 三种解决
2022-06-06

android 窗口焦点介绍

背景 我们经常会遇到一种Application does not hava focused window的ANR异常,这种异常一般是没有焦点窗口FocusedWindow导致,且这类异常只会发生在key事件的派发,因为key事件是需要找到一
2023-08-21

Android中的WebView详细介绍

Android中WebView的详细解释: 1. 概念: WebView(网络视图)能加载显示网页,可以将其视为一个浏览器。它使用了WebKit渲染引擎加载显示网页。 2. 使用方法: (1).实例化WebView组件: A.在Act
2022-06-06

Android Application类的详细介绍

Android Application类详解: Android中Application类的详细解释: 我们在平时的开发中,有时候可能会需要一些全局数据,来让应用中的所有Activity和View都能访问到,大家在遇到这种情况时,可能首先会想
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录