OpenHarmerny 短彩信之Framework系统源码解析 原创 精华
作者:黄子轰
简介
短彩信系统框架层,以OpenHarmerny SystemAbility 系统常驻服务,为上层提供JS API 接口,下层适配不同硬件厂商Modem。提供短彩信系统框架功能业务,提供短信收发和彩信编解码基础能力;主要功能有GSM/CDMA短信收发、短信PDU(Protocol data unit,协议数据单元)编解码、Wap Push接收处理 、小区广播接收、彩信通知、 彩信编解码和SIM卡短信记录增删改查等。
架构图
Framework框架图
短彩信服务通过safwk组件实现SystemAbility 注册、启动等相关接口;短彩信Framework由接口管理类、短信发送管理类、短信接收管理类,和彩信编解码工具类组成。
- 接口管理类:SmsInterfaceManager 负责对外提供短信发送、SIM卡短信记录操作和配置相关接口,负责创建SmsSendManager 、SmsReceiveManager和smsMiscManager 对象。
- 短信发送管理类: SmsSendManager创建GSM(GsmSmsSender) 、CDMA(CdmaSmsSender) 和网络策略管理(SmsNetworkPolicyManager)对象,并根据网络制式调度对应的GSM或CDMA对象发送短信。
- 短信接收管理类: SmsReceiveManager 负责短信接收,监听来自RIL层的新短信信息;创建GSM(GsmSmsReceiveHandler) 和CDMA(CdmaSmsReceiveHandler) 对象;创建SmsWapPushHandler 和SmsCellBroadcastHandler 对象。
- 彩信编解码类:负责彩信PDU的编解码处理。
- Misc管理类:负责Sim卡短信操作、小区广播配置、短信服务中心地址配置和默认卡槽配置等
代码结构
Interfaces对外提供暴露接口,包括JS 接口定义,napi native C++ 的JS接口封装;frameworks 包括Native 接口定义和彩信编解码对外暴露的工具; sa_profile 提供SystemAbility 启动配置文件; sercives 包含了短信框架内部服务相关代码包括Gsm/Cdma Pdu 编解码工具和接收处理业务逻辑代码。
参考文档路径:
https://gitee.com/openharmony/telephony_sms_mms
发送短信时序图
应用程序调用API发送短信,经过参数判断、鉴权、长短信拆分、PDU编码;添加到发送队列,调用RIL发送短信接口发送短信到接收端。并将发送状态返回应用调用者,完成一次短信发送过程。
-
上层应用调用发送短信的API JS接口,调用JS Napi 接口;
-
JS Napi 调用Native 层C++ SendMessage 跨IPC 到SmsInterfaceManager对象;
-
SmsInterfaceManager根据过滤策略来过滤掉短信和参数合法性检查;
-
SmsInterfaceManager进行鉴权检查;
-
SmsInterfaceManager调用TextBasedSmsDelivery或TextBasedSmsDelivery到SmsSendManager;
-
SmsSendManager调用搜网服务来获取SIM卡和网络状态;
-
GSM网络将创建GsmSmsSender,CDMA网络将创建CdmaSmsSender;
-
GsmSmsSender或CdmaSmsSender将短信拆分并进行PDU编码然后放到队列中;
-
通过接口将短信发送到RIL层;
-
如果返回的状态失败将启动重发机制;
-
返回应用层发送的状态信息;
发送短信时序图
短信接收时序图
-
SmsReceiveManager创建GsmSmsReceiveHandler和CdmaSmsReceiveHandler;
-
GsmSmsReceiveHandler和CdmaSmsReceiveHandler分别注册事件到RIL层;
-
RIL Adapter上报短信事件;
-
GsmSmsReceiveHandler或CdmaSmsReceiveHandler调用SmsBaseMessage解析PDU数据。
-
GsmSmsReceiveHandler和CdmaSmsReceiveHandler过滤无效短信;根据PDU头部信息将多段消息合并;
-
拦截黑名单短信;
-
将接收处理状态应答到RIL;
-
广播发送接收处理的短信信息到广播接收者;
接收短信时序图
代码分析
1.SmsService 启动
服务入口类 SmsService.cpp 继承safwk组件的SystemAblility类;由SA系统服务管理框架(samgr)拉起服务。采用telephony.cfg + profile.xml + libtel_sms_mms.z.so的方式由init进程执行对应的telephony.cfg文件拉起SmsService SystemAbility对应的telephony进程,并执行void SmsService::OnStart()
2.模块初始化
SmsService 服务启动后,调用OnStart() 函数;并创建服务内部类,初始化内部资源,包括SmsInterfaceManager、SmsSendManager、SmsReceiveManager 对象创建和初始化
3.服务对外提供Native IPC 接口实现
SmsService.cpp 继承SmsInterfaceStub.cpp ;SmsInterfaceStub 是native层对外接口IPC服务端代码,继承了并实现了IPC 对外接口ISmsServiceInterface用于跨进程对外提供navtive C++ API 接口; OnRemoteRequest() 是服务端的请求入口,通过请求Id 遍历memberFuncMap_ 调用对应的实现方法
4.多卡方案实现
根据卡槽数量创建对应的SmsInterfaceManager 对象,并用slotSmsInterfaceManagerMap_管理;服务启动后会调用InitModule() 方法并根据卡槽数量创建多个SmsInterfaceManager每个SmsInterfaceManager对象代码每一个卡槽。
5.短信发送流程
JS 发送短信接口 function sendMessage(options: SendMessageOptions): void, 位于sms_mms/interfaces/kits/js/@ohos.telephony.sms.d.ts 会调用位于sms_mms/frameworks/js/napi/src/napi_sms.cpp Napi 封装的SendMessage发送短信接口
SendMessage 最终会调用 sms_mms/frameworks/js/napi/src/napi_sms.cpp ActuallySendMessage函数; ActuallySendMessage 调用Native C++ 提供发送短信的单例类SmsServiceManagerClient 这个类是现实了OpenHarmony系统IPC 通讯框架的客户端;用于C/S架构与SmsService 服务通讯。SmsServiceManagerClient SendMessage() 接口需要两个回调对象分别是SendCallback和DeliveryCallback 用于返回服务发送短信的状态结果回调
通过SmsServiceManagerClient 的SendMessage 调用最终会通过IPC 调用到 sms_mms/services/sms_interface_stub.cpp 的OnRemoteRequest() 函数,通过定义的codeId 从memberFuncMap_ 遍历出OnSendSmsTextRequest() 方法并执行;OnSendSmsTextRequest主要是IPC数据的反序列号并调用SmsService 实现的SendMessage()方法
SmsInterfaceManager 对象TextBasedSmsDelivery 用于发送短信接口调用SmsSendManager对象的 TextBasedSmsDelivery();根据当前sloidId 卡的网络状态 调用Gsm 或者Cdma 来进一步发送短信处理
Gsm或者Cdma 长短信分段和PDU的编码过程,入口函数GsmSmsSender::TextBasedSmsDelivery()或者CdmaSmsSender::TextBasedSmsDelivery() 并构造SmsSendIndexer 对象添加到Map队列中,并调用CoreService 提供的发送短信接口发送,等待发送结果;拿Gsm制式的来分析,代码如下
6.短信下发到core_service、ril_adapter源码分析
参考文档路径:
https://gitee.com/openharmony/telephony_core_service
https://gitee.com/openharmony/telephony_ril_adapter
由于core_service服务和短彩信服务在同一个进程中,所以我们通过CoreManagerInner::GetInstance()来获取核心服务的单例对象,调用SendGsmSms或SendCdmaSms函数发送短信。
SendGsmSms函数将eventId、refId和handler对象封装到response对象中再转发到telRilManager的SendGsmSms函数。
TelRilManager::SendGsmSms里面只有一个TaskSchedule函数调用,其实TaskSchedule是个模板函数,就是为了统一下所有任务调用。
这个模板函数最终会调用TelRilSms::SendGsmSms并且将response插入到函数的最后一个参数中。
在TelRilSms::SendGsmSms函数中我们调用CreateTelRilRequest来将serialId、response和HREQ_SMS_SEND_GSM_SMS等保存到一个map中方便我们后续将短信发送的状态上报到短彩信服务中。下面MessageParcel data将pdu、smscpdu、serialId序列化到data中,最后通过cellularRadio_->SendRequest通过IPC将数据发送到ril_adapter服务中。
进入Ril层我们分析services\hril_hdf\src\hril_hdf.c这个文件,hril_hdf.c是ril_adapter层加载vendor库、注册发送和响应函数、启动读写线程、事件调度的入口。
我们看到.Dispatch = RilAdapterDispatch说明事件调度入口就是进入RilAdapterDispatch函数。RilAdapterDispatch函数里面主要加互斥锁调用DispatchRequest(cmd, data)这个事件分发最终调用到hril_sms文件的HRilSms::SendGsmSms函数。
HRilSms::SendGsmSms函数将core_service发送下来的数据反序列化到struct GsmSmsMessageInfo message中,最后调用RequestWithStrings函数。最后将数据转发到vendor库的at_sms.c文件的ReqSendGsmSms函数
ReqSendGsmSms函数将AT指令下发到modem并且将发送的状态上报。上报流程和下发流程类似不做具体分析。
7.短信上报ril_adapter、core_service源码分析
首先打开vendor_adapter.c我们可以看到EventListeners函数。
EventListeners中主要是ATStartReadLoop函数将创建一个线程读取modem上报的内容,在OnNotifyOps中短信上报内容是AT +CMT指令。将调用到OnSmsReport函数。
OnReport最终会调到hril_manager.c中的OnSmsReport函数
在OnReport函数中查找notiMemberFuncMap的HNOTI_SMS_NEW_SMS对应的函数指针。
在NewSmsNotify函数我们主要将短信PDU、ID、类型序列化通过IPC上传到core_service。core_service在收到上报数据也只是转发到短彩信服务,这部分内容自行分析即可。
8.JS 发送短信示例
更多原创内容请关注:深开鸿技术团队
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建OpenHarmony生态。
感谢老师用心分享。