最新要闻
- 油价小幅下调 加一箱油将少花2元 全球最资讯
- 中海达(300177)6月13日主力资金净买入525.51万元_天天通讯
- PMR机械硬盘走到尽头了!西数/希捷正疯狂自救
- 6旬老人守株待兔式飞奔撞车碰瓷索赔 车主吓坏:监控还清白 环球精选
- 广东有多热?网友在广东买虾 还没到家就熟了 世界今日讯
- 美国再将31家中企列入“实体清单”!
- 2999元的国产显卡值不值得冲?实测3A大作给你答案
- 焦点信息:天津:“多卡合一”创新服务“城市小蜜蜂”
- 全球快报:小米卢伟冰:小米13 Ultra在意法西德及香港地区正式开售 销售超预期
- 首发预装鸿蒙OS 4.0!华为Mate60 Pro概念图出炉 全球热资讯
- 天天精选!NASA决定造访遍地黄金的“灵神星”:平均每位美国人能分300亿美元
- 美系硬派SUV福特探险者谍照曝光!外观内饰全面升级 预计将在年内首次亮相_今日热讯
- 今日热搜:8GB显卡卖到3199元 显存成本曝光:英伟达实在太赚了
- 视点!男生抠掉脸上痘痘流血近1小时:用了一包400张抽纸
- 每日报道:6月13日华鲁恒升尿素价格暂稳
- 烟台大学附属中学石明校区举行垃圾分类科普讲座|天天时快讯
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
天天观察:Android RIL&IMS源码分析
一、需求
1、了解IMS相关知识体系2、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 进行升级。
三、环境
- 芯片:高通Qcm2290
- 版本:Android 11
四、设计思路
4.1 RIL结构图
4.2 RIL相关模块介绍
模块 | 进程 | 介绍 |
---|---|---|
Dialer | com.android.dialer | 负责拨号、呼叫界面显示 |
TeleService | com.android.phone | 负责通话逻辑,如实际向RIL拨号、挂电话,及电话状态如拨号、振铃、接通等的变更。 |
TelecomService | system_server | 负责逻辑控制,是沟通各个进程交互的桥梁。 |
telephony-common(RILJ) | jar,看哪个进程引用,主要是com.android.phone | 主要是phone模块,hal层对应的java层客户端的代码,这个模块的代码就是跟hal下面的C/C++服务进行通信的 |
RILD | RILD | 主要负责接发RILJ指令、Modem指令 |
MODEM | Modem | Modem是调制解调器的缩写,它是一种用于数字信号和模拟信号之间转换的设备。在手机中,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 /* ABI override */, 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\telephonytelephony-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\telecommandroid提供的phone的一些sdk的代码,最终编译完成打包进framework.jarLINUX\android\frameworks\base\Android.bp
filegroup { name: "framework-telecomm-sources", 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\telephonyandroid提供的phone的一些sdk的代码,最终编译完成打包进framework.jarLINUX\android\frameworks\base\Android.bp
filegroup { name: "framework-telephony-sources", 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\rilRIL模块由rild守护进程、libril.so、librefrence.so三部分组成:
4.2.7.1 RILD守护进程
源码:LINUX\android\hardware\ril\rildRILD主要起到承上启下的作用,作为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\librillibril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息送给调用进程
4.2.7.3 librefrence共享库
源码:LINUX\android\hardware\ril\reference-rillibrefrence_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\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)绑定InCallServiceInCallServiceImpl是InCallService的子类,在Dialer进程,而TelecomService进程与InCallServiceImpl也是通过bind实现跨进程通信。
@LINUX\android\packages\services\Telecomm\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 /* forFullScreen */); activityIntent.putExtra(TouchPointManager.TOUCH_POINT, touchPoint); context.startActivity(activityIntent); }
5.2.3 广播下发消息
TelecomService进程发出一个定向广播,由TelecomService进程中的NewOutgoingCallBroadcastIntentReceiver对象接收。(1)TelecomService进程发送广播
@LINUX\android\packages\services\Telecomm\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\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)绑定TeleServicebinder绑定TeleService服务,实现跨进程通信,同时将将拨号请求分发给TeleService进程,由TeleService进程继续处理
@LINUX\android\packages\services\Telecomm\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\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
5.3.4 TeleService拨号请求下发(GsmCdmaPhone)
在teleService会获取当前呼叫的phone对象,如GsmCdmaPhone、ImsPhone、SipPhone,来决定要从用哪一种通讯方式进行呼叫。
@LINUX\android\packages\services\Telephony\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 /* isEmergencyCall */, null /* not an emergency call */);//获取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\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层发送指令 ... /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ 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) { /* no command pending */ 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_SMS | CDMA发送短信 |
RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE | CDMA短信消息的传送应答 |
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_CONFIG | CDMA获取小区广播配置 |
RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG | CDMA设置小区广播配置 |
RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION | CDMA小区广播开关 |
RIL_REQUEST_CDMA_SUBSCRIPTION | 查询CDMA的实现模式(CDMA手机两实现模式:机卡分离式:用户信息写在单独的UIM卡机卡一体式:用户信息写在手机中的) |
RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM | CDMA复制短息到uim卡,RUIM是应用在CDMA2000手机的一种智能卡 |
RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM | CDMA删除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_AUTHENTICATION | ISIM认证 |
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_AUTHENTICATION | SIM卡身份认证 |
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_REFRESH | modem请求更新卡对应的文件信息 |
RIL_UNSOL_CALL_RING | 有来电时上报 |
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED | SIM卡状态改变 |
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_CONNECTED | RIL连接成功通知 |
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_RESTART | modem重启通知 |
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-cnhttp://www.taodudu.cc/news/show-3144813.html?action=onClickhttp://baike.jld5.cn/news/51009.htmlhttps://wiki.mbalib.com/wiki/IMShttps://blog.csdn.net/guyuewangyue/article/details/122866358电路交换和分组交换区别:https://www.elecfans.com/d/1308634.htmlTeleComService介绍:https://blog.csdn.net/qq_40587575/article/details/113753895TeleService介绍:https://www.jianshu.com/p/ff51295b84a1Rild介绍:https://www.freesion.com/article/21011164222/https://blog.csdn.net/u014386544/article/details/52594400RIL指令:https://www.mianshigee.com/note/detail/23890yjg/https://blog.csdn.net/iteye_6233/article/details/82230745https://blog.csdn.net/u010961631/article/details/9446377/https://blog.csdn.net/sjz4860402/article/details/51182078http://www.2sim.cn/article/13https://zhuanlan.zhihu.com/p/117218424https://blog.csdn.net/u014386544/article/details/56851616
关键词:
天天观察:Android RIL&IMS源码分析
天天即时:5款超级好用的开发效率工具,建议收藏!
世界观点:记录--为什么推荐用svg而不用icon?
油价小幅下调 加一箱油将少花2元 全球最资讯
惠誉博华:48家银行未赎回二级资本债券,合计达364.8亿元
恒生指数收涨0.6% 恒生科技指数大涨重回4000点上方
中海达(300177)6月13日主力资金净买入525.51万元_天天通讯
PMR机械硬盘走到尽头了!西数/希捷正疯狂自救
6旬老人守株待兔式飞奔撞车碰瓷索赔 车主吓坏:监控还清白 环球精选
广东有多热?网友在广东买虾 还没到家就熟了 世界今日讯
美国再将31家中企列入“实体清单”!
2999元的国产显卡值不值得冲?实测3A大作给你答案
焦点信息:天津:“多卡合一”创新服务“城市小蜜蜂”
今日热文:线段树学习笔记
每日速看!尚医通-day10【微信扫码登录】(内附源码)
linux iptables安全技术与防火墙_快播报
收评:创业板指涨0.68%收获三连阳 半导体行业涨幅靠前
全球快报:小米卢伟冰:小米13 Ultra在意法西德及香港地区正式开售 销售超预期
首发预装鸿蒙OS 4.0!华为Mate60 Pro概念图出炉 全球热资讯
天天精选!NASA决定造访遍地黄金的“灵神星”:平均每位美国人能分300亿美元
美系硬派SUV福特探险者谍照曝光!外观内饰全面升级 预计将在年内首次亮相_今日热讯
今日热搜:8GB显卡卖到3199元 显存成本曝光:英伟达实在太赚了
视点!男生抠掉脸上痘痘流血近1小时:用了一包400张抽纸
每日报道:6月13日华鲁恒升尿素价格暂稳
焦点信息:市场监管总局:瞄准先进材料、人工智能等领域推动建立国家标准参考数据中心
烟台大学附属中学石明校区举行垃圾分类科普讲座|天天时快讯
速递!8GB内存笔记本卖到10499元起 苹果被批吃相难看:应该破发
货车高速上连续疯狂别车被撞停 官方:未造成伤亡、已找到肇事者|当前播报
天天热讯:马斯克相中的男人!14岁成SpaceX最年轻工程师、岗位年薪百万
环球即时看!小米平板6 Pro两个月使用心得:找不到短板的安卓板皇
Arm发布全新智能视觉参考设计 首次整合第三方IP核心
2023安洵杯 re复现
每天一道面试题:Spring的Bean生命周期
Axure RP教程_编程入门自学教程_菜鸟教程-免费教程分享_环球今日讯
环球今日报丨哥伦比亚4名空难获救儿童的母亲生前或遭家暴,孩子外公和父亲欲争夺抚养权
当前关注:你收益多少?余额宝上线第十年:每天为国人赚1亿零花钱 网友狂晒单
排队5小时!浙江网红面包黄牛加价上百元 网友吐槽:消协回应
【当前独家】中轴线文化遗产有了常设讲堂
三种方法让.NET轻松实现Excel转PDF
天天快看点丨docker-compose搭建wordpress
【播资讯】比亚迪执行副总裁:美国市场不在我们考虑范围内
石家庄迈入“刷脸”乘车时代:买一根火腿肠就能免费坐地铁活动结束了_环球动态
制作成本16.5亿!《封神三部曲》第一部7月20上映:角色海报公布 太强大 今日报
吹牛还是玩真的?丰田下一代电动汽车续航达1500公里
【天天报资讯】小米发布米家旅行箱:顶部嵌平设计 行走的小桌板
市场监管总局:到2035年 计量数据归集共享规模显著提升-快播
【技术积累】软件设计模式中的工厂模式【一】-独家
STM32F429 Discovery开发板应用:使用FreeRTOS队列+DMA双缓存实现串口数据接收
【寻味中华丨饮食】蔡甸藕带:白若玲珑玉 丝缕皆故乡
【天天时快讯】699元!XREAL Beam投屏盒子发布:随身携带的“可悬停AR空间屏”
AMD今晚发布新CPU Intel急了:至强性能比EPYC快7倍
【世界新视野】4-1战胜热火!掘金队夺队史首个NBA总冠军:网友发帖祝贺 约老师太强
小区门口连装8条减速带 物业回复让业主无语:为防业主逃费
贵1000元值不值?i7-13700H和i5-13500H对比实测 世界观点
我在塞尔维亚寻找约基奇-每日速递
全球微速讯:“铁榔头”郎平重返中学校园,为学弟学妹成长“支招”
世界最新:深度学习应用篇-推荐系统[11]:推荐系统的组成、场景转化指标(pv点击率,uv点击率,曝光点击率)、用户数据指标等评价指标详解
flutter 日志打印三種方法
最新:Linux根文件制作
热推荐:一对一直播源码平台搭建的关键条件,成败在此。
真刑!几行代码端了整个教务系统。。
启明星辰(002439)6月12日主力资金净卖出1310.11万元
长安欧尚Z6新能源半年降价3万多被集体投诉 车主:坑惨我们了
每日热讯!2折!115网盘618大促:10年VIP只要1000元 赠100TB空间
全脂/低脂可选:特仑苏纯牛奶2.7元/盒抄底(商超6元)
腾势N7赛道远超宝马X3 赵长江:意向客户看到展车后几乎全下单了
Fold5、Flip5换壳!三星W24系列折叠屏手机通过认证:25W快充
吴尚垠 吴尚_每日消息
JAVA非递归生成无限级菜单树的较简代码实现。(非泛用型工具包,仅总结逻辑)
每日关注!低代码开发平台为数智赋能,让开发变得更简单
奶我一口是什么意思网络用语_奶你一口是什么意思简介介绍
腾讯祭出的大招《无畏契约》 能不能成为下一个《英雄联盟》?-环球微速讯
环球观点:最大内存+最美拍照手机!小米Civi 3 1TB上市:2999元
当前消息!满级玩家有盼头了 暗黑世界V等你来
28.98万起 智己LS7都市版上市 CEO刘涛:现在买增程过几年就会焦虑 每日热点
男子洗澡被闯入的两匹“狼”吓坏 经辨认是阿拉斯加 焦点精选
C天键(301383)6月12日主力资金净买入2791.69万元 焦点快看
【当前独家】hvv面试常见框架漏洞
天天热头条丨ldquo 以至 rdquo ldquo 以致 rdquo ldquo 以至于 rdquo 与 ldquo 以致于 rdquo 的区别
蔚来降价3万!李斌:买的起2、30万车的人时间成本很高 时薪200元肯定是有的-世界播报
世界即时:仇恨拉满!日本核污水排放在即 韩国人正疯狂买盐:不敢吃海鲜了
三冠王巡游!曼城全队展示三座奖杯 哈兰德赤膊上阵 城迷疯狂庆祝
每日快报!暂停加息预期支撑多头 美债市场周初表现偏强
微资讯!英伟达市占率超83% 显卡降不降价我说了算!4060系列买到偷着乐?
希捷被重罚3亿美元后!消息称华为不缺硬盘、SSD了:西数持续供货中_每日资讯
十多年了 苹果新款Mac Pro依然不是中国制造:美泰联手组装
芬兰加入北约的军事协调工作结束 双方签署声明 速读
每日速读!读发布!设计与部署稳定的分布式系统(第2版)笔记01_生产环境的生存法则
大家超爱看黑美鱼?《小美人鱼》卖座成2023票房TOP10:国内外口碑两极分化
焦点简讯:漫威等大片国人不爱看了 不符合审美!郭帆:中国电影将弯道超车好莱坞
环球微速讯:香干怎么做比较好吃?
靠给肯德基、麦当劳供货的纸袋大王上市:创始人身价近12亿
一个月3家公司退出:日本手机产业无奈 打不过苹果也打不过小米-世界新消息
天天新动态:618降价英雄:大屏电视跌破2000元该如何买?
绝不降价的蔚来全系降3万!李斌被逼得没辙了
夸克App半夜突然上热搜 网友懵了:没广告很好用
全球报道:鲁葱杂5号_关于鲁葱杂5号简述
开远市气象台发布暴雨蓝色预警信号【Ⅳ级/一般】【2023-06-12】|每日速读
微控制器实时操作系统实践4选择正确的MCU 每日报道
全球短讯!.NET 5 以后的 HttpClient 超时问题