
一、简介
二、基础知识
1. 短彩信框架图

2.代码结构
Interfaces 对外提供暴露接口,包括 JS 接口定义,napi native C++ 的 JS 接口封装;frameworks 包括 Native 接口定义和彩信编解码对外暴露的工具;sa_profile 提供 SystemAbility 启动配置文件;sercives 包含了短信框架内部服务相关代码包括 Gsm/Cdma Pdu 编解码工具和接收处理业务逻辑代码。
/base/telephony/sms_mms├─ frameworks # 短彩信内部框架接口层├─ interfaces # 对外暴露的接口│ ├─ innerkits│ └─ kits├─ sa_profile # 启动配置文件├─ services # 服务内部代码│ ├─ include # 头文件目录│ ├─ cdma # CDMA制式源文件│ └─ gsm # GSM制式源文件├─ test # 单元测试目录└─ utils # 通用工具相关
3. 电话子系统(sms) 核心类

4. 短信发送时序图
1. 上层应用调用发送短信的 API JS 接口,调用 JS Napi 接口;
2. JS Napi 调用 Native 层 C++ SendMessage 跨 IPC 到 SmsInterfaceManager 对象;
3. SmsInterfaceManager 根据过滤策略来过滤掉短信和参数合法性检查;
4. SmsInterfaceManager 进行鉴权检查;
5. SmsInterfaceManager 调用 TextBasedSmsDelivery 或 TextBasedSmsDelivery 到 SmsSendManager;
6. SmsSendManager 调用搜网服务来获取 SIM 卡和网络状态;
7. GSM 网络将创建 GsmSmsSender,CDMA 网络将创建 CdmaSmsSender;
8. GsmSmsSender 或 CdmaSmsSender 将短信拆分并进行 PDU 编码然后放到队列中;
9. 通过接口将短信发送到 RIL 层;
10. 如果返回的状态失败将启动重发机制;
11. 返回应用层发送的状态信息;

5. 短信接收时序图

6. 相关仓
https://gitee.com/openharmony/telephony_sms_mms
https://gitee.com/openharmony/telephony_core_service
https://gitee.com/openharmony/telephony_ril_adapter
三、源码解析
1. SmsService 启动
class SmsService : public SystemAbility, public SmsInterfaceStub {DECLARE_DELAYED_SINGLETON(SmsService)DECLARE_SYSTEM_ABILITY(SmsService) // necessarypublic:void OnStart() override;void OnStop() override;private:constexpr static uint32_t CONNECT_SERVICE_WAIT_TIME = 2000; // msbool Init();bool registerToService_ = false;ServiceRunningState state_ = ServiceRunningState::STATE_NOT_START;};} // namespace Telephony} // namespace OHOS
2. 模块初始化
void SmsService::OnStart() {TELEPHONY_LOGI("SmsService::OnStart start service Enter.");if (state_ == ServiceRunningState::STATE_RUNNING) {TELEPHONY_LOGE("msService has already started.");return;}if (!Init()) {TELEPHONY_LOGE("failed to init SmsService");return;}state_ = ServiceRunningState::STATE_RUNNING;TELEPHONY_LOGI("SmsService::OnStart start service Exit.");}bool SmsService::Init(){if (!registerToService_) {WaitCoreServiceToInit();}return true;}//等待核心服务完成初始化,并调用InitModule 初始化内部内部代码void SmsService::WaitCoreServiceToInit(){std::thread connectTask([&]() {while (true) {TELEPHONY_LOGI("connect core service ...");if (CoreManagerInner::GetInstance().IsInitFinished()) {InitModule();TELEPHONY_LOGI("SmsService Connection successful");break;}std::this_thread::sleep_for(milliseconds(CONNECT_SERVICE_WAIT_TIME));}});connectTask.detach();}
3. Native IPC 接口实现
int SmsInterfaceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option){int32_t result = 0;std::u16string myDescripter = SmsInterfaceStub::GetDescriptor();std::u16string remoteDescripter = data.ReadInterfaceToken();if (myDescripter == remoteDescripter) {auto itFunc = memberFuncMap_.find(code);if (itFunc != memberFuncMap_.end()) {auto memberFunc = itFunc->second;if (memberFunc != nullptr) {(this->*memberFunc)(data, reply, option);} else {TELEPHONY_LOGE("memberFunc is nullptr");}} else {TELEPHONY_LOGE("itFunc was not found");}} else {TELEPHONY_LOGE("descriptor checked fail");return result;}// 添加memberFuncMap 请求处理函数SmsInterfaceStub::SmsInterfaceStub(){memberFuncMap_[TEXT_BASED_SMS_DELIVERY] =&SmsInterfaceStub::OnSendSmsTextRequest;memberFuncMap_[DATA_BASED_SMS_DELIVERY] = &SmsInterfaceStub::OnSendSmsDataRequest;memberFuncMap_[SET_SMSC_ADDRESS] = &SmsInterfaceStub::OnSetSmscAddr;memberFuncMap_[GET_SMSC_ADDRESS] = &SmsInterfaceStub::OnGetSmscAddr;memberFuncMap_[ADD_SIM_MESSAGE] = &SmsInterfaceStub::OnAddSimMessage;memberFuncMap_[DEL_SIM_MESSAGE] = &SmsInterfaceStub::OnDelSimMessage;memberFuncMap_[UPDATE_SIM_MESSAGE] = &SmsInterfaceStub::OnUpdateSimMessage;memberFuncMap_[GET_ALL_SIM_MESSAGE] = &SmsInterfaceStub::OnGetAllSimMessages;memberFuncMap_[SET_CB_CONFIG] = &SmsInterfaceStub::OnSetCBConfig;memberFuncMap_[SET_DEFAULT_SMS_SLOT_ID] = &SmsInterfaceStub::OnSetDefaultSmsSlotId;memberFuncMap_[GET_DEFAULT_SMS_SLOT_ID] = &SmsInterfaceStub::OnGetDefaultSmsSlotId;memberFuncMap_[SPLIT_MESSAGE] = &SmsInterfaceStub::OnSplitMessage;memberFuncMap_[GET_SMS_SEGMENTS_INFO] = &SmsInterfaceStub::OnGetSmsSegmentsInfo;memberFuncMap_[GET_IMS_SHORT_MESSAGE_FORMAT] = &SmsInterfaceStub::OnGetImsShortMessageFormat;memberFuncMap_[IS_IMS_SMS_SUPPORTED] = &SmsInterfaceStub::OnIsImsSmsSupported;memberFuncMap_[HAS_SMS_CAPABILITY] = &SmsInterfaceStub::OnHasSmsCapability;}
4. 多卡方案实现
服务启动后会调用 InitModule() 方法并根据卡槽数量创建多个 SmsInterfaceManager 每个 SmsInterfaceManager 对象代码每一个卡槽。
void SmsInterfaceStub::InitModule() {static bool bInitModule = false;if (!bInitModule) {bInitModule = true;std::lock_guard<std::mutex> lock(mutex_);for (int32_t slotId = 0; slotId < SIM_SLOT_COUNT; ++slotId) {slotSmsInterfaceManagerMap_[slotId] = std::make_shared<SmsInterfaceManager>(slotId);if (slotSmsInterfaceManagerMap_[slotId] == nullptr) {return;}slotSmsInterfaceManagerMap_[slotId]->InitInterfaceManager();TELEPHONY_LOGI("SmsInterfaceStub InitModule slotId = %{public}d",slotId);}}}
5. 短信发送流程
JS 调用发送短信示例代码, 导入 SDK sms 包并构造 SendMessageOptions 对象参数。
import sms from "@ohos.telephony.sms"; //导入短彩信包let msg: SendMessageOptions = {slotId: 0,destinationHost: '123xxxxxxxx',content: '这是一封短信',sendCallback: (err, data) => {if (err) {// 接口调用失败,err非空console.error(`failed to send message because ${err.message}`);return;}// 接口调用成功,err为空console.log(`success to send message: ${data.result}`);}}// 调用接口sms.sendMessage(msg);
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 发送短信接口。
static napi_value SendMessage(napi_env env, napi_callback_info info){size_t parameterCount = 1;napi_value parameters[1] = {0};napi_value thisVar = nullptr;void *data = nullptr;napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data);int32_t messageMatchResult = MatchSendMessageParameters(env, parameters,parameterCount);NAPI_ASSERT(env, messageMatchResult != MESSAGE_PARAMETER_NOT_MATCH, "type mismatch");auto asyncContext = std::make_unique<SendMessageContext>().release();if (asyncContext == nullptr) {std::string errorCode = std::to_string(napi_generic_failure);std::string errorMessage = "error at SendMessageContext is nullptr";NAPI_CALL(env, napi_throw_error(env, errorCode.c_str(), errorMessage.c_str()));return nullptr;}ParseMessageParameter(messageMatchResult, env, parameters[0], *asyncContext);napi_create_reference(env, thisVar, DEFAULT_REF_COUNT, &asyncContext->thisVarRef);napi_value resourceName = nullptr;napi_create_string_utf8(env, "SendMessage", NAPI_AUTO_LENGTH, &resourceName);napi_create_async_work(env, nullptr, resourceName, NativeSendMessage, SendMessageCallback,(void *)asyncContext, &(asyncContext->work));napi_queue_async_work(env, asyncContext->work);return NapiUtil::CreateUndefined(env);}
SendMessage 最终会调用 sms_mms/frameworks/js/napi/src/napi_sms.cpp ActuallySendMessage 函数;
ActuallySendMessage 调用 Native C++ 提供发送短信的单例类 SmsServiceManagerClient 这个类是现实了 OpenHarmony 系统 IPC 通讯框架的客户端;
用于 C/S 架构与 SmsService 服务通讯。SmsServiceManagerClient SendMessage() 接口需要两个回调对象分别是 SendCallback 和 DeliveryCallback 用于返回服务发送短信的状态结果回调。
static bool ActuallySendMessage(napi_env env, SendMessageContext ¶meter){std::unique_ptr<SendCallback> sendCallback =std::make_unique<SendCallback>(hasSendCallback, env, parameter.thisVarRef, parameter.sendCallbackRef);std::unique_ptr<DeliveryCallback> deliveryCallback = std::make_unique<DeliveryCallback>(hasDeliveryCallback, env, parameter.thisVarRef, parameter.deliveryCallbackRef);//文本类型的短信if (parameter.messageType == TEXT_MESSAGE_PARAMETER_MATCH) {int32_t sendResult = DelayedSingleton<SmsServiceManagerClient>::GetInstance()->SendMessage(parameter.slotId, parameter.destinationHost, parameter.serviceCenter, parameter.textContent,sendCallback.release(), deliveryCallback.release());TELEPHONY_LOGI("NativeSendMessage SendTextMessage execResult = %{public}d", sendResult);}// 数据类型的短信else if (parameter.messageType == RAW_DATA_MESSAGE_PARAMETER_MATCH) {if (parameter.rawDataContent.size() > 0) {uint16_t arrayLength = static_cast<uint16_t>(parameter.rawDataContent.size());int32_t sendResult = DelayedSingleton<SmsServiceManagerClient>::GetInstance()->SendMessage(parameter.slotId, parameter.destinationHost, parameter.serviceCenter,parameter.destinationPort, ¶meter.rawDataContent[0],arrayLength, sendCallback.release(), deliveryCallback.release());TELEPHONY_LOGI("NativeSendMessage SendRawDataMessage execResult = %{public}d", sendResult);}}return false;}//Native C++ 发送短信接口函数int32_t SmsServiceManagerClient::SendMessage(int32_t slotId, const std::u16string desAddr,const std::u16string scAddr, const std::u16string text, const sptr<ISendShortMessageCallback> &callback,const sptr<IDeliveryShortMessageCallback> &deliveryCallback){if (InitSmsServiceProxy()) {smsServiceInterface_->SendMessage(slotId, desAddr, scAddr, text, callback, deliveryCallback);TELEPHONY_LOGI("execute SendMessage\n");return ERROR_NONE;}return ERROR_SERVICE_UNAVAILABLE;}// InitSmsServiceProxy 用于初始化与SmsService IPC 通许连接工作bool SmsServiceManagerClient::InitSmsServiceProxy(){if (smsServiceInterface_ == nullptr) {std::lock_guard<std::mutex> lock(mutex_);sptr<ISystemAbilityManager> systemAbilityManager =SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();if (!systemAbilityManager) {TELEPHONY_LOGE(" Get system ability mgr failed.");return false;}sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(TELEPHONY_SMS_MMS_SYS_ABILITY_ID);if (!remoteObject) {TELEPHONY_LOGE("Get SMS Service Failed.");return false;}smsServiceInterface_ = iface_cast<ISmsServiceInterface>(remoteObject);if ((!smsServiceInterface_) || (!smsServiceInterface_->AsObject())) {TELEPHONY_LOGE("Get SMS Service Proxy Failed.");return false;}recipient_ = new SmsServiceInterfaceDeathRecipient();if (!recipient_) {TELEPHONY_LOGE("Failed to create death Recipient ptr SmsServiceInterfaceDeathRecipient!");return false;}smsServiceInterface_->AsObject()->AddDeathRecipient(recipient_);}return true;}
通过 SmsServiceManagerClient 的 SendMessage 调用最终会通过 IPC 调用到 sms_mms/services/sms_interface_stub.cpp 的 OnRemoteRequest() 函数;
通过定义的 codeId 从 memberFuncMap_ 遍历出 OnSendSmsTextRequest() 方法并执行;
OnSendSmsTextRequest 主要是 IPC 数据的反序列号并调用 SmsService 实现的 SendMessage() 方法。
void SmsInterfaceStub::OnSendSmsTextRequest(MessageParcel &data, MessageParcel &reply, MessageOption &option){int32_t result = 0;sptr<ISendShortMessageCallback> sendCallback = nullptr;sptr<IDeliveryShortMessageCallback> deliveryCallback = nullptr;int32_t slotId = data.ReadInt32();u16string desAddr = data.ReadString16();u16string scAddr = data.ReadString16();u16string text = data.ReadString16();sptr<IRemoteObject> remoteSendCallback = data.ReadRemoteObject();sptr<IRemoteObject> remoteDeliveryCallback = data.ReadRemoteObject();if (remoteSendCallback != nullptr) {sendCallback = iface_cast<ISendShortMessageCallback>(remoteSendCallback);}if (remoteDeliveryCallback != nullptr) {deliveryCallback = iface_cast<IDeliveryShortMessageCallback>(remoteDeliveryCallback);}TELEPHONY_LOGI("MessageID::TEXT_BASED_SMS_DELIVERY %{public}d", slotId);SendMessage(slotId, desAddr, scAddr, text, sendCallback, deliveryCallback);reply.WriteInt32(result);}void SmsService::SendMessage(int32_t slotId, const u16string desAddr, const u16string scAddr,const u16string text, const sptr<ISendShortMessageCallback> &sendCallback,const sptr<IDeliveryShortMessageCallback> &deliveryCallback){// 权限校验if (!TelephonyPermission::CheckPermission(Permission::SEND_MESSAGES)) {SmsSender::SendResultCallBack(sendCallback, ISendShortMessageCallback::SEND_SMS_FAILURE_UNKNOWN);TELEPHONY_LOGE("Check Permission Failed, No Has Telephony Send Messages Permisson.");return;}// 获取对应slotId 对应的SmsInterfaceManager 对象std::shared_ptr<SmsInterfaceManager> interfaceManager = GetSmsInterfaceManager(slotId);............interfaceManager->TextBasedSmsDelivery(StringUtils::ToUtf8(desAddr), StringUtils::ToUtf8(scAddr),StringUtils::ToUtf8(text), sendCallback, deliveryCallback);}
SmsInterfaceManager 对象 TextBasedSmsDelivery 用于发送短信接口调用 SmsSendManager 对象的 TextBasedSmsDelivery();根据当前 sloidId 卡的网络状态 调用 Gsm 或者 Cdma 来进一步发送短信处理。
void SmsSendManager::TextBasedSmsDelivery(const string &desAddr, const string &scAddr, const string &text,const sptr<ISendShortMessageCallback> &sendCallback,const sptr<IDeliveryShortMessageCallback> &deliveryCallback){......此处省略.....NetWorkType netWorkType = networkManager_->GetNetWorkType();TELEPHONY_LOGI("netWorkType = %{public}d.", netWorkType);if (netWorkType == NetWorkType::NET_TYPE_GSM) {gsmSmsSender_->TextBasedSmsDelivery(desAddr, scAddr, text, sendCallback, deliveryCallback);} else if (netWorkType == NetWorkType::NET_TYPE_CDMA) {cdmaSmsSender_->TextBasedSmsDelivery(desAddr, scAddr, text, sendCallback, deliveryCallback);} else {SmsSender::SendResultCallBack(sendCallback, ISendShortMessageCallback::SEND_SMS_FAILURE_SERVICE_UNAVAILABLE);TELEPHONY_LOGI("network unknown send error.");}}
Gsm 或者 Cdma 长短信分段和 PDU 的编码过程,入口函数 GsmSmsSender::TextBasedSmsDelivery()。
或者 CdmaSmsSender::TextBasedSmsDelivery() 并构造 SmsSendIndexer 对象添加到 Map 队列中,并调用 CoreService 提供的发送短信接口发送,等待发送结果;拿 Gsm 制式的来分析,代码如下:
void GsmSmsSender::TextBasedSmsDelivery(const string &desAddr, const string &scAddr, const string &text,const sptr<ISendShortMessageCallback> &sendCallback, const sptr<IDeliveryShortMessageCallback> &deliveryCallback){bool isMore = false;bool isStatusReport = false;int ret = 0;int headerCnt;int cellsInfosSize;unsigned char msgRef8bit;SmsCodingScheme codingType;GsmSmsMessage gsmSmsMessage;std::vector<struct SplitInfo> cellsInfos;// 长短信分段拆分gsmSmsMessage.SplitMessage(cellsInfos, text, CheckForce7BitEncodeType(), codingType);isStatusReport = (deliveryCallback == nullptr) ? false : true;std::shared_ptr<struct SmsTpdu> tpdu =gsmSmsMessage.CreateDefaultSubmitSmsTpdu(desAddr, scAddr, text, isStatusReport, codingType);....部分代码省略.........std::unique_lock<std::mutex> lock(mutex_);for (int i = 0; i < cellsInfosSize; i++) {std::shared_ptr<SmsSendIndexer> indexer = nullptr;std::string segmentText;segmentText.append((char *)(cellsInfos[i].encodeData.data()),cellsInfos[i].encodeData.size());....部分代码省略.........// 编码PDUstd::shared_ptr<struct EncodeInfo> encodeInfo = gsmSmsMessage.GetSubmitEncodeInfo(scAddr, isMore);if (encodeInfo == nullptr) {SendResultCallBack(indexer, ISendShortMessageCallback::SEND_SMS_FAILURE_UNKNOWN);TELEPHONY_LOGE("create encodeInfo encodeInfo nullptr error.");continue;}// 构造填充SmsSendIndexer对象SetSendIndexerInfo(indexer, encodeInfo, msgRef8bit);indexer->SetUnSentCellCount(unSentCellCount);indexer->SetHasCellFailed(hasCellFailed);SendSmsToRil(indexer);}}//判断是否是IMS网络域,调用CoreService 不同的接口进行发送void GsmSmsSender::SendSmsToRil(const shared_ptr<SmsSendIndexer> &smsIndexer){....部分代码省略.........GsmSimMessageParam smsData;smsData.refId = refId;smsData.smscPdu = StringUtils::StringToHex(smsIndexer->GetEncodeSmca());if (!isImsNetDomain_ && smsIndexer->GetPsResendCount() == 0) {uint8_t tryCount = smsIndexer->GetCsResendCount();if (tryCount > 0) {smsIndexer->UpdatePduForResend();}smsData.pdu = StringUtils::StringToHex(smsIndexer->GetEncodePdu());if (tryCount == 0 && smsIndexer->GetHasMore()) {TELEPHONY_LOGI("SendSmsMoreMode pdu len = %{public}zu", smsIndexer->GetEncodePdu().size());CoreManagerInner::GetInstance().SendSmsMoreMode(slotId_,RadioEvent::RADIO_SEND_SMS_EXPECT_MORE, smsData, shared_from_this());} else {TELEPHONY_LOGI("SendSms pdu len = %{public}zu", smsIndexer->GetEncodePdu().size());CoreManagerInner::GetInstance().SendGsmSms(slotId_,RadioEvent::RADIO_SEND_SMS, smsData, shared_from_this());}} else {TELEPHONY_LOGI("ims network domain send sms interface.!");smsIndexer->SetPsResendCount(smsIndexer->GetPsResendCount() + 1);smsData.pdu = StringUtils::StringToHex(smsIndexer->GetEncodePdu());if (smsIndexer->GetHasMore()) {CoreManagerInner::GetInstance().SendSmsMoreMode(slotId_,RadioEvent::RADIO_SEND_SMS_EXPECT_MORE, smsData, shared_from_this());} else {CoreManagerInner::GetInstance().SendGsmSms(slotId_,RadioEvent::RADIO_SEND_SMS, smsData, shared_from_this());}}}
6. 核心服务下发流程
由于 core_service 服务和短彩信服务在同一个进程中,所以我们通过 CoreManagerInner::GetInstance() 来获取核心服务的单例对象,调用 SendGsmSms 或 SendCdmaSms 函数发送短信。
int32_t CoreManagerInner::SendGsmSms(int32_t slotId, int32_t eventId, GsmSimMessageParam &gsmMessage,const std::shared_ptr<AppExecFwk::EventHandler> &handler){if (telRilManager_ == nullptr) {TELEPHONY_LOGE("telRilManager is null!");return TELEPHONY_ERR_LOCAL_PTR_NULL;}AppExecFwk::InnerEvent::Pointer response = AppExecFwk::InnerEvent::Get(eventId, gsmMessage.refId);response->SetOwner(handler);return telRilManager_->SendGsmSms(slotId, gsmMessage.smscPdu, gsmMessage.pdu, response);}
SendGsmSms 函数将 eventId、refId 和 handler 对象封装到 response 对象中再转发到 telRilManager 的 SendGsmSms 函数。
/*********************** TelRilNetwork end ****************************//*********************** TelRilSms start ******************************/int32_t TelRilManager::SendGsmSms(int32_t slotId, std::string smscPdu, std::string pdu, const AppExecFwk::InnerEvent::Pointer &response){return TaskSchedule(response, "TelRilSms", GetTelRilSms(slotId), &TelRilSms::SendGsmSms, smscPdu, pdu);}
TelRilManager::SendGsmSms 里面只有一个 TaskSchedule 函数调用,其实 TaskSchedule 是个模板函数,就是为了统一下所有任务调用。
template<typename ResponsePtr, typename ClassTypePtr, typename FuncType, typename... ParamTypes>inline int32_t TaskSchedule(ResponsePtr &_result, const std::string _module, ClassTypePtr &_obj,FuncType &&_func, ParamTypes &&..._args) const{if (_func != nullptr) {// The reason for using native member function access here is to// remove std::unique_ptr to prevent copying.// The reason for not directly using pointers to access member functions is:// _obj is a smart pointer, not a native pointer.return (_obj.*(_func))(std::forward<ParamTypes>(_args)..., _result);} else {TELEPHONY_LOGE("%{public}s - this %{public}p: %{public}s", _module.c_str(), &_obj, "null pointer");return HRIL_ERR_NULL_POINT;}}
这个模板函数最终会调用 TelRilSms::SendGsmSms 并且将 response 插入到函数的最后一个参数中。
int32_t TelRilSms::SendGsmSms(std::string &smsPdu, std::string &pdu, const AppExecFwk::InnerEvent::Pointer &response){std::shared_ptr<TelRilRequest> telRilRequest = CreateTelRilRequest(HREQ_SMS_SEND_GSM_SMS, response);if (telRilRequest == nullptr) {TELEPHONY_LOGE("telRilRequest is nullptr");return TELEPHONY_ERR_LOCAL_PTR_NULL;}TELEPHONY_LOGI("telRilRequest->serialId_:%{public}d", telRilRequest->serialId_);MessageParcel data;data.WriteInt32(slotId_);GsmSmsMessageInfo mGsmSmsMessageInfo = ConstructGsmSendSmsRequestLinkList(smsPdu, pdu);mGsmSmsMessageInfo.serial = telRilRequest->serialId_;mGsmSmsMessageInfo.Marshalling(data);MessageParcel reply;OHOS::MessageOption option = {OHOS::MessageOption::TF_ASYNC};if (cellularRadio_->SendRequest(HREQ_SMS_SEND_GSM_SMS, data, reply, option)) {TELEPHONY_LOGE("cellularRadio_->SendRequest fail");}return TELEPHONY_ERR_SUCCESS;}
在 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 库、注册发送和响应函数、启动读写线程、事件调度的入口。
static int32_t RilAdapterDispatch(struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply){int32_t ret;static pthread_mutex_t dispatchMutex = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_lock(&dispatchMutex);TELEPHONY_LOGI("RilAdapterDispatch cmd:%{public}d", cmd);ret = DispatchRequest(cmd, data);pthread_mutex_unlock(&dispatchMutex);return ret;}static struct IDeviceIoService g_rilAdapterService = {.Dispatch = RilAdapterDispatch,.Open = NULL,.Release = NULL,};
我们看到 .Dispatch = RilAdapterDispatch 说明事件调度入口就是进入 RilAdapterDispatch 函数。RilAdapterDispatch 函数里面主要加互斥锁调用 DispatchRequest(cmd, data) 这个事件分发最终调用到 hril_sms 文件的 HRilSms::SendGsmSms 函数。
int32_t HRilSms::SendGsmSms(struct HdfSBuf *data){struct GsmSmsMessageInfo message;MessageParcel *parcel = nullptr;const int32_t COUNT_STRINGS_VALUE = 2;if (SbufToParcel(data, &parcel)) {TELEPHONY_LOGE("RilAdapter failed to do SbufToParcel");return HRIL_ERR_INVALID_PARAMETER;}if (parcel == nullptr) {TELEPHONY_LOGE("parcel int32_t SendGsmSms is nullptr!");return HRIL_ERR_INVALID_PARAMETER;}if (!message.ReadFromParcel(*parcel)) {TELEPHONY_LOGE("RilAdapter failed to do ReadFromParcel!");return HRIL_ERR_INVALID_PARAMETER;}return RequestWithStrings(message.serial, HREQ_SMS_SEND_GSM_SMS, COUNT_STRINGS_VALUE, message.smscPdu.c_str(), message.pdu.c_str());}
HRilSms::SendGsmSms 函数将 core_service 发送下来的数据反序列化到 struct GsmSmsMessageInfo message 中,最后调用 RequestWithStrings 函数。最后将数据转发到 vendor 库的 at_sms.c 文件的 ReqSendGsmSms 函数。
void ReqSendGsmSms(const ReqDataInfo *requestInfo, const char *const *data, size_t dataLen){//省略非核心代码//向modem发送AT +CMGS指令err = SendCommandSmsLock(cmd, smsPdu, "+CMGS:", 0, &responseInfo);if (err != 0 || (responseInfo != NULL && !responseInfo->success)) {HandlerSmsResult(&response, &reportInfo, requestInfo, &err, responseInfo);return;}//获取发送后状态HandleResult(&err, result, responseInfo, &response);reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0);//上报发送后的状态OnSmsReport(GetSlotId(requestInfo), reportInfo, (const uint8_t *)&response, sizeof(HRilSmsResponse));FreeResponseInfo(responseInfo);}
ReqSendGsmSms 函数将 AT 指令下发到 modem 并且将发送的状态上报。上报流程和下发流程类似不做具体分析。
7. 核心服务主动上报
首先打开 vendor_adapter.c 我们可以看到 EventListeners 函数。
static void EventListeners(void){int32_t waitNextTryTime = SLEEP_TIME;const char *devicePath = DEVICE_PATH;char atTtyPath[PARAMETER_SIZE] = {0};usleep(DELAY_WAIT_MS); // Prevent slow loading of system properties.if (GetParameter(AT_TTY_PATH, "", atTtyPath, PARAMETER_SIZE) > 0) {devicePath = atTtyPath;}TELEPHONY_LOGI("opening AT interface %{public}s", devicePath);AtSetOnUnusual(AtOnUnusual);for (;;) {while (g_fd < 0) {if (devicePath != NULL) {g_fd = open(devicePath, O_RDWR);}if (g_fd >= 0 && !memcmp(devicePath, DEVICE_PATH_DEFAULT, sizeof(DEVICE_PATH_DEFAULT) - 1)) {struct termios ios;tcgetattr(g_fd, &ios);ios.c_lflag = 0;tcsetattr(g_fd, TCSANOW, &ios);}if (g_fd < 0) {TELEPHONY_LOGE("ril vendorlib,opening AT interface. retrying...");sleep(waitNextTryTime);}}g_atStatus = 0;int32_t ret = ATStartReadLoop(g_fd, OnNotifyOps);if (ret < 0) {TELEPHONY_LOGE("AtRead error %d\n", ret);return;}ModemInit();sleep(1);WaitAtClose();}}
EventListeners 中主要是 ATStartReadLoop 函数将创建一个线程读取 modem 上报的内容,在 OnNotifyOps 中短信上报内容是 AT +CMT 指令。将调用到 OnSmsReport 函数。
void OnNotifyOps(const char *s, const char *smsPdu){//省略非核心代码if (IsCallNoticeCmd(s)) {CallReportInfoProcess(s);} else if (ReportStrWith(s, "+CMT:")) {HRilSmsResponse smsResponse = {};smsResponse.pdu = (char *)smsPdu;reportInfo.notifyId = HNOTI_SMS_NEW_SMS;OnSmsReport(GetSlotId(NULL), reportInfo, (const uint8_t *)&smsResponse, strlen(smsResponse.pdu));//省略非核心代码}
OnReport 最终会调到 hril_manager.c 中的 OnSmsReport 函数。
void HRilManager::OnSmsReport(int32_t slotId, const ReportInfo *reportInfo, const uint8_t *response, size_t responseLen){OnReport(hrilSms_, slotId, reportInfo, response, responseLen);}
在 OnReport 函数中查找 notiMemberFuncMap 的 HNOTI_SMS_NEW_SMS 对应的函数指针。
// NotificationnotiMemberFuncMap_[HNOTI_SMS_NEW_SMS] = &HRilSms::NewSmsNotify;notiMemberFuncMap_[HNOTI_SMS_NEW_CDMA_SMS] =&HRilSms::NewCdmaSmsNotify;notiMemberFuncMap_[HNOTI_SMS_STATUS_REPORT] = &HRilSms::SmsStatusReportNotify;notiMemberFuncMap_[HNOTI_SMS_NEW_SMS_STORED_ON_SIM] = &HRilSms::NewSmsStoredOnSimNotify;notiMemberFuncMap_[HNOTI_CB_CONFIG_REPORT] = &HRilSms::CBConfigNotify;int32_t HRilSms::NewSmsNotify(int32_t indType, const HRilErrNumber e, const void *response, size_t responseLen){//省略部分代码std::unique_ptr<MessageParcel> parcel = std::make_unique<MessageParcel>();if (parcel == nullptr) {TELEPHONY_LOGE("parcel in NewSmsNotify is nullptr!");return HRIL_ERR_GENERIC_FAILURE;}if (!parcel->WriteInterfaceToken(HRIL_INTERFACE_TOKEN)) {TELEPHONY_LOGE("write interface token failed.");return HRIL_ERR_GENERIC_FAILURE;}struct HdfSBuf *dataSbuf = ParcelToSbuf(parcel.get());HRilResponseHeadInfo headInfo = {0};headInfo.slotId = GetSlotId();headInfo.type = (HRilResponseTypes)indType;if (!HdfSbufWriteUnpadBuffer(dataSbuf, (const uint8_t *)&headInfo, sizeof(HRilResponseHeadInfo))) {HdfSbufRecycle(dataSbuf);return HRIL_ERR_GENERIC_FAILURE;}smsMessageInfo.Marshalling(*parcel.get());indType = static_cast<int32_t>(ConvertIntToRadioNoticeType(indType));//通过IPC上报数据到core_serviceif (DataSbuf(dataSbuf, indType) == HRIL_ERR_GENERIC_FAILURE) {TELEPHONY_LOGE("DataSbuf in NewSmsNotify is failed!");return HRIL_ERR_GENERIC_FAILURE;}return HRIL_ERR_SUCCESS;}
在 NewSmsNotify 函数我们主要将短信 PDU、ID、类型序列化通过 IPC 上传到 core_service。core_service 在收到上报数据也只是转发到短彩信服务,这部分内容自行分析即可。
四、总结
开源项目的输出就是为了给开发者提供更多的学习途径,文本详细介绍了 OpenHarmony 电话子系统短彩信模块,从 JS 到 Framework 短彩信服务,以及跟 CoreService(核心服务)、RilAdapter 交互流程分析;提取出比较重要的代码片段分析了短信发送和短信接收流程,最终完成了整个框架层的调用过程。希望通过对 OpenHarmony 短彩信 Framework 层代码的分析和解读,能帮助广大开发者更全面地认识 OpenHarmony 短彩信模块的功能业务流程,更容易地适配自家的 modem 硬件,以此达到快速开发和优化功能的目的。
作为 OpenHarmony 开源项目的共建单位之一,深开鸿有责任、有义务、更有能力持续完善 OpenHarmony 的技术能力、不断以创新技术加速开源生态建设的布局。希望有更多的开发者参与到 OpenHarmony 生态的共建,共同推动生态繁荣。
END
关注深开鸿
了解更多资讯
深开鸿微信号
深开鸿视频号
深圳开鸿数字产业发展有限公司(简称“深开鸿”),以智能物联网操作系统领跑者为战略目标,基于OpenHarmony聚焦智能物联网操作系统(KaihongOS)技术研发与持续创新。立足金融、泛政府、能源、交通、工业和消费等领域,深开鸿专注于数字终端、数字生活和数字生产等智能物联网操作系统的深耕,配套软硬件多场景智能化服务,赋能千行百业,为数字中国提供坚实的数字底座。从开源中来,到开源中去,深开鸿致力于构建多赢的物联网操作系统生态圈,持续拓宽行业边界,实现万物互联。
成为智能物联网操作系统领跑者
点击在看和点赞,与更多的美好相遇 ↓

