• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 电话服务开发指导
2
3
4## Modem厂商库初始化开发指导
5
6
7### 场景介绍
8
9Modem厂商库初始化是指在厂商库里实现const HRilOps \*RilInitOps(const struct HRilReport \*reportOps)函数,在该函数里处理三个重要的功能:
10
11- 接收RIL Adapter事件回调的函数指针,当Modem有业务事件上报时,调用对应的函数指针,把事件上报给RIL Adapter。
12
13- 创建读取Modem设备节点的线程,在该线程里会循环地读取Modem上报的事件,并把接收的Modem信息解析为具体业务相关的事件进行上报。
14
15- 返回业务请求接口的函数指针给RIL Adapter。
16
17
18### 接口说明
19
20Modem厂商库初始化接口。
21
22  **表1** Modem厂商库初始化接口功能介绍
23
24| 接口名 | 描述 |
25| -------- | -------- |
26| const&nbsp;HRilOps&nbsp;\*RilInitOps(const&nbsp;struct&nbsp;HRilReport&nbsp;\*&nbsp;reportOps) | 接口功能:Modem厂商库运行的入口。<br/>参数reportOps:RIL&nbsp;Adapter传入的事件回调函数指针。<br/>返回值:业务请求接口的函数指针。 |
27
28
29### 开发步骤
30
31
321. RilInitOps接口中设置RIL Adapter传入的事件回调函数指针。
33
34   ```
35   // 定义Modem厂商库回调函数指针
36   static struct HRilReport g_reportOps = {
37       OnCallReport,    // 通话相关业务回调函数
38       OnDataReport,    // 蜂窝数据相关业务回调函数
39       OnModemReport,   // Modem相关业务回调函数
40       OnNetworkReport, // 搜网相关业务回调函数
41       OnSimReport,     // SIM卡相关业务回调函数
42       OnSmsReport      // 短信相关业务回调函数
43   };
44   ```
45
46
471. 创建主线程g_reader,开启消息循环。
48
49   ```
50   pthread_attr_t t;
51   pthread_attr_init(&t);
52   pthread_attr_setdetachstate(&t, PTHREAD_CREATE_DETACHED);
53   ret = pthread_create(&g_reader, &t, ReaderLoop, &t); // 创建线程
54   ```
55
56
571. 在g_eventListeners线程用open()打开Modem设备节点,并创建g_reader线程循环读取处理Modem上报的消息。
58
59   ```
60   g_fd = open(g_devicePath, O_RDWR); // 打开设备节点,入参g_devicePath是Modem设备节点
61   pthread_attr_init(&attr);
62   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
63   ret = pthread_create(&g_eventListeners, &attr, EventListeners, NULL);
64   ```
65
66
671. 返回业务请求接口的函数指针。
68
69   ```
70   // call模块业务请求接口结构体
71   typedef struct {
72       // 获取呼叫列表
73       void (*GetCallList)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);
74       // 拨打电话
75       void (*Dial)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);
76       // 挂断电话
77       void (*Hangup)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);
78       // 拒接来电
79       void (*Reject)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);
80       // 接听来电
81       void (*Answer)(ReqDataInfo *requestInfo, const void *data, size_t dataLen);
82   } HRilCallReq;
83
84   // call模块回调函数指针
85   static const HRilCallReq g_callReqOps = {
86       .GetCallList = ReqGetCallList, // 获取呼叫列表接口
87       .Dial = ReqDial,               // 拨打电话接口
88       .Hangup = ReqHangup,           // 挂断电话接口
89       .Reject = ReqReject,           // 拒接来电接口
90       .Answer = ReqAnswer,           // 接听来电接口
91   };
92
93   // 业务请求结构体
94   typedef struct {
95       const HRilCallReq *callOps;       // 通话相关业务请求结构体指针
96       const HRilSimReq *simOps;         // SIM卡相关业务请求结构体指针
97       const HRilSmsReq *smsOps;         // 短彩信相关业务请求结构体指针
98       const HRilDataReq *dataOps;       // 蜂窝数据相关业务请求结构体指针
99       const HRilNetworkReq *networkOps; // 搜网相关业务请求结构体指针
100       const HRilModemReq *modemOps;     // Modem相关业务请求结构体指针
101   } HRilOps;
102
103   // 业务请求接口定义
104   HRilOps g_hrilOps = {
105       .callOps = &g_callReqOps,       // 定义通话业务请求接口
106       .simOps = &g_simReqOps,         // 定义SIM卡业务请求接口
107       .smsOps = &g_smsReqOps,         // 定义短彩信业务请求接口
108       .networkOps = &g_networkReqOps, // 定义蜂窝数据业务请求接口
109       .dataOps = &g_dataReqOps,       // 定义搜网业务请求接口
110       .modemOps = &g_modemReqOps,     // 定义Modem业务请求接口
111   };
112   ```
113
114
115### 调测验证
116
1171. 用[hdc_std工具](../subsystems/subsys-toolchain-hdc-guide.md#环境准备)连接调试设备,把编译生成的libril_vendor.z.so库文件(参见[Modem厂商库集成指导](#modem厂商库集成指导))通过以下命令推到/system/lib/目录下。
118
119   ```
120   hdc_std file send libril_vendor.z.so /system/lib/
121   ```
122
1232. 执行hdc_std shell sync,hdc_std shell reboot重启设备。
124
125   ```
126   hdc_std shell sync
127   hdc_std shell reboot
128   ```
129
1303. 执行hdc_std shell hilog,根据日志查看函数RilInitOps()是否正确执行完成。如下调测验证日志供参考:
131
132   ```
133   09-02 07:40:47.807   455   455 I 01f08/HrilHdf: [LoadVendor-(hril_hdf.c:148)] RilInit LoadVendor start with rilLibPath:libril_vendor.z.so
134   09-02 07:40:47.830   455   455 I 01f08/HrilHdf: [LoadVendor-(hril_hdf.c:163)] HRilRegOps completed
135   ```
136
137
138## Modem业务请求及响应开发指导
139
140
141### 场景介绍
142
143Modem业务请求及响应是指RIL Adapter收到电话服务具体业务请求后,调用Modem厂商库初始化获得的函数指针,把具体业务请求发送给厂商库,厂商库根据业务请求ID做相应的业务处理。
144
145
146### 接口说明
147
148Modem业务请求及响应接口。
149
150  **表2** Modem业务请求及响应接口功能介绍(以拨号功能模块为例)
151
152| 接口名 | 描述 |
153| -------- | -------- |
154| void&nbsp;ReqDial(ReqDataInfo&nbsp;\*requestInfo,&nbsp;const&nbsp;void&nbsp;\*data,&nbsp;size_t&nbsp;dataLen); | 接口功能:对拨号请求进行处理。<br/>参数requestInfo:请求类型信息。<br/>参数data:被叫号码信息。<br/>参数dataLen:数据长度。<br/>返回值:无。 |
155| void&nbsp;(\*OnCallReport)(struct&nbsp;ReportInfo&nbsp;reportInfo,&nbsp;const&nbsp;void&nbsp;\*data,&nbsp;size_t&nbsp;dataLen); | 接口功能:对通话业务执行结果进行响应,即当请求业务执行完成后,Modem将该请求执行的结果上报给RIL&nbsp;Adapter。<br/>参数reportInfo:返回类型信息。<br/>参数data:返回数据。<br/>参数dataLen:数据长度。<br/>返回值:无。 |
156
157
158### 开发步骤
159
1601. 在ReqDial()接口中对拨号请求进行处理。
161
162   ```
163   // 拨号请求接口实现
164   void ReqDial(ReqDataInfo *requestInfo, const void *data, size_t dataLen)
165   {
166       HRilDial *pDial = NULL;
167       char cmd[MAX_BUFF_SIZE] = {0};
168       const char *clir = NULL;
169       int ret;
170       int err = HRIL_ERR_SUCCESS;
171       struct ReportInfo reportInfo = {};
172       ResponseInfo *pResponse = NULL;
173       if (data == NULL) {
174           TELEPHONY_LOGE("data is null!!!");
175           err = HRIL_ERR_INVALID_PARAMETER;
176           reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0);
177           OnCallReport(reportInfo, NULL, 0);
178           return;
179       }
180       pDial = (HRilDial *)data;
181       switch (pDial->clir) {
182           case CALL_CLIR_INVOCATION:
183               clir = "I";
184               break; /* invocation */
185           case CALL_CLIR_SUPPRESSION:
186               clir = "i";
187               break; /* suppression */
188           case CALL_CLIR_SUBSCRIPTION_DEFUALT:
189           default:
190               clir = "";
191               break; /* subscription default */
192       }
193       (void)sprintf_s(cmd, MAX_BUFF_SIZE, "ATD%s%s;", pDial->address, clir);
194       ret = SendCommandLock(cmd, NULL, 0, &pResponse); // 发送AT指令
195       ......
196   }
197   ```
198
1992. 在Modem执行完拨号命令后,调用OnCallReport()回调函数,把该请求执行的结果上报给RIL Adapter。
200
201   ```
202   ret = SendCommandLock(cmd, NULL, 0, &pResponse);
203   if (ret != 0 || (pResponse != NULL && pResponse->success == 0)) {
204       TELEPHONY_LOGE("ATD send failed");
205       err = HRIL_ERR_GENERIC_FAILURE;
206   }
207   reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0);
208   OnCallReport(reportInfo, NULL, 0); // 调用通话相关回调函数
209   ```
210
211
212### 调测验证
213
2141. 用[hdc_std工具](../subsystems/subsys-toolchain-hdc-guide.md#环境准备)工具连接调试设备,把编译生成的libril_vendor.z.so库文件通过以下命令推到/system/lib/目录下。
215
216   ```
217   hdc_std file send libril_vendor.z.so /system/lib/
218   ```
219
2202. 执行hdc_std shell sync,hdc_std shell reboot重启设备。
221
222   ```
223   hdc_std shell sync
224   hdc_std shell reboot
225   ```
226
2273. hdc_std shell后执行./system/bin/ril_adapter_test,输入编号1,根据提示输入电话号码,测试拨打电话功能。
228
229   ```
230   hdc_std shell
231   # ./system/bin/ril_adapter_test
232   ----> Test Enter  --------->Call---------------------
233
234   1----> RilUnitTest::OnRequestCallDialTest
235   2----> RilUnitTest:: OnRequestCallHangupTest
236   3----> RilUnitTest:: OnRequestCallAnswerTest
237   4----> RilUnitTest::OnRequestCallGetCurrentCallsStatusTest
238   5----> RilUnitTest::OnRequestRefusedCallTest
239
240   1
241   ```
242
2434. 另开一个终端窗口,执行hdc_std shell hilog,通过日志查看函数ReqDial()是否正确执行完成。如下调测验证日志供参考:
244
245   ```
246   09-02 07:55:09.073   455  2059 I 01f08/RilVendor: [SendCommandLock-(at_support.c:226)] command ATD18675231804;, NeedATPause:0, atCmd:AT
247   09-02 07:55:09.099   455  2053 I 01f08/Rilvendor: [ProcessResponse-(at_support.c:159)] processLine line = OK
248   09-02 07:55:09.100   455  2053 E 01f08/RilVendor: [ReportStrWith-(vendor_util.c:63)] str or prefix parameter is null.
249   09-02 07:55:09.100   455  2053 E 01f08/RilVendor: [ProcessLastResponse-(vendor_channel.c:77)] g_bufferCur endLine is null
250   09-02 07:55:09.100   455  2059 I 01f08/RilVendor: [SendCommandLock-(at_support.c:243)] err = 0
251   09-02 07:55:09.100   455  2053 I 01f08/RilVendor: [ProcessResponse-(at_support.c:159)] processLine line = ^ORIG:1,0
252   ```
253
254
255## Modem事件上报开发指导
256
257
258### 场景介绍
259
260Modem事件上报是指在厂商库的Modem设备节点读取线程,循环读取到Modem主动上报的消息后,对Modem上报事件进行解析,然后上报给RIL Adapter。
261
262
263### 接口说明
264
265Modem事件上报接口。
266
267  **表3** Modem事件上报接口功能介绍
268
269| 接口名 | 描述 |
270| -------- | -------- |
271| void&nbsp;OnNotifyOps(const&nbsp;char&nbsp;\*s,&nbsp;const&nbsp;char&nbsp;\*smsPdu) | 接口功能:对Modem上报的事件进行分发处理。<br/>参数s:AT指令前缀。<br/>参数smsPdu:短信PDU信息。<br/>返回值:无。 |
272
273
274### 开发步骤
275
2761. 在Modem设备节点读取线程g_reader里调用OnNotifyOps()解析具体的Modem上报事件,判断命令类型,并调用OnXxxReport()把解析得到的各模块事件上报给hril业务层。
277
278   ```
279   // 将Modem上报数据解析为对应模块的主动上报事件
280   void OnNotifyOps(const char *s, const char *smsPdu)
281   {
282       int ret = 0;
283       struct ReportInfo reportInfo = {0};
284       reportInfo.error = HRIL_ERR_SUCCESS;
285       reportInfo.type = HRIL_NOTIFICATION;
286       if (GetRadioState() == HRIL_RADIO_POWER_STATE_UNAVAILABLE) {
287           return;
288       }
289       TELEPHONY_LOGD("enter to [%{public}s]:%{public}s", s, smsPdu);
290       // 通过AT指令判断主动上报命令类型
291       if (ReportStrWith(s, "+CRING:") || ReportStrWith(s, "RING") || ReportStrWith(s, "IRING") ||
292           ReportStrWith(s, "NO CARRIER") || ReportStrWith(s, "+CCWA") || ReportStrWith(s, "^CCALLSTATE") ||
293           ReportStrWith(s, "^CEND") || ReportStrWith(s, "^CCWA")) {
294           reportInfo.notifyId = HNOTI_CALL_STATE_UPDATED;
295           OnCallReport(reportInfo, NULL, 0);
296       } else if (ReportStrWith(s, "+CMT:")) {
297           reportInfo.notifyId = HNOTI_SMS_NEW_SMS;
298           OnSmsReport(reportInfo, (void *)smsPdu, strlen(smsPdu));
299       }
300       // 将各模块事件上报给hril业务层
301       ......
302   }
303   ```
304
3051. hril业务层将上报事件分发给Telephony Service。
306
307   ```
308   // 呼叫状态主动上报
309   int32_t HRilCall::CallStateUpdated(
310       int32_t slotId, int32_t notifyType, const HRilErrno e, const void *response, size_t responseLen)
311   {
312       struct HdfSBuf *dataSbuf = HdfSBufTypedObtain(SBUF_IPC);
313       if (serviceCallbackNotify_ == nullptr) {
314           TELEPHONY_LOGE("RilAdapter serviceCallbackNotify_ is null");
315           HdfSBufRecycle(dataSbuf);
316           return HDF_FAILURE;
317       }
318       // 分发处理
319       int32_t ret = serviceCallbackNotify_->dispatcher->Dispatch(
320           serviceCallbackNotify_, HNOTI_CALL_STATE_UPDATED, dataSbuf, nullptr);
321       if (ret != HDF_SUCCESS) {
322           HdfSBufRecycle(dataSbuf);
323           return HDF_FAILURE;
324       }
325       HdfSBufRecycle(dataSbuf);
326       return HDF_SUCCESS;
327   }
328   ```
329
330
331### 调测验证
332
3331. 用[hdc_std工具](../subsystems/subsys-toolchain-hdc-guide.md#环境准备)工具连接调试设备,把编译生成的libril_vendor.z.so库文件通过以下命令推到/system/lib/目录下。
334
335   ```
336   hdc_std file send libril_vendor.z.so /system/lib/
337   ```
338
3392. 执行hdc_std shell sync,hdc_std shell reboot重启设备。
340
341   ```
342   hdc_std shell sync
343   hdc_std shell reboot
344   ```
345
3463. hdc_std shell后执行./system/bin/ril_adapter_test,输入编号1,根据提示输入电话号码,测试拨打电话功能。
347
348   ```
349   hdc_std shell
350   # ./system/bin/ril_adapter_test
351   ----> Test Enter  --------->Call---------------------
352
353   1----> RilUnitTest::OnRequestCallDialTest
354   2----> RilUnitTest:: OnRequestCallHangupTest
355   3----> RilUnitTest:: OnRequestCallAnswerTest
356   4----> RilUnitTest::OnRequestCallGetCurrentCallsStatusTest
357   5----> RilUnitTest::OnRequestRefusedCallTest
358
359   1
360   ```
361
3624. 另开一个终端窗口,执行hdc_std shell hilog,通过日志查看函数OnNotifyOps()是否正确执行完成。如下调测验证日志供参考:
363
364   ```
365   01-01 00:08:01.334   546   551 D 02b01/TelRilTest: [DialResponse-(tel_ril_call.cpp:280)] DialResponse --> radioResponseInfo->serial:2, radioResponseInfo->error:0
366   01-01 00:08:01.334   546   557 D 02b01/TelRilTest: [ProcessEvent-(tel_ril_test.cpp:1262)] TelRilTest::DemoHandler::ProcessEvent --> eventId:101
367   01-01 00:08:01.334   143   512 D 02b01/Rilvendor: [ReadResponse-(channel.c:93)] g_bufferCur :
368   01-01 00:08:01.334   143   512 D 02b01/Rilvendor: ^ORIG:1,0
369   01-01 00:08:01.334   143   512 D 02b01/Rilvendor: [ReadResponse-(channel.c:108)] AT< ^ORIG:1,0
370   01-01 00:08:01.334   143   512 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:137)] processLine line = ^ORIG:1,0
371   01-01 00:08:01.334   143   512 D 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:126)] enter to [^ORIG:1,0]:(null)
372   01-01 00:08:01.335   143   512 W 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:167)] enter to  is unrecognized command: ^ORIG:1,0
373   01-01 00:08:01.335   143   512 D 02b01/Rilvendor: [ProcessLastResponse-(channel.c:37)] last data more than one line , FindEndOfLine  g_bufferCur:
374   01-01 00:08:01.335   143   512 E 02b01/Rilvendor: [ProcessLastResponse-(channel.c:39)] g_bufferCur endLine is null
375   01-01 00:08:01.336   143   512 D 02b01/Rilvendor: [ReadResponse-(channel.c:93)] g_bufferCur :
376   01-01 00:08:01.336   143   512 D 02b01/Rilvendor: ^CCALLSTATE: 1,0,1
377   01-01 00:08:01.336   143   512 D 02b01/Rilvendor: [ReadResponse-(channel.c:108)] AT< ^CCALLSTATE: 1,0,1
378   01-01 00:08:01.336   143   512 D 02b01/Rilvendor: [ProcessResponse-(at_support.c:137)] processLine line = ^CCALLSTATE: 1,0,1
379   01-01 00:08:01.336   143   512 D 02b01/Rilvendor: [OnNotifyOps-(vendor_report.c:126)] enter to [^CCALLSTATE: 1,0,1]:(null)
380   01-01 00:08:01.336   546   551 D 02b01/CoreService: [OnRemoteRequest-(tel_ril_manager.cpp:80)] RilManager OnRemoteRequest code:1001
381   01-01 00:08:01.336   546   551 D 02b01/CoreService: [NotifyObserver-(observer_handler.cpp:76)] handler->SendEvent:8
382   ```
383
384
385### 开发实例
386
387- **去电开发实例**
388    去电的调用流程示例如下图所示:
389    **图1** 去电调用时序图
390
391  ![zh-cn_image_0000001171507146](figures/zh-cn_image_0000001171507146.png)
392
393    当应用触发去电动作时,RIL Adapter会接收到拨打电话的请求,hril调用对应的拨打电话的接口ReqDial()。在该接口里会把电话服务传过来的数据封装为对应的AT指令发送到Modem,Modem执行完拨号命令后通过OnCallReport()接口把响应结果上报给RIL Adapter。
394
395  ```
396  // call模块回调函数指针
397  static const HRilCallReq g_callReqOps = {
398      .GetCallList = ReqGetCallList, // 获取呼叫列表接口
399      .Dial = ReqDial,               // 拨打电话接口
400      .Hangup = ReqHangup,           // 挂断电话接口
401      .Reject = ReqReject,           // 拒接来电接口
402      .Answer = ReqAnswer,           // 接听来电接口
403  };
404
405  // 系统业务请求接口定义
406  HRilOps g_hrilOps = {
407      .callOps = &g_callReqOps,       // 定义通话业务请求接口
408      .simOps = &g_simReqOps,         // 定义SIM卡业务请求接口
409      .smsOps = &g_smsReqOps,         // 定义短彩信业务请求接口
410      .networkOps = &g_networkReqOps, // 定义蜂窝数据业务请求接口
411      .dataOps = &g_dataReqOps,       // 定义搜网业务请求接口
412      .modemOps = &g_modemReqOps,     // 定义Modem业务请求接口
413  };
414
415  // 拨号请求接口实现
416  void ReqDial(ReqDataInfo *requestInfo, const void *data, size_t dataLen)
417  {
418      HRilDial *pDial = NULL;
419      char cmd[MAX_BUFF_SIZE] = {0};
420      const char *clir = NULL;
421      int ret;
422      int err = HRIL_ERR_SUCCESS;
423      struct ReportInfo reportInfo = {};
424      ResponseInfo *pResponse = NULL;
425      if (data == NULL) {
426          TELEPHONY_LOGE("data is null!!!");
427          err = HRIL_ERR_INVALID_PARAMETER;
428          reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0);
429          OnCallReport(reportInfo, NULL, 0);
430          return;
431      }
432      pDial = (HRilDial *)data;
433      switch (pDial->clir) {
434          case CALL_CLIR_INVOCATION:
435              clir = "I";
436              break; /* invocation */
437          case CALL_CLIR_SUPPRESSION:
438              clir = "i";
439              break; /* suppression */
440          case CALL_CLIR_SUBSCRIPTION_DEFUALT:
441          default:
442              clir = "";
443              break; /* subscription default */
444      }
445      (void)sprintf_s(cmd, MAX_BUFF_SIZE, "ATD%s%s;", pDial->address, clir);
446      ret = SendCommandLock(cmd, NULL, 0, &pResponse); // 发送AT命令
447      if (ret != 0) {
448          err = HRIL_ERR_CMD_SEND_FAILURE;
449          TELEPHONY_LOGE("ATD send failed");
450      } else {
451          if (pResponse != NULL && pResponse->success == 0) {
452              TELEPHONY_LOGE("ReqDial return ERROR");
453              err = HRIL_ERR_CMD_NO_CARRIER;
454          }
455      }
456      reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0);
457      OnCallReport(reportInfo, NULL, 0); // 调用通话相关业务回调函数
458      FreeResponseInfo(pResponse);
459  }
460  ```
461
462
463- **来电开发实例**
464    来电的调用流程示例如下图所示:
465    **图2** 来电调用时序图
466
467  ![zh-cn_image_0000001214727595](figures/zh-cn_image_0000001214727595.png)
468
469  Modem设备节点读取线程g_reader会循环读取Modem上报的消息,当Modem接收到来电时会主动上报来电相关的信息;
470
471    当该线程通过调用OnNotifyOps()解析到Modem上报的数据是以"+CRING"、"RING"等字符开头时,表示有来电事件,然后通过OnCallReport(reportInfo, NULL, 0)上报给RIL Adapter完成来电事件上报。
472
473  ```
474  // 将Modem上报数据解析为对应模块的主动上报事件
475  void OnNotifyOps(const char *s, const char *smsPdu)
476  {
477      int ret = 0;
478      struct ReportInfo reportInfo = {0};
479      reportInfo.error = HRIL_ERR_SUCCESS;
480      reportInfo.type = HRIL_NOTIFICATION;
481      if (GetRadioState() == HRIL_RADIO_POWER_STATE_UNAVAILABLE) {
482          return;
483      }
484      TELEPHONY_LOGD("enter to [%{public}s]:%{public}s", s, smsPdu);
485      // 通过AT指令判断主动上报命令类型
486      if (ReportStrWith(s, "+CRING:") || ReportStrWith(s, "RING") || ReportStrWith(s, "IRING") ||
487          ReportStrWith(s, "NO CARRIER") || ReportStrWith(s, "+CCWA") || ReportStrWith(s, "^CCALLSTATE") ||
488          ReportStrWith(s, "^CEND") || ReportStrWith(s, "^CCWA")) {
489          reportInfo.notifyId = HNOTI_CALL_STATE_UPDATED;
490          OnCallReport(reportInfo, NULL, 0);  // 调用通话相关业务回调函数
491      } else if (ReportStrWith(s, "+CMT:")) {
492          reportInfo.notifyId = HNOTI_SMS_NEW_SMS;
493          OnSmsReport(reportInfo, (void *)smsPdu, strlen(smsPdu));
494      }
495      // add your codes
496      ......
497  }
498  ```
499
500
501## Modem厂商库集成指导
502
503
504### 编译设置
505
506Modem厂商库可通过BUILD.gn编译为一个动态库,在RIL Adapter启动时用dlopen方式加载到系统中,然后执行厂商库的初始化操作(参见[Modem厂商库初始化开发指导](#modem厂商库初始化开发指导)),BUILD.gn编写示例如下:
507
508
509```
510import("//build/ohos.gni")
511RIL_ADAPTER = "//base/telephony"
512ohos_shared_library("ril_vendor") { // Modem厂商库名称
513    sources = [ // 编译源文件
514        "at_call.c",
515        "at_data.c",
516        "xxx.c",
517    ]
518    include_dirs = [ // 包含的头文件目录
519        "$RIL_ADAPTER/ril_adapter/vendor/include",
520        "$RIL_ADAPTER/ril_adapter/interfaces/innerkits",
521        "include",
522    ]
523    deps = [ // 内部依赖
524        "//drivers/adapter/uhdf2/osal:libhdf_utils",
525        "//base/telephony/core_service/utils:libtelephony_common",
526    ]
527    external_deps = [ "hilog:libhilog" ] // 外部依赖
528
529    part_name = "ril_adapter"  // 部件名称
530    subsystem_name = "telephony" // 子系统名称
531}
532```
533
534
535### 调测验证
536
5371. 编译代码。
538
5392. 查看/out/{device_name}/telephony/ril_adapter目录是否存在libril_vendor.z.so,存在证明集成成功。否则检查代码,重新编译验证。
540