OpenHarmony源码解析之RIL Adapter 原创 精华
作者:杨金壮
1 简介
RIL(Radio Interface Layer)是Telephony和Modem之间的抽象层,用于实现Telephony和Modem之间的通信转换。Modem厂商有高通、mtk、海思、展讯等,不同的Modem在接口、内部机制、实现方式等方面都有不同。RIL Adapter屏蔽不同Modem厂商硬件差异,为上层提供统一的接口。
1.1 OpenHarmony 架构图
RIL Adapter在OpenHarmony 架构中属于电话子系统,如下图所示。
图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两种。
图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命令包括:基本命令和扩展命令。扩展命令以字符“+”为前缀,并需要使用分号“;”与前面的命令分隔开。
图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 代码流程
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 相关仓
-
注册服务 :https://gitee.com/openharmony/telephony_state_registry
-
riladapter:https://gitee.com/openharmony/telephony_ril_adapter
-
网络管理 :https://gitee.com/openharmony/communication_netmanager_standard
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开发技术,共建鸿蒙生态,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
开鸿老师总结的太全面了,必须好好学习一下。