0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

OpenHarmony電話子系統(tǒng)的其中的短彩信模塊

OpenAtom OpenHarmony ? 來(lái)源:OpenAtom OpenHarmony ? 作者:OpenAtom OpenHarmony ? 2022-06-01 10:54 ? 次閱讀

一、簡(jiǎn)介

近年來(lái),隨著國(guó)內(nèi)信息化市場(chǎng)的逐步成長(zhǎng),趨向成熟,以 OpenAtom OpenHarmony(簡(jiǎn)稱(chēng)“OpenHarmony”)為基座,以操作系統(tǒng)為代表的產(chǎn)業(yè)不斷吸引了眾多資源投入,匯聚了眾多開(kāi)發(fā)者的加入。深開(kāi)鴻基于 OpenHarmony 做商業(yè)發(fā)行版,以 OpenHarmony 為技術(shù)底座,專(zhuān)注于智能物聯(lián)網(wǎng)操作系統(tǒng)。立足金融、泛政府、能源、交通、工業(yè)和消費(fèi)等領(lǐng)域,深開(kāi)鴻專(zhuān)注于數(shù)字終端、數(shù)字生活和數(shù)字生產(chǎn)等智能物聯(lián)網(wǎng)操作系統(tǒng)的深耕,配套軟硬件多場(chǎng)景智能化服務(wù),賦能千行百業(yè)。OpenHarmony 電話子系統(tǒng)為 OS 提供了基礎(chǔ)的無(wú)線通信能力,本文將基于 OpenHarmony 電話子系統(tǒng)的其中的短彩信模塊,詳細(xì)分析短信彩信模塊的 Framework 層代碼框架、功能業(yè)務(wù)和代碼關(guān)鍵流程,以便 OS 系統(tǒng)開(kāi)發(fā)者、應(yīng)用開(kāi)發(fā)者能快速的入門(mén) OpenHarmony 短彩信功能業(yè)務(wù)的開(kāi)發(fā)和不同 modem 硬件廠商的適配工作。短彩信模塊以系統(tǒng)常駐服務(wù),為上層提供 JS API 接口,下層適配不同硬件廠商 Modem。提供短彩信系統(tǒng)框架功能業(yè)務(wù),提供短信收發(fā)和彩信編解碼基礎(chǔ)能力;主要功能有 GSM/CDMA 短信收發(fā)、短信 PDU(Protocol data unit,協(xié)議數(shù)據(jù)單元)編解碼、Wap Push 接收處理 、小區(qū)廣播接收、彩信通知、 彩信編解碼和 SIM 卡短信記錄增刪改查等。

二、基礎(chǔ)知識(shí)

1. 短彩信框架圖

e29a41b2-e155-11ec-ba43-dac502259ad0.png

2. 代碼結(jié)構(gòu)

Interfaces 對(duì)外提供暴露接口,包括 JS 接口定義,napi native C++ 的 JS 接口封裝;frameworks 包括 Native 接口定義和彩信編解碼對(duì)外暴露的工具;sa_profile 提供 SystemAbility 啟動(dòng)配置文件;sercives 包含了短信框架內(nèi)部服務(wù)相關(guān)代碼包括 Gsm/Cdma Pdu 編解碼工具和接收處理業(yè)務(wù)邏輯代碼。
/base/telephony/sms_mms├─ frameworks        # 短彩信內(nèi)部框架接口層├─ interfaces        # 對(duì)外暴露的接口│ ├─ innerkits│ └─ kits├─ sa_profile        # 啟動(dòng)配置文件├─ services         # 服務(wù)內(nèi)部代碼│ ├─ include        # 頭文件目錄│ ├─ cdma         # CDMA制式源文件│ └─ gsm          # GSM制式源文件├─ test           # 單元測(cè)試目錄└─utils#通用工具相關(guān)

3. 電話子系統(tǒng)(sms) 核心類(lèi)

短彩信模塊業(yè)務(wù)流程涉及到的比較重要的核心類(lèi)成員;包括 sms_mms 服務(wù),依賴的 core_service 和 ril_adapter 關(guān)鍵類(lèi)。

e3110996-e155-11ec-ba43-dac502259ad0.png

4. 短信發(fā)送時(shí)序圖

應(yīng)用程序調(diào)用 API 發(fā)送短信,經(jīng)過(guò)參數(shù)判斷、鑒權(quán)、長(zhǎng)短信拆分、PDU 編碼;添加到發(fā)送隊(duì)列,調(diào)用 RIL 發(fā)送短信接口發(fā)送短信到接收端。并將發(fā)送狀態(tài)返回應(yīng)用調(diào)用者,完成一次短信發(fā)送過(guò)程。

1.上層應(yīng)用調(diào)用發(fā)送短信的 API JS 接口,調(diào)用 JS Napi 接口;

2.JS Napi 調(diào)用 Native 層 C++ SendMessage 跨 IPC 到 SmsInterfaceManager 對(duì)象;

3.SmsInterfaceManager 根據(jù)過(guò)濾策略來(lái)過(guò)濾掉短信和參數(shù)合法性檢查;

4.SmsInterfaceManager 進(jìn)行鑒權(quán)檢查;

5.SmsInterfaceManager 調(diào)用 TextBasedSmsDelivery 或 TextBasedSmsDelivery 到 SmsSendManager;

6.SmsSendManager 調(diào)用搜網(wǎng)服務(wù)來(lái)獲取 SIM 卡和網(wǎng)絡(luò)狀態(tài);

7.GSM 網(wǎng)絡(luò)將創(chuàng)建 GsmSmsSender,CDMA 網(wǎng)絡(luò)將創(chuàng)建 CdmaSmsSender;

8.GsmSmsSender 或 CdmaSmsSender 將短信拆分并進(jìn)行 PDU 編碼然后放到隊(duì)列中;

9.通過(guò)接口將短信發(fā)送到 RIL 層;

10.如果返回的狀態(tài)失敗將啟動(dòng)重發(fā)機(jī)制;

11.返回應(yīng)用層發(fā)送的狀態(tài)信息;

e344428e-e155-11ec-ba43-dac502259ad0.png

5. 短信接收時(shí)序圖

1.SmsReceiveManager創(chuàng)建GsmSmsReceiveHandler和CdmaSmsReceiveHandler;2.GsmSmsReceiveHandler和CdmaSmsReceiveHandler分別注冊(cè)事件到RIL層;3.RIL Adapter上報(bào)短信事件;4.GsmSmsReceiveHandler或CdmaSmsReceiveHandler調(diào)用SmsBaseMessage解析PDU數(shù)據(jù);5.GsmSmsReceiveHandler和CdmaSmsReceiveHandler過(guò)濾無(wú)效短信;根據(jù)PDU頭部信息將多段消息合并;6.攔截黑名單短信;7.將接收處理狀態(tài)應(yīng)答到RIL;8.廣播發(fā)送接收處理的短信信息到廣播接收者;

e3743930-e155-11ec-ba43-dac502259ad0.png

6. 相關(guān)倉(cāng)

https://gitee.com/openharmony/telephony_sms_mms

https://gitee.com/openharmony/telephony_core_service

https://gitee.com/openharmony/telephony_ril_adapter

三、源碼解析

1. SmsService 啟動(dòng)

服務(wù)入口類(lèi) SmsService.cpp 繼承 safwk 組件的 SystemAblility 類(lèi);由 SA 系統(tǒng)服務(wù)管理框架(samgr)拉起服務(wù)。采用 telephony.cfg + profile.xml + libtel_sms_mms.z.so 的方式由 init 進(jìn)程執(zhí)行對(duì)應(yīng)的 telephony.cfg 文件拉起 SmsService SystemAbility 對(duì)應(yīng)的 telephony 進(jìn)程,并執(zhí)行 void SmsService::OnStart()。


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; // ms    bool Init();    bool registerToService_ = false;    ServiceRunningState state_ = ServiceRunningState::STATE_NOT_START;};} // namespace Telephony}//namespaceOHOS

2. 模塊初始化

SmsService 服務(wù)啟動(dòng)后,調(diào)用 OnStart() 函數(shù);并創(chuàng)建服務(wù)內(nèi)部類(lèi),初始化內(nèi)部資源,包括 SmsInterfaceManager、SmsSendManager、SmsReceiveManager 對(duì)象創(chuàng)建和初始化。


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;}//等待核心服務(wù)完成初始化,并調(diào)用InitModule 初始化內(nèi)部?jī)?nèi)部代碼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::sleep_for(milliseconds(CONNECT_SERVICE_WAIT_TIME));       }    });    connectTask.detach();}

3. Native IPC 接口實(shí)現(xiàn)

SmsService.cpp 繼承 SmsInterfaceStub.cpp ;SmsInterfaceStub 是 native 層對(duì)外接口 IPC 服務(wù)端代碼,繼承了并實(shí)現(xiàn)了 IPC 對(duì)外接口 ISmsServiceInterface 用于跨進(jìn)程對(duì)外提供 navtive C++ API 接口;OnRemoteRequest() 是服務(wù)端的請(qǐng)求入口,通過(guò)請(qǐng)求 Id 遍歷 memberFuncMap_ 調(diào)用對(duì)應(yīng)的實(shí)現(xiàn)方法。


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 請(qǐng)求處理函數(shù)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. 多卡方案實(shí)現(xiàn)

根據(jù)卡槽數(shù)量創(chuàng)建對(duì)應(yīng)的 SmsInterfaceManager 對(duì)象,并用 slotSmsInterfaceManagerMap_ 管理。

服務(wù)啟動(dòng)后會(huì)調(diào)用 InitModule() 方法并根據(jù)卡槽數(shù)量創(chuàng)建多個(gè) SmsInterfaceManager 每個(gè) SmsInterfaceManager 對(duì)象代碼每一個(gè)卡槽。


void SmsInterfaceStub::InitModule() {    static bool bInitModule = false;    if (!bInitModule) {        bInitModule = true;        std::lock_guard lock(mutex_);        for (int32_t slotId = 0; slotId < SIM_SLOT_COUNT; ++slotId) {            slotSmsInterfaceManagerMap_[slotId] = std::make_shared(slotId);            if (slotSmsInterfaceManagerMap_[slotId] == nullptr) {                return;            }            slotSmsInterfaceManagerMap_[slotId]->InitInterfaceManager();            TELEPHONY_LOGI("SmsInterfaceStub InitModule slotId = %{public}d",slotId);        }    }}

5. 短信發(fā)送流程

JS 調(diào)用發(fā)送短信示例代碼, 導(dǎo)入 SDK sms 包并構(gòu)造 SendMessageOptions 對(duì)象參數(shù)。


import sms from "@ohos.telephony.sms"; //導(dǎo)入短彩信包let msg: SendMessageOptions = {  slotId: 0,  destinationHost: '123xxxxxxxx',  content: '這是一封短信',  sendCallback: (err, data) => {    if (err) {      // 接口調(diào)用失敗,err非空      console.error(`failed to send message because ${err.message}`);      return;    }    // 接口調(diào)用成功,err為空    console.log(`success to send message: ${data.result}`);  }}// 調(diào)用接口sms.sendMessage(msg);

JS 發(fā)送短信接口 function sendMessage(options: SendMessageOptions): void 位于 sms_mms/interfaces/kits/js/@ohos.telephony.sms.d.ts。會(huì)調(diào)用位于 sms_mms/frameworks/js/napi/src/napi_sms.cpp Napi 封裝的 SendMessage 發(fā)送短信接口。
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().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 最終會(huì)調(diào)用 sms_mms/frameworks/js/napi/src/napi_sms.cpp ActuallySendMessage 函數(shù);

ActuallySendMessage 調(diào)用 Native C++ 提供發(fā)送短信的單例類(lèi) SmsServiceManagerClient 這個(gè)類(lèi)是現(xiàn)實(shí)了 OpenHarmony 系統(tǒng) IPC 通訊框架的客戶端;

用于 C/S 架構(gòu)與 SmsService 服務(wù)通訊。SmsServiceManagerClient SendMessage() 接口需要兩個(gè)回調(diào)對(duì)象分別是 SendCallback 和 DeliveryCallback 用于返回服務(wù)發(fā)送短信的狀態(tài)結(jié)果回調(diào)。


static bool ActuallySendMessage(napi_env env, SendMessageContext ¶meter){    std::unique_ptr sendCallback =        std::make_unique(hasSendCallback, env, parameter.thisVarRef, parameter.sendCallbackRef);    std::unique_ptr deliveryCallback = std::make_unique(        hasDeliveryCallback, env, parameter.thisVarRef, parameter.deliveryCallbackRef);    //文本類(lèi)型的短信    if (parameter.messageType == TEXT_MESSAGE_PARAMETER_MATCH) {        int32_t sendResult = DelayedSingleton::GetInstance()->SendMessage(            parameter.slotId, parameter.destinationHost, parameter.serviceCenter, parameter.textContent,            sendCallback.release(), deliveryCallback.release());        TELEPHONY_LOGI("NativeSendMessage SendTextMessage execResult = %{public}d", sendResult);    }     // 數(shù)據(jù)類(lèi)型的短信    else if (parameter.messageType == RAW_DATA_MESSAGE_PARAMETER_MATCH) {        if (parameter.rawDataContent.size() > 0) {            uint16_t arrayLength = static_cast(parameter.rawDataContent.size());            int32_t sendResult = DelayedSingleton::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++ 發(fā)送短信接口函數(shù)int32_t SmsServiceManagerClient::SendMessage(int32_t slotId, const std::u16string desAddr,    const std::u16string scAddr, const std::u16string text, const sptr &callback,    const sptr &deliveryCallback){    if (InitSmsServiceProxy()) {        smsServiceInterface_->SendMessage(slotId, desAddr, scAddr, text, callback, deliveryCallback);        TELEPHONY_LOGI("execute SendMessage
");        return ERROR_NONE;    }    return ERROR_SERVICE_UNAVAILABLE;}
// InitSmsServiceProxy 用于初始化與SmsService IPC 通許連接工作bool SmsServiceManagerClient::InitSmsServiceProxy(){    if (smsServiceInterface_ == nullptr) {        std::lock_guard lock(mutex_);        sptr systemAbilityManager =            SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();        if (!systemAbilityManager) {            TELEPHONY_LOGE(" Get system ability mgr failed.");            return false;        }        sptr remoteObject = systemAbilityManager->GetSystemAbility(TELEPHONY_SMS_MMS_SYS_ABILITY_ID);        if (!remoteObject) {            TELEPHONY_LOGE("Get SMS Service Failed.");            return false;        }        smsServiceInterface_ = iface_cast(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;}

通過(guò) SmsServiceManagerClient 的 SendMessage 調(diào)用最終會(huì)通過(guò) IPC 調(diào)用到 sms_mms/services/sms_interface_stub.cpp 的 OnRemoteRequest() 函數(shù);

通過(guò)定義的 codeId 從 memberFuncMap_ 遍歷出 OnSendSmsTextRequest() 方法并執(zhí)行;

OnSendSmsTextRequest 主要是 IPC 數(shù)據(jù)的反序列號(hào)并調(diào)用 SmsService 實(shí)現(xiàn)的 SendMessage() 方法。


void SmsInterfaceStub::OnSendSmsTextRequest(MessageParcel &data, MessageParcel &reply, MessageOption &option){    int32_t result = 0;    sptr sendCallback = nullptr;    sptr deliveryCallback = nullptr;    int32_t slotId = data.ReadInt32();    u16string desAddr = data.ReadString16();    u16string scAddr = data.ReadString16();    u16string text = data.ReadString16();    sptr remoteSendCallback = data.ReadRemoteObject();    sptr remoteDeliveryCallback = data.ReadRemoteObject();    if (remoteSendCallback != nullptr) {        sendCallback = iface_cast(remoteSendCallback);    }    if (remoteDeliveryCallback != nullptr) {        deliveryCallback = iface_cast(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 &sendCallback,    const sptr &deliveryCallback){  // 權(quán)限校驗(yàn)    if (!TelephonyPermission::SEND_MESSAGES)) {        SmsSender::SendResultCallBack(sendCallback, ISendShortMessageCallback::SEND_SMS_FAILURE_UNKNOWN);        TELEPHONY_LOGE("Check Permission Failed, No Has Telephony Send Messages Permisson.");        return;    }    // 獲取對(duì)應(yīng)slotId 對(duì)應(yīng)的SmsInterfaceManager 對(duì)象    std::shared_ptr interfaceManager = GetSmsInterfaceManager(slotId);    ............    interfaceManager->TextBasedSmsDelivery(StringUtils::ToUtf8(desAddr), StringUtils::ToUtf8(scAddr),        StringUtils::ToUtf8(text), sendCallback, deliveryCallback);}

SmsInterfaceManager 對(duì)象 TextBasedSmsDelivery 用于發(fā)送短信接口調(diào)用 SmsSendManager 對(duì)象的 TextBasedSmsDelivery();根據(jù)當(dāng)前 sloidId 卡的網(wǎng)絡(luò)狀態(tài) 調(diào)用 Gsm 或者 Cdma 來(lái)進(jìn)一步發(fā)送短信處理。


void SmsSendManager::TextBasedSmsDelivery(const string &desAddr, const string &scAddr, const string &text,    const sptr &sendCallback,    const sptr &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 長(zhǎng)短信分段和 PDU 的編碼過(guò)程,入口函數(shù) GsmSmsSender::TextBasedSmsDelivery()。

或者 CdmaSmsSender::TextBasedSmsDelivery() 并構(gòu)造 SmsSendIndexer 對(duì)象添加到 Map 隊(duì)列中,并調(diào)用 CoreService 提供的發(fā)送短信接口發(fā)送,等待發(fā)送結(jié)果;拿 Gsm 制式的來(lái)分析,代碼如下:


void GsmSmsSender::TextBasedSmsDelivery(const string &desAddr, const string &scAddr, const string &text,    const sptr &sendCallback, const sptr &deliveryCallback){    bool isMore = false;    bool isStatusReport = false;    int ret = 0;    int headerCnt;    int cellsInfosSize;    unsigned char msgRef8bit;    SmsCodingScheme codingType;    GsmSmsMessage gsmSmsMessage;    std::vector cellsInfos;    // 長(zhǎng)短信分段拆分    gsmSmsMessage.SplitMessage(cellsInfos, text, CheckForce7BitEncodeType(), codingType);    isStatusReport = (deliveryCallback == nullptr) ? false : true;    std::shared_ptr tpdu =        gsmSmsMessage.CreateDefaultSubmitSmsTpdu(desAddr, scAddr, text, isStatusReport, codingType);
  ....部分代碼省略.........    std::unique_lock lock(mutex_);    for (int i = 0; i < cellsInfosSize; i++) {        std::shared_ptr indexer = nullptr;        std::string segmentText;        segmentText.append((char *)(cellsInfos[i].encodeData.data()),cellsInfos[i].encodeData.size());   ....部分代碼省略.........   // 編碼PDU        std::shared_ptr encodeInfo = gsmSmsMessage.GetSubmitEncodeInfo(scAddr, isMore);        if (encodeInfo == nullptr) {            SendResultCallBack(indexer, ISendShortMessageCallback::SEND_SMS_FAILURE_UNKNOWN);            TELEPHONY_LOGE("create encodeInfo encodeInfo nullptr error.");            continue;        }        // 構(gòu)造填充SmsSendIndexer對(duì)象        SetSendIndexerInfo(indexer, encodeInfo, msgRef8bit);        indexer->SetUnSentCellCount(unSentCellCount);        indexer->SetHasCellFailed(hasCellFailed);        SendSmsToRil(indexer);    }}
//判斷是否是IMS網(wǎng)絡(luò)域,調(diào)用CoreService 不同的接口進(jìn)行發(fā)送void GsmSmsSender::SendSmsToRil(const shared_ptr &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. 核心服務(wù)下發(fā)流程

由于 core_service 服務(wù)和短彩信服務(wù)在同一個(gè)進(jìn)程中,所以我們通過(guò) CoreManagerInner::GetInstance() 來(lái)獲取核心服務(wù)的單例對(duì)象,調(diào)用 SendGsmSms 或 SendCdmaSms 函數(shù)發(fā)送短信。


int32_t CoreManagerInner::SendGsmSms(int32_t slotId, int32_t eventId, GsmSimMessageParam &gsmMessage,    const std::shared_ptr &handler){    if (telRilManager_ == nullptr) {        TELEPHONY_LOGE("telRilManager is null!");        return TELEPHONY_ERR_LOCAL_PTR_NULL;    }    AppExecFwk::Pointer response = AppExecFwk::Get(eventId, gsmMessage.refId);    response->SetOwner(handler);    return telRilManager_->SendGsmSms(slotId, gsmMessage.smscPdu, gsmMessage.pdu, response);}

SendGsmSms 函數(shù)將 eventId、refId 和 handler 對(duì)象封裝到 response 對(duì)象中再轉(zhuǎn)發(fā)到 telRilManager 的 SendGsmSms 函數(shù)。


/*********************** TelRilNetwork end ****************************//*********************** TelRilSms start ******************************/int32_t TelRilManager::SendGsmSms(    int32_t slotId, std::string smscPdu, std::string pdu, const AppExecFwk::Pointer &response){    return TaskSchedule(response, "TelRilSms", GetTelRilSms(slotId), &TelRilSms::SendGsmSms, smscPdu, pdu);}

TelRilManager::SendGsmSms 里面只有一個(gè) TaskSchedule 函數(shù)調(diào)用,其實(shí) TaskSchedule 是個(gè)模板函數(shù),就是為了統(tǒng)一下所有任務(wù)調(diào)用。


template    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(_args)..., _result);        } else {            TELEPHONY_LOGE("%{public}s - this %{public}p: %{public}s", _module.c_str(), &_obj, "null pointer");            return HRIL_ERR_NULL_POINT;        }}

這個(gè)模板函數(shù)最終會(huì)調(diào)用 TelRilSms::SendGsmSms 并且將 response 插入到函數(shù)的最后一個(gè)參數(shù)中。


int32_t TelRilSms::string &smsPdu, std::string &pdu, const AppExecFwk::Pointer &response){    std::shared_ptr 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::TF_ASYNC};    if (cellularRadio_->SendRequest(HREQ_SMS_SEND_GSM_SMS, data, reply, option)) {        TELEPHONY_LOGE("cellularRadio_->SendRequest fail");    }    return TELEPHONY_ERR_SUCCESS;}

在 TelRilSms::SendGsmSms 函數(shù)中我們調(diào)用 CreateTelRilRequest 來(lái)將 serialId、response 和 HREQ_SMS_SEND_GSM_SMS 等保存到一個(gè) map 中方便我們后續(xù)將短信發(fā)送的狀態(tài)上報(bào)到短彩信服務(wù)中。下面 MessageParcel data 將 pdu、smscpdu、serialId 序列化到 data 中,最后通過(guò) cellularRadio_->SendRequest 通過(guò) IPC 將數(shù)據(jù)發(fā)送到 ril_adapter 服務(wù)中。進(jìn)入 Ril 層我們分析 serviceshril_hdfsrchril_hdf.c 這個(gè)文件,hril_hdf.c 是 ril_adapter 層加載 vendor 庫(kù)、注冊(cè)發(fā)送和響應(yīng)函數(shù)、啟動(dòng)讀寫(xiě)線程、事件調(diào)度的入口。


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 說(shuō)明事件調(diào)度入口就是進(jìn)入 RilAdapterDispatch 函數(shù)。RilAdapterDispatch 函數(shù)里面主要加互斥鎖調(diào)用 DispatchRequest(cmd, data) 這個(gè)事件分發(fā)最終調(diào)用到 hril_sms 文件的 HRilSms::SendGsmSms 函數(shù)。


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 函數(shù)將 core_service 發(fā)送下來(lái)的數(shù)據(jù)反序列化到 struct GsmSmsMessageInfo message 中,最后調(diào)用 RequestWithStrings 函數(shù)。最后將數(shù)據(jù)轉(zhuǎn)發(fā)到 vendor 庫(kù)的 at_sms.c 文件的 ReqSendGsmSms 函數(shù)。


void ReqSendGsmSms(const ReqDataInfo *requestInfo, const char *const *data, size_t dataLen){//省略非核心代碼//向modem發(fā)送AT +CMGS指令    err = SendCommandSmsLock(cmd, smsPdu, "+CMGS:", 0, &responseInfo);    if (err != 0 || (responseInfo != NULL && !responseInfo->success)) {        HandlerSmsResult(&response, &reportInfo, requestInfo, &err, responseInfo);        return;   }//獲取發(fā)送后狀態(tài)  HandleResult(&err, result, responseInfo, &response);   reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0);    //上報(bào)發(fā)送后的狀態(tài)   OnSmsReport(GetSlotId(requestInfo), reportInfo, (const uint8_t *)&response, sizeof(HRilSmsResponse));    FreeResponseInfo(responseInfo);}

ReqSendGsmSms 函數(shù)將 AT 指令下發(fā)到 modem 并且將發(fā)送的狀態(tài)上報(bào)。上報(bào)流程和下發(fā)流程類(lèi)似不做具體分析。

7. 核心服務(wù)主動(dòng)上報(bào)

首先打開(kāi) vendor_adapter.c 我們可以看到 EventListeners 函數(shù)。


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
", ret);            return;        }        ModemInit();        sleep(1);        WaitAtClose();    }}

EventListeners 中主要是 ATStartReadLoop 函數(shù)將創(chuàng)建一個(gè)線程讀取 modem 上報(bào)的內(nèi)容,在 OnNotifyOps 中短信上報(bào)內(nèi)容是 AT +CMT 指令。將調(diào)用到 OnSmsReport 函數(shù)。


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 最終會(huì)調(diào)到 hril_manager.c 中的 OnSmsReport 函數(shù)。


void HRilManager::OnSmsReport(    int32_t slotId, const ReportInfo *reportInfo, const uint8_t *response, size_t responseLen){    OnReport(hrilSms_, slotId, reportInfo, response, responseLen);}

在 OnReport 函數(shù)中查找 notiMemberFuncMap 的 HNOTI_SMS_NEW_SMS 對(duì)應(yīng)的函數(shù)指針。


// 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 parcel = std::make_unique();    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(ConvertIntToRadioNoticeType(indType));   //通過(guò)IPC上報(bào)數(shù)據(jù)到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 函數(shù)我們主要將短信 PDU、ID、類(lèi)型序列化通過(guò) IPC 上傳到 core_service。core_service 在收到上報(bào)數(shù)據(jù)也只是轉(zhuǎn)發(fā)到短彩信服務(wù),這部分內(nèi)容自行分析即可。

四、總結(jié)

開(kāi)源項(xiàng)目的輸出就是為了給開(kāi)發(fā)者提供更多的學(xué)習(xí)途徑,文本詳細(xì)介紹了 OpenHarmony 電話子系統(tǒng)短彩信模塊,從 JS 到 Framework 短彩信服務(wù),以及跟 CoreService(核心服務(wù))、RilAdapter 交互流程分析;提取出比較重要的代碼片段分析了短信發(fā)送和短信接收流程,最終完成了整個(gè)框架層的調(diào)用過(guò)程。希望通過(guò)對(duì) OpenHarmony 短彩信 Framework 層代碼的分析和解讀,能幫助廣大開(kāi)發(fā)者更全面地認(rèn)識(shí) OpenHarmony 短彩信模塊的功能業(yè)務(wù)流程,更容易地適配自家的 modem 硬件,以此達(dá)到快速開(kāi)發(fā)和優(yōu)化功能的目的。

作為 OpenHarmony 開(kāi)源項(xiàng)目的共建單位之一,深開(kāi)鴻有責(zé)任、有義務(wù)、更有能力持續(xù)完善 OpenHarmony 的技術(shù)能力、不斷以創(chuàng)新技術(shù)加速開(kāi)源生態(tài)建設(shè)的布局。希望有更多的開(kāi)發(fā)者參與到 OpenHarmony 生態(tài)的共建,共同推動(dòng)生態(tài)繁榮。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    632

    瀏覽量

    29110
  • OpenHarmony
    +關(guān)注

    關(guān)注

    25

    文章

    3640

    瀏覽量

    16061

原文標(biāo)題:OpenHarmony源碼解析之電話子系統(tǒng)——短彩信

文章出處:【微信號(hào):gh_e4f28cfa3159,微信公眾號(hào):OpenAtom OpenHarmony】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    深度解析linux時(shí)鐘子系統(tǒng)

    linux內(nèi)核中實(shí)現(xiàn)了一個(gè)CLK子系統(tǒng),用于對(duì)上層提供各模塊(例如需要時(shí)鐘信號(hào)的外設(shè),USB等)的時(shí)鐘驅(qū)動(dòng)接口,對(duì)下層提供具體SOC的時(shí)鐘操作細(xì)節(jié)。
    的頭像 發(fā)表于 09-29 16:46 ?243次閱讀
    深度解析linux時(shí)鐘<b class='flag-5'>子系統(tǒng)</b>

    Openharmony軟件評(píng)估指南-米爾瑞芯微RK3568開(kāi)發(fā)板

    Openharmony軟件評(píng)估指南用于介紹在米爾的開(kāi)發(fā)板上運(yùn)行Openharmony系統(tǒng)下的核心資源與外設(shè)資源的測(cè)試步驟與評(píng)估方法。本文可作為前期評(píng)估指南使用,也可以作為通用系統(tǒng)開(kāi)發(fā)的
    發(fā)表于 09-06 20:06

    藍(lán)牙模塊在車(chē)載系統(tǒng)中的應(yīng)用與集成:現(xiàn)狀、挑戰(zhàn)與未來(lái)展望

    隨著科技的快速發(fā)展,藍(lán)牙技術(shù)已經(jīng)深入到我們生活的方方面面,其中車(chē)載系統(tǒng)中的應(yīng)用尤為顯著。藍(lán)牙模塊作為一種無(wú)線通信技術(shù),不僅為駕駛者提供了更加便捷的操作體驗(yàn),同時(shí)也提升了駕駛的安全性。本文旨在分析藍(lán)牙
    的頭像 發(fā)表于 06-20 17:29 ?459次閱讀

    鴻蒙OpenHarmony開(kāi)發(fā):【編譯構(gòu)建指導(dǎo)】

    OpenHarmony編譯子系統(tǒng)是以GN和Ninja構(gòu)建為基座,對(duì)構(gòu)建和配置粒度進(jìn)行部件化抽象、對(duì)內(nèi)建模塊進(jìn)行功能增強(qiáng)、對(duì)業(yè)務(wù)模塊進(jìn)行功能擴(kuò)展的系統(tǒng)
    的頭像 發(fā)表于 05-13 09:31 ?1532次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>開(kāi)發(fā):【編譯構(gòu)建指導(dǎo)】

    鴻蒙OpenHarmony開(kāi)發(fā)板解析:【 模塊配置規(guī)則】

    編譯子系統(tǒng)通過(guò)模塊、部件和產(chǎn)品三層配置來(lái)實(shí)現(xiàn)編譯和打包。模塊就是編譯子系統(tǒng)的一個(gè)目標(biāo),包括(動(dòng)態(tài)庫(kù)、靜態(tài)庫(kù)、配置文件、預(yù)編譯模塊等)。
    的頭像 發(fā)表于 05-10 14:39 ?833次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>開(kāi)發(fā)板解析:【 <b class='flag-5'>模塊</b>配置規(guī)則】

    鴻蒙OpenHarmony開(kāi)發(fā)板:【子系統(tǒng)配置規(guī)則】

    通過(guò)build倉(cāng)下的subsystem_config.json可以查看所有子系統(tǒng)的配置規(guī)則。
    的頭像 發(fā)表于 05-08 22:07 ?243次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>開(kāi)發(fā)板:【<b class='flag-5'>子系統(tǒng)</b>配置規(guī)則】

    鴻蒙OpenHarmony【標(biāo)準(zhǔn)系統(tǒng)編寫(xiě)“Hello World”程序】 (基于RK3568開(kāi)發(fā)板)

    源碼],創(chuàng)建RK3568開(kāi)發(fā)板的源碼工程。 示例目錄 拉取openharmony項(xiàng)目代碼,在代碼根目錄創(chuàng)建sample子系統(tǒng)文件夾,在子系統(tǒng)目錄下創(chuàng)建hello部件文件夾,hello文件夾中創(chuàng)建
    的頭像 發(fā)表于 04-24 17:32 ?681次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>【標(biāo)準(zhǔn)<b class='flag-5'>系統(tǒng)</b>編寫(xiě)“Hello World”程序】 (基于RK3568開(kāi)發(fā)板)

    鴻蒙OpenHarmony技術(shù):【設(shè)備互信認(rèn)證】

    OpenHarmony中,設(shè)備互信認(rèn)證模塊作為安全子系統(tǒng)的子模塊,負(fù)責(zé)設(shè)備間可信關(guān)系的建立、維護(hù)、使用、撤銷(xiāo)等全生命周期的管理,實(shí)現(xiàn)可信設(shè)備間的互信認(rèn)證和安全會(huì)話密鑰協(xié)商,是搭載
    的頭像 發(fā)表于 03-25 17:04 ?625次閱讀
    鴻蒙<b class='flag-5'>OpenHarmony</b>技術(shù):【設(shè)備互信認(rèn)證】

    鴻蒙開(kāi)發(fā)圖形圖像:【圖形子系統(tǒng)

    圖形子系統(tǒng)主要包括UI組件、布局、動(dòng)畫(huà)、字體、輸入事件、窗口管理、渲染繪制等模塊,構(gòu)建基于輕量OS應(yīng)用框架滿足硬件資源較小的物聯(lián)網(wǎng)設(shè)備或者構(gòu)建基于標(biāo)準(zhǔn)OS的應(yīng)用框架滿足富設(shè)備的OpenHarmony
    的頭像 發(fā)表于 03-23 16:50 ?583次閱讀
    鴻蒙開(kāi)發(fā)圖形圖像:【圖形<b class='flag-5'>子系統(tǒng)</b>】

    鴻蒙開(kāi)發(fā)學(xué)習(xí):【驅(qū)動(dòng)子系統(tǒng)

    OpenHarmony驅(qū)動(dòng)子系統(tǒng)采用C面向?qū)ο缶幊棠P蜆?gòu)建,通過(guò)平臺(tái)解耦、內(nèi)核解耦,兼容不同內(nèi)核,提供了歸一化的驅(qū)動(dòng)平臺(tái)底座,旨在為開(kāi)發(fā)者提供更精準(zhǔn)、更高效的開(kāi)發(fā)環(huán)境,力求做到一次開(kāi)發(fā),多系統(tǒng)部署。
    的頭像 發(fā)表于 03-17 22:05 ?534次閱讀
    鴻蒙開(kāi)發(fā)學(xué)習(xí):【驅(qū)動(dòng)<b class='flag-5'>子系統(tǒng)</b>】

    鴻蒙開(kāi)發(fā)實(shí)戰(zhàn):【電話服務(wù)子系統(tǒng)

    電話服務(wù)子系統(tǒng),提供了一系列的API用于獲取無(wú)線蜂窩網(wǎng)絡(luò)和SIM卡相關(guān)的一些信息。應(yīng)用可以通過(guò)調(diào)用API來(lái)獲取當(dāng)前注冊(cè)網(wǎng)絡(luò)名稱(chēng)、網(wǎng)絡(luò)服務(wù)狀態(tài)、信號(hào)強(qiáng)度以及SIM卡的相關(guān)信息。
    的頭像 發(fā)表于 03-14 21:49 ?320次閱讀
    鴻蒙開(kāi)發(fā)實(shí)戰(zhàn):【<b class='flag-5'>電話</b>服務(wù)<b class='flag-5'>子系統(tǒng)</b>】

    北斗報(bào)文是什么?看完你就懂了

    北斗報(bào)文通信服務(wù)是北斗衛(wèi)星導(dǎo)航系統(tǒng)提供的一種獨(dú)特的通信功能,它利用衛(wèi)星信號(hào)實(shí)現(xiàn)用戶與用戶、用戶與中心控制系統(tǒng)之間的雙向簡(jiǎn)短文字通信。在沒(méi)有地面通信網(wǎng)絡(luò)覆蓋的地區(qū),如海洋、沙漠、山區(qū)等環(huán)境下,用戶
    的頭像 發(fā)表于 03-14 12:03 ?1152次閱讀

    【工作準(zhǔn)備】OpenHarmony鴻蒙操作系統(tǒng)開(kāi)發(fā)——基礎(chǔ)必備軟件

    前言 在下根據(jù)多年 OpenHarmony 內(nèi)核及多個(gè)子系統(tǒng)的開(kāi)發(fā)經(jīng)驗(yàn),將用到的必備工具軟件列出一張清單,供新同學(xué)參考。如何精進(jìn)?請(qǐng)自行搜索專(zhuān)業(yè)手冊(cè)進(jìn)行學(xué)習(xí),我是碰到什么問(wèn)題、需要什么小功能然后去查
    的頭像 發(fā)表于 02-23 15:51 ?1637次閱讀
    【工作準(zhǔn)備】<b class='flag-5'>OpenHarmony</b>鴻蒙操作<b class='flag-5'>系統(tǒng)</b>開(kāi)發(fā)——基礎(chǔ)必備軟件

    啟動(dòng)System Init進(jìn)入OpenHarmony系統(tǒng)過(guò)程分析與適配

    和內(nèi)核等配置信息,其中各組件及特性需要根據(jù)設(shè)備需求配置,新增的子系統(tǒng)模塊組件可以配置到此文件中。如果配置到rich.json等將要繼承的配置文件也可以起作用,但放到此文件/對(duì)應(yīng)的配置文件更規(guī)范。如果
    發(fā)表于 01-26 10:04

    礦用廣播系統(tǒng),網(wǎng)絡(luò)電話音頻模塊-SIP2800V

    SIP2800V系列模塊是我司設(shè)計(jì)研發(fā)的一款用于井下的礦用IP音頻傳輸模塊,可用此模塊打造一套低延遲、高效率、高靈活和多擴(kuò)展的IP礦用廣播對(duì)講系統(tǒng),亦可對(duì)傳統(tǒng)煤礦
    發(fā)表于 11-15 17:24 ?0次下載