OpenHarmerny 短彩信之Framework系统源码解析 原创 精华

深开鸿
发布于 2022-4-27 16:16
浏览
2收藏

作者:黄子轰

简介

短彩信系统框架层,以OpenHarmerny SystemAbility 系统常驻服务,为上层提供JS API 接口,下层适配不同硬件厂商Modem。提供短彩信系统框架功能业务,提供短信收发和彩信编解码基础能力;主要功能有GSM/CDMA短信收发、短信PDU(Protocol data unit,协议数据单元)编解码、Wap Push接收处理 、小区广播接收、彩信通知、 彩信编解码和SIM卡短信记录增删改查等。

架构图

OpenHarmerny 短彩信之Framework系统源码解析-鸿蒙开发者社区

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 编解码工具和接收处理业务逻辑代码。

/base/telephony/sms_mms
├─ frameworks        # 短彩信内部框架接口层
├─ interfaces        # 对外暴露的接口
│ ├─ innerkits
│ └─ kits
├─ sa_profile        # 启动配置文件
├─ services         # 服务内部代码
│ ├─ include        # 头文件目录
│ ├─ cdma         # CDMA制式源文件
│ └─ gsm          # GSM制式源文件
├─ test           # 单元测试目录
└─ utils          # 通用工具相关
参考文档路径:

https://gitee.com/openharmony/telephony_sms_mms

发送短信时序图

应用程序调用API发送短信,经过参数判断、鉴权、长短信拆分、PDU编码;添加到发送队列,调用RIL发送短信接口发送短信到接收端。并将发送状态返回应用调用者,完成一次短信发送过程。

  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. 返回应用层发送的状态信息;

OpenHarmerny 短彩信之Framework系统源码解析-鸿蒙开发者社区

发送短信时序图

短信接收时序图

  1. SmsReceiveManager创建GsmSmsReceiveHandler和CdmaSmsReceiveHandler;

  2. GsmSmsReceiveHandler和CdmaSmsReceiveHandler分别注册事件到RIL层;

  3. RIL Adapter上报短信事件;

  4. GsmSmsReceiveHandler或CdmaSmsReceiveHandler调用SmsBaseMessage解析PDU数据。

  5. GsmSmsReceiveHandler和CdmaSmsReceiveHandler过滤无效短信;根据PDU头部信息将多段消息合并;

  6. 拦截黑名单短信;

  7. 将接收处理状态应答到RIL;

  8. 广播发送接收处理的短信信息到广播接收者;

OpenHarmerny 短彩信之Framework系统源码解析-鸿蒙开发者社区

接收短信时序图

代码分析

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()

class SmsService : public SystemAbility, public SmsInterfaceStub {
    DECLARE_DELAYED_SINGLETON(SmsService)
    DECLARE_SYSTEM_ABILITY(SmsService) // necessary
public:
    void OnStart() override;
    void OnStop() override;
private:
    constexpr static uint32_t CONNECT_SERVICE_WAIT_TIME = 2000; // ms
    bool Init();
    bool registerToService_ = false;
    ServiceRunningState state_ = ServiceRunningState::STATE_NOT_START;
};
} // namespace Telephony
} // namespace OHOS

2.模块初始化

SmsService 服务启动后,调用OnStart() 函数;并创建服务内部类,初始化内部资源,包括SmsInterfaceManager、SmsSendManager、SmsReceiveManager 对象创建和初始化

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 接口实现

SmsService.cpp 继承SmsInterfaceStub.cpp ;SmsInterfaceStub 是native层对外接口IPC服务端代码,继承了并实现了IPC 对外接口ISmsServiceInterface用于跨进程对外提供navtive C++ API 接口; OnRemoteRequest() 是服务端的请求入口,通过请求Id 遍历memberFuncMap_ 调用对应的实现方法

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.多卡方案实现

根据卡槽数量创建对应的SmsInterfaceManager 对象,并用slotSmsInterfaceManagerMap_管理;服务启动后会调用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 发送短信接口 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, &parameterCount, 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 &parameter)
{
    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);
        if (sendResult == ERROR_NONE) {
            return true;
        } else {
            return false;
        }
    } 
    // 数据类型的短信
    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, &parameter.rawDataContent[0],
                arrayLength, sendCallback.release(), deliveryCallback.release());
            TELEPHONY_LOGI("NativeSendMessage SendRawDataMessage execResult = %{public}d", sendResult);
            if (sendResult == ERROR_NONE) {
                return true;
            } else {
                return false;
            }
        }
    }
    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());
 		....部分代码省略.........
 		// 编码PDU
        std::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、ril_adapter源码分析

参考文档路径:

https://gitee.com/openharmony/telephony_core_service

https://gitee.com/openharmony/telephony_ril_adapter

由于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.短信上报ril_adapter、core_service源码分析

首先打开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对应的函数指针。

// Notification
    notiMemberFuncMap_[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_service 
	if (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在收到上报数据也只是转发到短彩信服务,这部分内容自行分析即可。

8.JS 发送短信示例

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);

更多原创内容请关注:深开鸿技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建OpenHarmony生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2023-1-12 11:02:56修改
2
收藏 2
回复
举报
1条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

感谢老师用心分享。

回复
2022-4-27 16:26:00
回复
    相关推荐