OpenHarmony源码解析之RIL Adapter 原创 精华

发布于 2022-1-13 16:07
浏览
1收藏

作者:杨金壮

1 简介

​ RIL(Radio Interface Layer)是Telephony和Modem之间的抽象层,用于实现Telephony和Modem之间的通信转换。Modem厂商有高通、mtk、海思、展讯等,不同的Modem在接口、内部机制、实现方式等方面都有不同。RIL Adapter屏蔽不同Modem厂商硬件差异,为上层提供统一的接口。

1.1 OpenHarmony 架构图

​ RIL Adapter在OpenHarmony 架构中属于电话子系统,如下图所示。

OpenHarmony源码解析之RIL Adapter-开源基础软件社区
​ 图1 OpenHarmony架构图

1.2 电话子系统

​ 电话子系统属于基础软件服务子系统集,在其核心服务模块core_service中,初始化RIL管理以及获取RIL
Adapter服务,通过注册回调服务,实现与RIL Adapter进行通信。代码目录如下:

/base/telphony/core_service

\|── interfaces # 接口目录

│ \|── innerkits # 部件间的内部接口

│ \|── kits # 对应用提供的接口(例如JS接口)

\|── services # 核心服务实现代码目录

\|── etc # 核心服务的驱动脚本目录

\|── sa_profile # 核心服务的启动文件目录

\|── tel_ril # 核心服务与RIL Adapter通信代码目录

\|── network_search # 搜网服务代码目录

\|── sim # SIM卡服务代码目录

└── common

​ RIL Adapter不对外暴露接口,可通过核心服务调用,并且需要与Telephony核心服务配合使用,需要Modem厂商库实现接口。

​ 硬件上,需要搭载的设备支持以下硬件:可以进行独立蜂窝通信的Modem。

2 基础知识

​ RIL Adapter模块的主要功能是转换业务请求为AT命令,监听、解析、上送Modem的response及notification信息。

​ RIL Adapter可以简单细化为hril层和vendorlib层,为了实现充分解耦,各厂商AT指令等差异化的功能都放在vendorlib层,hril层主要是向上通信,vendorlib层主要是向下和Modem通信。RIL Adapter通过注册HDF服务与上层通讯。RIL Adapter和Modem之间的通信方式常见的有AT命令和QMI两种。

OpenHarmony源码解析之RIL Adapter-开源基础软件社区
​ 图2 RIL Adapter模块架构图

2.1 AT命令

​ AT命令是Hayes公司为了控制Modem发明的控制协议,AT命令集是从终端设备(Terminal Equipment,TE)或数据终端设备(Data Terminal Equipment,DTE)向终端适配器(Terminal Adapter,TA)或数据电路终端设备(Data Circuit Terminal Equipment,DCE)发送的。通过AT命令可以进行呼叫、短信、电话本、数据业务、传真等方面的控制,并且采用标准串口来收发AT命令。

​ 所有的AT命令行都由前缀“AT”开始,以回车符<CR>结束。中间是一个或者多个AT命令。AT命令包括:基本命令和扩展命令。扩展命令以字符“+”为前缀,并需要使用分号“;”与前面的命令分隔开。

OpenHarmony源码解析之RIL Adapter-开源基础软件社区
​ 图3 AT命令格式图

2.2 QMI

​ QMI(Qualcomm Modem Interface)是高通提供的与Modem交互的接口。QMI框架包括client部分和server部分,其中QMI client运行在RIL Adapter,采用dlopen方式打开,QMI server运行在Modem,client和server之间使用socket方式通讯。

3 代码解析

3.1 代码目录

base/telephony/ril_adapter

├─ hril # hril层的各个业务模块接口实现

├─ hril_hdf # 注册HDF服务,注册向上通信接口

├─ include # 头文件存放目录

├─ interfaces # 对应提供上层各业务内部接口

│ └─ innerkits

├─ test # 单元测试相关代码

│ ├─ mock

│ └─ unittest # 单元测试代码

└─ vendor # 厂商库代码:各业务AT指令

│ └─ include

3.2 代码流程

OpenHarmony源码解析之RIL Adapter-开源基础软件社区
​ RIL Adapter除了主线程之外,还会拉起event处理线程和Modem消息处理线程。

​ **eventLoop:**打开AT通道,完成Modem初始设置,组合AT命令发送到Modem,等待response,并将response上送;

1.static void EventListeners(void)  
2.{  
3.    int waitNextTryTime = SLEEP_TIME;  
4.    const char *devicePath = DEVICE_PATH;  
5.    char atTtyPath[PARAMETER_ZISE] = {0};  
6.  
7.    usleep(DELAY_WAIT_MS); // Prevent slow loading of system properties.  
8.    if (GetParameter(AT_TTY_PATH, "", atTtyPath, PARAMETER_ZISE) > 0) {  
9.        devicePath = atTtyPath;  
10.    }  
11.  
12.    TELEPHONY_LOGI("opening AT interface %{public}s", devicePath);  
13.    AtSetOnUnusual(AtOnUnusual);  
14.    for (;;) {  
15.        while (g_fd < 0) {  
16.            if (devicePath != NULL) {  
17.                g_fd = open(devicePath, O_RDWR);  
18.            }  
19.            if (g_fd >= 0 && !memcmp(devicePath, DEVICE_PATH_DEFAULT, sizeof(DEVICE_PATH_DEFAULT) - 1)) {  
20.                struct termios ios;  
21.                tcgetattr(g_fd, &ios);  
22.                ios.c_lflag = 0;  
23.                tcsetattr(g_fd, TCSANOW, &ios);  
24.            }  
25.            if (g_fd < 0) {  
26.                TELEPHONY_LOGE("ril vendorlib,opening AT interface. retrying...");  
27.                sleep(waitNextTryTime);  
28.            }  
29.        }  
30.        g_atStatus = 0;  
31.        int ret = ATStartReadLoop(g_fd, OnNotifyOps);  
32.        if (ret < 0) {  
33.            TELEPHONY_LOGE("AtRead error %d\n", ret);  
34.            return;  
35.        }  
36.        ModemInit();  
37.        sleep(1);  
38.        WaitAtClose(); /*AT通道在检测超时后,将会主动的关闭当前的AT通道,此时将会激活waitForClose                             中的阻塞线程 然后waitForClose将会返回 而一旦waitForClose函数返回,将会                             再次进入for循环,重新打开AT通道。*/ 
39.    }  
40.}  

​ **readLoop :**解析从Modem发过来的消息,notification和response分开处理。

1.void *ReaderLoop(void *s)  
2.{  
3.    while (1) {  
4.        const char *str = NULL;  
5.        const char *pdu = NULL;  
6.        str = ReadResponse(g_atFd);  
7.        if (str == NULL) {  
8.            TELEPHONY_LOGI("%{public}s enter str is null", __func__);  
9.            break;  
10.        }  
11.        if (IsSmsNotify(str)) {  
12.            pdu = ReadResponse(g_atFd);  
13.            TELEPHONY_LOGI("new sms notify :%{public}s, pdu :%{public}s", str, pdu);  
14.        }  
15.        ProcessResponse(str, pdu);  
16.    }  
17.    OnReaderClosed();  
18.    return NULL;  
19.}  

3.3 相关仓

4 核心功能解析

​ RIL Adapter核心的处理包括厂商库加载,业务接口实现以及Modem消息处理。

4.1 厂商库加载

​ RIL Adapter是通过dlopen()函数加载厂商so文件,然后调用so文件的RilInitOps()函数,该函数的作用是使得RIL Adapter和so文件互相注册回调函数,把HRilReport注册给so,同时返回HRilOps,RIL Adapter得到一组函数指针。

1.#define RIL_LIB_PATH "/system/lib/libril_vendor.z.so"  
2.  
3.static void LoadVendor(void)  
4.{  
5.    const char *rilLibPath = NULL;  
6.    // Pointer to ril init function in vendor ril  
7.    const HRilOps *(*rilInitOps)(const struct HRilReport *) = NULL;  
8.    // functions returned by ril init function in vendor ril  
9.    const HRilOps *ops = NULL;  
10.    rilLibPath = RIL_LIB_PATH;  
11.    if (rilLibPath == NULL) {  
12.        TELEPHONY_LOGE("dynamic library path is empty");  
13.        return;  
14.    }  
15.  
16.    TELEPHONY_LOGD("RilInit rilInit start");  
17.    g_dlHandle = dlopen(rilLibPath, RTLD_NOW);  
18.    if (g_dlHandle == NULL) {  
19.        return;  
20.    }  
21.    rilInitOps = (const HRilOps *(*)(const struct HRilReport *))dlsym(g_dlHandle, "RilInitOps");  
22.    if (rilInitOps == NULL) {  
23.        dlclose(g_dlHandle);  
24.        TELEPHONY_LOGE("RilInit not defined or exported ");  
25.        return;  
26.    }  
27.    ops = rilInitOps(&g_reportOps);  
28.    TELEPHONY_LOGD("RilInit rilInit completed");  
29.    HRilRegOps(ops);  
30.}  

​ HRilReport数据结构如下:

1.struct HRilReport {  
2.    void (*OnCallReport)int32_t slotId, struct ReportInfo reportInfo, 
            const uint8_t *data, size_t dataLen);  
3.    void (*OnDataReport)int32_t slotId, struct ReportInfo reportInfo, 
            const uint8_t *data, size_t dataLen);  
4.    void (*OnModemReport)int32_t slotId, struct ReportInfo reportInfo, 
            const uint8_t *data, size_t dataLen);  
5.    void (*OnNetworkReport)int32_t slotId, struct ReportInfo reportInfo, 
            const uint8_t *data, size_t dataLen);  
6.    void (*OnSimReport)int32_t slotId, struct ReportInfo reportInfo, 
            const uint8_t *data, size_t dataLen);  
7.    void (*OnSmsReport)int32_t slotId, struct ReportInfo reportInfo, 
            const uint8_t *data, size_t dataLen);  
8.};

​ HRilOps 数据结构如下:

1.typedef struct {  
2.    int version;  
3.    const HRilCallReq *callOps;  
4.    const HRilSimReq *simOps;  
5.    const HRilSmsReq *smsOps;  
6.    const HRilDataReq *dataOps;  
7.    const HRilNetworkReq *networkOps;  
8.    const HRilModemReq *modemOps;  
9.} HRilOps;  

4.2 业务接口实现

1、注册各业务回调处理函数;

1.extern "C" void HRilRegOps(const HRilOps *hrilOps)  
2.{  
3.    if (hrilOps == nullptr) {  
4.        TELEPHONY_LOGE("HRilRegOps: HRilRegOps * nullptr");  
5.        return;  
6.    }  
7.    if (rilRegisterStatus > RIL_REGISTER_IS_NONE) {  
8.        TELEPHONY_LOGE("HRilRegOps is running!!!!");  
9.        return;  
10.    }  
11.    (void)memcpy_s(&g_callBacks, sizeof(HRilOps), hrilOps, sizeof(HRilOps));  
12.    rilRegisterStatus = RIL_REGISTER_IS_RUNNING;  
13.    if (g_callBacks.smsOps != nullptr) {  
14.        g_manager->RegisterSmsFuncs(g_callBacks.smsOps);  
15.    }  
16.    if (g_callBacks.callOps != nullptr) {  
17.        g_manager->RegisterCallFuncs(g_callBacks.callOps);  
18.    }  
19.    if (g_callBacks.dataOps != nullptr) {  
20.        g_manager->RegisterDataFuncs(g_callBacks.dataOps);  
21.    }  
22.    if (g_callBacks.modemOps != nullptr) {  
23.        g_manager->RegisterModemFuncs(g_callBacks.modemOps);  
24.    }  
25.    if (g_callBacks.networkOps != nullptr) {  
26.        g_manager->RegisterNetworkFuncs(g_callBacks.networkOps);  
27.    }  
28.    if (g_callBacks.simOps != nullptr) {  
29.        g_manager->RegisterSimFuncs(g_callBacks.simOps);  
30.    }  
31.}  

2、目前RIL Adapter支持call、sim、sms、data、modem、network六种业务,下面以call为例介绍业务接口实现;

​ call业务请求注册:

1.typedef struct {  
2.    void (*GetCallList)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);  
3.    void (*Dial)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);  
4.    void (*Hangup)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);  
5.    void (*Reject)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);  
6.    void (*Answer)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);  
7.    void (*GetClip)(ReqDataInfo *requestInfo);  
8.    void (*SetClip)(ReqDataInfo *requestInfo, int action);  
9.    void (*Hold)(ReqDataInfo *requestInfo);  
10.    void (*Active)(ReqDataInfo *requestInfo);  
11.    void (*Swap)(ReqDataInfo *requestInfo);  
12.    void (*Join)(ReqDataInfo *requestInfo, int callType);  
13.    void (*Split)(ReqDataInfo *requestInfo, int nThCall, int callType);  
14.    void (*CallSupplement)(ReqDataInfo *requestInfo, int type);  
15.    void (*GetCallWait)(ReqDataInfo *requestInfo);  
16.    void (*SetCallWait)(ReqDataInfo *requestInfo, int active);  
17.    void (*SetCallForwarding)(ReqDataInfo *requestInfo, HRilCFInfo info);  
18.    void (*GetCallForwarding)(ReqDataInfo *requestInfo, int reason);  
19.    void (*GetCallRestriction)(ReqDataInfo *requestInfo, const char *fac);  
20.    void (*SetCallRestriction)(ReqDataInfo *requestInfo, CallRestrictionInfo info);  
21.    void (*GetClir)(ReqDataInfo *requestInfo);  
22.    void (*SetClir)(ReqDataInfo *requestInfo, int action);  
23.    void (*StartDtmf)(ReqDataInfo *requestInfo, CallDTMFInfo info);  
24.    void (*SendDtmf)(ReqDataInfo *requestInfo, CallDTMFInfo info);  
25.    void (*StopDtmf)(ReqDataInfo *requestInfo, CallDTMFInfo info);  
26.} HRilCallReq;  
27.void HRilCall::RegisterCallFuncs(const HRilCallReq *callFuncs)  
28.{  
29.    callFuncs_ = callFuncs;  
30.}  

​ call业务请求队列:

1.void HRilCall::AddHandlerToMap()  
2.{  
3.    // Notification  
4.    notiMemberFuncMap_[HNOTI_CALL_STATE_UPDATED] = &HRilCall::CallStateUpdated;  
5.  
6.    // Response  
7.    respMemberFuncMap_[HREQ_CALL_GET_CALL_LIST] = &HRilCall::GetCallListResponse;  
8.    respMemberFuncMap_[HREQ_CALL_DIAL] = &HRilCall::DialResponse;  
9.    respMemberFuncMap_[HREQ_CALL_HANGUP] = &HRilCall::HangupResponse;  
10.    respMemberFuncMap_[HREQ_CALL_REJECT] = &HRilCall::RejectResponse;  
11.    respMemberFuncMap_[HREQ_CALL_ANSWER] = &HRilCall::AnswerResponse;  
12.    respMemberFuncMap_[HREQ_CALL_HOLD] = &HRilCall::HoldResponse;  
13.    respMemberFuncMap_[HREQ_CALL_ACTIVE] = &HRilCall::ActiveResponse;  
14.    respMemberFuncMap_[HREQ_CALL_SWAP] = &HRilCall::SwapResponse;  
15.    respMemberFuncMap_[HREQ_CALL_DEAL_CLIP] = &HRilCall::GetClipResponse;  
16.    respMemberFuncMap_[HREQ_CALL_SET_CLIP] = &HRilCall::SetClipResponse;  
17.    respMemberFuncMap_[HREQ_CALL_JOIN] = &HRilCall::JoinResponse;  
18.    respMemberFuncMap_[HREQ_CALL_SPLIT] = &HRilCall::SplitResponse;  
19.    respMemberFuncMap_[HREQ_CALL_SUPPLEMENT] = &HRilCall::CallSupplementResponse;  
20.    respMemberFuncMap_[HREQ_CALL_GET_CALL_WAIT] = &HRilCall::GetCallWaitResponse;  
21.    respMemberFuncMap_[HREQ_CALL_SET_CALL_WAIT] = &HRilCall::SetCallWaitResponse;  
22.    respMemberFuncMap_[HREQ_CALL_GET_CALL_FORWARDING] = &HRilCall::GetCallForwardResponse;  
23.    respMemberFuncMap_[HREQ_CALL_SET_CALL_FORWARDING] = &HRilCall::SetCallForwardResponse;  
24.    respMemberFuncMap_[HREQ_CALL_GET_CALL_RESTRICTION] = &HRilCall::GetCallRestrictionResponse;  
25.    respMemberFuncMap_[HREQ_CALL_SET_CALL_RESTRICTION] = &HRilCall::SetCallRestrictionResponse;  
26.    respMemberFuncMap_[HREQ_CALL_DEAL_CLIR] = &HRilCall::GetClirResponse;  
27.    respMemberFuncMap_[HREQ_CALL_SET_CLIR] = &HRilCall::SetClirResponse;  
28.    respMemberFuncMap_[HREQ_CALL_START_DTMF] = &HRilCall::StartDtmfResponse;  
29.    respMemberFuncMap_[HREQ_CALL_SEND_DTMF] = &HRilCall::SendDtmfResponse;  
30.    respMemberFuncMap_[HREQ_CALL_STOP_DTMF] = &HRilCall::StopDtmfResponse;  
31.  
32.    // request  
33.    reqMemberFuncMap_[HREQ_CALL_GET_CALL_LIST] = &HRilCall::GetCallList;  
34.    reqMemberFuncMap_[HREQ_CALL_DIAL] = &HRilCall::Dial;  
35.    reqMemberFuncMap_[HREQ_CALL_HANGUP] = &HRilCall::Hangup;  
36.    reqMemberFuncMap_[HREQ_CALL_REJECT] = &HRilCall::Reject;  
37.    reqMemberFuncMap_[HREQ_CALL_ANSWER] = &HRilCall::Answer;  
38.    reqMemberFuncMap_[HREQ_CALL_HOLD] = &HRilCall::Hold;  
39.    reqMemberFuncMap_[HREQ_CALL_ACTIVE] = &HRilCall::Active;  
40.    reqMemberFuncMap_[HREQ_CALL_SWAP] = &HRilCall::Swap;  
41.    reqMemberFuncMap_[HREQ_CALL_DEAL_CLIP] = &HRilCall::GetClip;  
42.    reqMemberFuncMap_[HREQ_CALL_SET_CLIP] = &HRilCall::SetClip;  
43.    reqMemberFuncMap_[HREQ_CALL_JOIN] = &HRilCall::Join;  
44.    reqMemberFuncMap_[HREQ_CALL_SPLIT] = &HRilCall::Split;  
45.    reqMemberFuncMap_[HREQ_CALL_SUPPLEMENT] = &HRilCall::CallSupplement;  
46.    reqMemberFuncMap_[HREQ_CALL_GET_CALL_WAIT] = &HRilCall::GetCallWait;  
47.    reqMemberFuncMap_[HREQ_CALL_SET_CALL_WAIT] = &HRilCall::SetCallWait;  
48.    reqMemberFuncMap_[HREQ_CALL_GET_CALL_FORWARDING] = &HRilCall::GetCallForward;  
49.    reqMemberFuncMap_[HREQ_CALL_SET_CALL_FORWARDING] = &HRilCall::SetCallForward;  
50.    reqMemberFuncMap_[HREQ_CALL_GET_CALL_RESTRICTION] = &HRilCall::GetCallRestriction;  
51.    reqMemberFuncMap_[HREQ_CALL_SET_CALL_RESTRICTION] = &HRilCall::SetCallRestriction;  
52.    reqMemberFuncMap_[HREQ_CALL_DEAL_CLIR] = &HRilCall::GetClir;  
53.    reqMemberFuncMap_[HREQ_CALL_SET_CLIR] = &HRilCall::SetClir;  
54.    reqMemberFuncMap_[HREQ_CALL_START_DTMF] = &HRilCall::StartDtmf;  
55.    reqMemberFuncMap_[HREQ_CALL_SEND_DTMF] = &HRilCall::SendDtmf;  
56.    reqMemberFuncMap_[HREQ_CALL_STOP_DTMF] = &HRilCall::StopDtmf;  
57.}  

​ 打电话请求(Dial)处理函数举例:

1.void HRilCall::Dial(int32_t slotId, struct HdfSBuf *data)  
2.{  
3.    const int32_t NUM_POINTERS = 1;  
4.    DialInfo dialInfo = DialInfo();  
5.    MessageParcel *parcel = nullptr;  
6.    if (data == nullptr) {  
7.        TELEPHONY_LOGE("RilAdapter Dial data is null!");  
8.        return;  
9.    }  
10.    if (SbufToParcel(data, &parcel)) {  
11.        TELEPHONY_LOGE("RilAdapter failed to do SbufToParcel");  
12.        return;  
13.    }  
14.    if (!dialInfo.ReadFromParcel(*parcel)) {  
15.        TELEPHONY_LOGE("RilAdapter failed to do ReadFromParcel!");  
16.        return;  
17.    }  
18.  
19.    ReqDataInfo *requestInfo = CreateHRilRequest(dialInfo.serial, slotId, HREQ_CALL_DIAL);  
20.    if (requestInfo == nullptr) {  
21.        TELEPHONY_LOGE("RilAdapter failed to do Create Dial HRilRequest!");  
22.        return;  
23.    }  
24.    HRilDial dial = {};  
25.  
26.    if (!ConvertToString(&dial.address, dialInfo.address, requestInfo)) {  
27.        TELEPHONY_LOGE("RilAdapter failed to do ConvertToString!");  
28.        free(requestInfo);  
29.        return;  
30.    }  
31.    dial.clir = (int32_t)dialInfo.clir;  
32.    if (callFuncs_ == nullptr) {  
33.        FreeStrings(NUM_POINTERS, dial.address);  
34.        TELEPHONY_LOGE("RilAdapter HRilCall::Dial  callFuncs_ is nullptr!");  
35.        free(requestInfo);  
36.        return;  
37.    }  
38.    callFuncs_->Dial(requestInfo, &dial, sizeof(HRilDial));  
39.    FreeStrings(NUM_POINTERS, dial.address);  
40.    free(requestInfo);  
41.}  

​ 打电话请求(Dial)response处理:

1.int32_t HRilCall::DialResponse(int32_t slotId,int32_t requestNum, HRilRadioResponseInfo &responseInfo, const void *response, size_t responseLen)  
3.{  
4.    return ResponseRequestInfo(requestNum, &responseInfo, sizeof(responseInfo));  
5.}  

4.3 Modem消息处理

​ read Loop监听到Modem上送信息,处理流程如下:

​ 1、首先处理Error、Success简单应答信息,再处理短信业务(因为短信业务信息的文本格式非常固定,共有两行line1和line2,所以做优先特殊处理),其它业务统一处理;

1.void ProcessResponse(const char *responseLine, const char *pdu)  
2.{  
3.    if (responseLine == NULL) {  
4.        TELEPHONY_LOGE("%{public}s enter s is null", __func__);  
5.        return;  
6.    }  
7.    TELEPHONY_LOGD("processLine line = %{public}s", responseLine);  
8.  
9.    int isPrefix = ReportStrWith(responseLine, (const char*)g_prefix);  
10.    pthread_mutex_lock(&g_commandmutex);  
11.    if (g_response == NULL) {  
12.        if (g_onNotifyFunc != NULL) {  
13.            pthread_mutex_unlock(&g_commandmutex);  
14.  
15.            g_onNotifyFunc(responseLine, pdu);  
16.            return;  
17.        }  
18.    } else if (IsResponseError(responseLine)) {  
19.        if (g_response != NULL) {  
20.            g_response->success = 0;  
21.            g_response->result = strdup(responseLine);  
22.        }  
23.        pthread_cond_signal(&g_commandcond);  
24.    } else if (IsResponseSuccess(responseLine)) {  
25.        if (g_response != NULL) {  
26.            g_response->success = 1;  
27.            g_response->result = strdup(responseLine);  
28.        }  
29.        pthread_cond_signal(&g_commandcond);  
30.    } else if (IsSms(responseLine) && g_smsPdu != NULL) {  
31.        if (g_response != NULL) {  
32.            g_response->result = strdup(responseLine);  
33.        }  
34.        WriteATCommand((const char *)g_smsPdu, 1, g_atFd);  
35.    } else {  
36.        if (((isdigit(responseLine[0]) || isPrefix) && g_smsPdu == NULL) || (g_smsPdu != NULL && isPrefix)) {  
37.            AddLinkListNode(responseLine);  
38.        } else {  
39.            if (g_onNotifyFunc != NULL) {  
40.                pthread_mutex_unlock(&g_commandmutex);  
41.  
42.                g_onNotifyFunc(responseLine, pdu);  
43.                return;  
44.            }  
45.        }  
46.    }  
47.    pthread_mutex_unlock(&g_commandmutex);  
48.}  

​ 2、解析消息,匹配调用对应业务处理函数;

1.void OnNotifyOps(const char *s, const char *smsPdu)  
2.{  
3.    char *str = NULL;  
4.    struct ReportInfo reportInfo = {0};  
5.    reportInfo.error = HRIL_ERR_SUCCESS;  
6.    reportInfo.type = HRIL_NOTIFICATION;  
7.  
8.    if (GetRadioState() == HRIL_RADIO_POWER_STATE_UNAVAILABLE) {  
9.        return;  
10.    }  
11.    TELEPHONY_LOGD("enter to [%{public}s]:%{public}s", s, smsPdu);  
12.  
13.    str = strdup(s);  
14.    if (IsCallNoticeCmd(s)) {  
15.        CallResportInfoProcess(s);  
16.    } else if (ReportStrWith(s, "+CMT:")) {  
17.        reportInfo.notifyId = HNOTI_SMS_NEW_SMS;  
18.        OnSmsReport(HRIL_SIM_SLOT_1, reportInfo, (const uint8_t *)smsPdu, strlen(smsPdu));  
19.    } else if (ReportStrWith(s, "+CDS:")) {  
20.        int size = (smsPdu != NULL) ? strlen(smsPdu) : 0;  
21.        reportInfo.notifyId = HNOTI_SMS_STATUS_REPORT;  
22.        OnSmsReport(HRIL_SIM_SLOT_1, reportInfo, (const uint8_t *)smsPdu, size);  
23.    } else if (ReportStrWith(s, "+CBM:") || ReportStrWith(s, "+CSCB:")) {  
24.        ReportCBMOrCSCB(&reportInfo);  
25.        ReportCBMOrCSCB(&reportInfo); // The test requires sending two  
26.    } else if (ReportStrWith(s, "+COPS: (")) {  
27.        char *copsstr = strdup(s);  
28.        ProcessOperListToUse(copsstr);  
29.        free(copsstr);  
30.    } else if (ReportStrWith(s, "^SIMST:")) {  
31.        reportInfo.notifyId = HNOTI_SIM_STATUS_CHANGED;  
32.        OnSimReport(HRIL_SIM_SLOT_1, reportInfo, NULL, 0);  
33.    } else {  
34.        OnNotifyNetWorksOps(s, str);  
35.    }  
36.    free(str);  
37.}  

​ 3、以call业务为例,OnCallReport分开处理response和notification消息;

1.void OnCallReport(struct ReportInfo reportInfo, const void *response, 
                    size_t responseLen)  
2.{  
3.    if (g_reportOps != NULL) {  
4.        g_reportOps->OnCallReport(reportInfo, response, responseLen);  
5.    } else {  
6.        TELEPHONY_LOGE("g_reportOps is NULL");  
7.    }  
8.}  
1.void HRilManager::OnCallReport(struct ReportInfo *reportInfo, const void *response, 
                                 size_t responseLen)  
2.{  
3.    if (reportInfo == nullptr) {  
4.        TELEPHONY_LOGE("OnCallReport reportInfo is null!!!");  
5.        return;  
6.    }  
7.    switch (reportInfo->type) {  
8.        case (int32_t)ReportType::HRIL_RESPONSE: {  
9.            ReqDataInfo *reqInfo = nullptr;  
10.            HRilSimId simId = HRIL_SIM_1;  
11.            reqInfo = (ReqDataInfo *)reportInfo->requestInfo;  
12.            simId = reqInfo->simId;  
13.            HRilRadioResponseInfo responseInfo = {};  
14.            responseInfo.serial = reqInfo->serial;  
15.            responseInfo.error = (HRilErrType)reportInfo->error;  
16.            hrilCall_->ProcessCallResponse(simId, reqInfo->request, responseInfo, response, responseLen);  
17.            break;  
18.        }  
19.        case (int32_t)ReportType::HRIL_NOTIFICATION: {  
20.            hrilCall_->ProcessCallNotify(  
21.                reportInfo->notifyId, HRIL_NOTIFICATION_TYPE, reportInfo->error, response, responseLen);  
22.            break;  
23.        }  
24.        default:  
25.            break;  
26.    }  
27.}  

​ 4、response消息处理;

1.void HRilCall::ProcessCallResponse(int32_t slotId, int32_t code, HRilRadioResponseInfo  2.                       &responseInfo, const void *response, size_t responseLen)  
3.{  
4.    auto itFunc = respMemberFuncMap_.find(code);  
5.    if (itFunc != respMemberFuncMap_.end()) {  
6.        auto memberFunc = itFunc->second;  
7.        if (memberFunc != nullptr) {  
8.            (this->*memberFunc)(slotId, code, responseInfo, response, responseLen);  
9.        }  
10.    } else {  
11.        TELEPHONY_LOGE("not fund resqfunc: %{public}d", code);  
12.    }  
13.}  

​ 如果匹配为Dial应答消息,封装处理后上送给业务。

1.int32_t HRilCall::DialResponse(int32_t slotId, int32_t requestNum,HRilRadioResponseInfo2.                  &responseInfo, const void *response, size_t responseLen)  
3.{  
4.    return ResponseRequestInfo(requestNum, &responseInfo, sizeof(responseInfo));  
5.}  
6.  
7.  
8.int32_t HRilBase::ResponseRequestInfo(int32_t requestNum, const void *responseInfo, 
                                        uint32_t reqLen)  
9.{  
10.    struct HdfSBuf *dataSbuf = HdfSBufTypedObtain(SBUF_IPC);  
11.    if (dataSbuf == nullptr) {  
12.        return HDF_FAILURE;  
13.    }  
14.    if (!HdfSbufWriteUnpadBuffer(dataSbuf, (const uint8_t *)responseInfo, reqLen)) {  
15.        HdfSBufRecycle(dataSbuf);  
16.        return HDF_FAILURE;  
17.    }  
18.    int32_t ret = serviceCallback_->dispatcher->Dispatch(serviceCallback_, 
                                              requestNum, dataSbuf, nullptr);  
19.    if (ret != HDF_SUCCESS) {  
20.        HdfSBufRecycle(dataSbuf);  
21.        return HDF_FAILURE;  
22.    }  
23.    if (dataSbuf != nullptr) {  
24.        HdfSBufRecycle(dataSbuf);  
25.    }  
26.    return HDF_SUCCESS;  
27.}  

​ 5、notification消息处理,匹配后封装上送给业务。

1.void HRilCall::ProcessCallNotify(int32_t code, int32_t notifyType, HRilErrno e, 
2.                                   const void *response, size_t responseLen)  
3.{  
4.    auto itFunc = notiMemberFuncMap_.find(code);  
5.    if (itFunc != notiMemberFuncMap_.end()) {  
6.        auto memberFunc = itFunc->second;  
7.        if (memberFunc != nullptr) {  
8.            int32_t slotId = 0;  
9.            (this->*memberFunc)(slotId, notifyType, e, response, responseLen);  
10.        }  
11.    } else {  
12.        TELEPHONY_LOGE("not fund notifunc: %{public}d", code);  
13.    }  
14.}  
15.  
16.int32_t HRilCall::CallStateUpdated(int32_t slotId, int32_t notifyType, 
                           const HRilErrno e, const void *response, size_t responseLen)  
18.{  
19.    struct HdfSBuf *dataSbuf = HdfSBufTypedObtain(SBUF_IPC);  
20.    if (serviceCallbackNotify_ == nullptr) {  
21.        TELEPHONY_LOGE("RilAdapter serviceCallbackNotify_ is null");  
22.        HdfSBufRecycle(dataSbuf);  
23.        return HDF_FAILURE;  
24.    }  
25.    int32_t ret = serviceCallbackNotify_->dispatcher->Dispatch(  
26.        serviceCallbackNotify_, HNOTI_CALL_STATE_UPDATED, dataSbuf, nullptr);  
27.    if (ret != HDF_SUCCESS) {  
28.        HdfSBufRecycle(dataSbuf);  
29.        return HDF_FAILURE;  
30.    }  
31.    HdfSBufRecycle(dataSbuf);  
32.    return HDF_SUCCESS;  
33.} 

5 总结

​ 本文档对电话子系统中的RIL Adapter功能、架构、核心源码流程做了简单介绍,目前该模块正在不断开源更新中,该文中涉及代码部分不一定是最新的。

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

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

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-1-13 16:07:51修改
5
收藏 1
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐