1# Telephony Development 2 3 4## Initializing a Modem Vendor Library 5 6 7### When to Use 8 9Initializing a modem vendor library means to implement **const HRilOps \*RilInitOps(const struct HRilReport \*reportOps)** function in the vendor library. This function is mainly used to: 10 11- Receive function pointers to event callbacks of RIL Adapter. When a service event needs to be reported, the target pointer will be called to report the event to RIL Adapter. 12 13- Create a thread for reading modem nodes. In this thread, the data reported by the modem is read cyclically and parsed as a specific service event for reporting. 14 15- Return the function pointer of the service request API to RIL Adapter. 16 17 18### Available APIs 19 20The following table describes the API for initializing a modem vendor library. 21 22 **Table 1** API for initializing a modem vendor library 23 24| Name| Description| 25| -------- | -------- | 26| const HRilOps \*RilInitOps(const struct HRilReport \* reportOps) | Function: Provides an entry for running a modem vendor library.<br>Input arguments:<br>**reportOps**: event callback function pointer passed by RIL Adapter.<br>Return value: function pointer of the service request API.| 27 28 29### How to Develop 30 31 321. Set the event callback function pointers passed by RIL Adapter through **RilInitOps**. 33 34 ``` 35 // Define the callback function pointers of the modem vendor library. 36 static struct HRilReport g_reportOps = { 37 OnCallReport, // Callback function for call services 38 OnDataReport, // Callback function for cellular data services 39 OnModemReport, // Callback function for modem services 40 OnNetworkReport, // Callback function for network search services 41 OnSimReport, // Callback function for SIM card services 42 OnSmsReport // Callback function for SMS services 43 }; 44 ``` 45 46 471. Create the **g_reader** main thread to enable message looping. 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); // Create the g_reader thread. 54 ``` 55 56 571. In the **g_eventListeners** thread, use **open()** to open a modem node and then create the **g_reader** thread to read and process messages reported by the modem. 58 59 ``` 60 g_fd = open(g_devicePath, O_RDWR); // Open the device node specified by g_devicePath. 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. Return the function pointer of the service request API. 68 69 ``` 70 // Structure for the service request API of the call module 71 typedef struct { 72 // Obtain the call list. 73 void (*GetCallList)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 74 // Make a call 75 void (*Dial)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 76 // End a call. 77 void (*Hangup)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 78 // Reject a call 79 void (*Reject)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 80 // Answer a call. 81 void (*Answer)(ReqDataInfo *requestInfo, const void *data, size_t dataLen); 82 } HRilCallReq; 83 84 // Callback function pointer of the call module 85 static const HRilCallReq g_callReqOps = { 86 .GetCallList = ReqGetCallList, // Obtain the call list. 87 .Dial = ReqDial, // Make a call. 88 .Hangup = ReqHangup, // Disconnect a call. 89 .Reject = ReqReject, // Reject a call. 90 .Answer = ReqAnswer, // Answer a call. 91 }; 92 93 // Service request structure 94 typedef struct { 95 const HRilCallReq *callOps; // Pointer to the structure of call service requests 96 const HRilSimReq *simOps; // Pointer to the structure of SIM card service requests 97 const HRilSmsReq *smsOps; // Pointer to the structure of SMS and MMS service requests 98 const HRilDataReq *dataOps; // Pointer to the structure of cellular data service requests 99 const HRilNetworkReq *networkOps; // Pointer to the structure of network search service requests 100 const HRilModemReq *modemOps; // Pointer to the structure of modem service requests 101 } HRilOps; 102 103 // Service request APIs 104 HRilOps g_hrilOps = { 105 .callOps = &g_callReqOps, // API for call service requests 106 .simOps = &g_simReqOps, // API for SIM card service requests 107 .smsOps = &g_smsReqOps, // API for SMS and MMS service requests 108 .networkOps = &g_networkReqOps, // API for cellular data service requests 109 .dataOps = &g_dataReqOps, // API for network search service requests 110 .modemOps = &g_modemReqOps, // API for modem service requests 111 }; 112 ``` 113 114 115### Debugging and Verification 116 1171. Use the [hdc\_std](../subsystems/subsys-toolchain-hdc-guide.md#how-to-obtain) tool to connect to a debugging device. Then, run the following command to send the generated **libril\_vendor.z.so** library file to the **/system/lib/** directory of the device. For details about how to integrate a library file, see [Integrating Modem Vendor Libraries](#integrating-modem-vendor-libraries). 118 119 ``` 120 hdc_std file send libril_vendor.z.so /system/lib/ 121 ``` 122 1232. Reboot the debugging device. 124 125 ``` 126 hdc_std shell sync 127 hdc_std shell reboot 128 ``` 129 1303. Run the **hdc_std shell hilog** command to view the debug log, and check whether the **RilInitOps()** function is successfully executed. The following debug log is for reference: 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## Responding to Modem Service Requests 139 140 141### When to Use 142 143After receiving a specific telephony service request, RIL Adapter calls the target function pointer obtained in modem vendor library initialization to send a specific service request to the vendor library. Then, the vendor library processes the request based on the request ID. 144 145 146### Available APIs 147 148The following table describes the APIs for responding to modem service requests, with the dial module as an example. 149 150 **Table 2** APIs for responding to modem service requests 151 152| Name| Description| 153| -------- | -------- | 154| void ReqDial(ReqDataInfo \*requestInfo, const void \*data, size_t dataLen); | Function: Processes number dial requests.<br>Input arguments:<br>**requestInfo**: request type.<br>**data**: called number.<br>**dataLen**: data length.<br>Return value: none| 155| void (\*OnCallReport)(struct ReportInfo reportInfo, const void \*data, size_t dataLen); | Function: Reports the execution result of a service request to RIL Adapter.<br>Input arguments:<br>**reportInfo**: request type.<br>**data**: returned data.<br>**dataLen**: data length.<br>Return value: none| 156 157 158### How to Develop 159 1601. Implement processing of dial requests in the **ReqDial()** API. 161 162 ``` 163 // Implement the API for processing dial requests. 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); // Send the AT command. 195 ...... 196 } 197 ``` 198 1992. After the modem executes the dial command, report the execution result to RIL Adapter via **OnCallReport()**. 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); // Invoke the callback function of the call service. 209 ``` 210 211 212### Debugging and Verification 213 2141. Use the [hdc\_std](../subsystems/subsys-toolchain-hdc-guide.md#how-to-obtain) tool to connect to a debugging device. Then, run the following command to send the generated **libril\_vendor.z.so** library file to the **/system/lib/** directory of the device. 215 216 ``` 217 hdc_std file send libril_vendor.z.so /system/lib/ 218 ``` 219 2202. Reboot the debugging device. 221 222 ``` 223 hdc_std shell sync 224 hdc_std shell reboot 225 ``` 226 2273. Run the **hdc_std shell** command. Then, run the **./system/bin/ril_adapter_test** command, type **1**, and enter the phone number as prompted to test the call function. 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. Open another terminal window, and run the **hdc_std shell hilog** command. Then, view the log to check whether **ReqDial()** is successfully executed. The following debug log is for reference: 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## Reporting Modem Events 256 257 258### When to Use 259 260A modem node thread reads the messages reported by the modem cyclically, parses the messages into specific events, and then reports the events to RIL Adapter. 261 262 263### Available APIs 264 265The following table describes the API for reporting modem events. 266 267 **Table 3** API for reporting modem events 268 269| Name| Description| 270| -------- | -------- | 271| void OnNotifyOps(const char \*s, const char \*smsPdu) | Function: Distributes the events reported by the modem.<br>Input arguments:<br>**s**: AT command prefix<br>**smsPdu**: PDU of the SMS message.<br>Return value: none| 272 273 274### How to Develop 275 2761. Call **OnNotifyOps()** in the g_reader thread of the modem device node to parse reported modem events. On determining the command type, call **OnXxxReport()** to report the parsed module events to the hril layer. 277 278 ``` 279 // Parse the data reported by the modem as events proactively reported by the corresponding module. 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 // Determine the type of the proactively reported events based on the AT command. 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 // Report the events of each module to the hril layer. 301 ...... 302 } 303 ``` 304 3051. Distribute the reported events from the **hril** layer to the Telephony Service layer. 306 307 ``` 308 // Report the call status proactively. 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 // Distribute events. 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### Debugging and Verification 332 3331. Use the [hdc\_std](../subsystems/subsys-toolchain-hdc-guide.md#how-to-obtain) tool to connect to a debugging device. Then, run the following command to send the generated **libril\_vendor.z.so** library file to the **/system/lib/** directory of the device. 334 335 ``` 336 hdc_std file send libril_vendor.z.so /system/lib/ 337 ``` 338 3392. Reboot the debugging device. 340 341 ``` 342 hdc_std shell sync 343 hdc_std shell reboot 344 ``` 345 3463. Run the **hdc_std shell** command. Then, run the **./system/bin/ril_adapter_test** command, type **1**, and enter the phone number as prompted to test the call function. 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. Open another terminal window, and run the **hdc_std shell hilog** command. Then, view the log to check whether **OnNotifyOps()** is successfully executed. The following debug log is for reference: 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### Development Example 386 387- **Outgoing Call** 388 The following figure shows the API calling for an outgoing call. 389 **Figure 1** Time sequence of API calling for an outgoing call 390 391  392 393 When an application initiates an outgoing call, RIL Adapter receives a call request, and the **hril** layer invokes the **ReqDial()** function. In **ReqDial()**, the data passed by the Telephony Service is encapsulated as an AT command and sent to the modem. After executing the dial command, the modem reports the execution result to RIL Adapter through **OnCallReport()**. 394 395 ``` 396 // Callback function pointer of the call module 397 static const HRilCallReq g_callReqOps = { 398 .GetCallList = ReqGetCallList, // Obtain the call list. 399 .Dial = ReqDial, // Make a call. 400 .Hangup = ReqHangup, // Disconnect a call. 401 .Reject = ReqReject, // Reject a call. 402 .Answer = ReqAnswer, // Answer a call. 403 }; 404 405 // Service request APIs 406 HRilOps g_hrilOps = { 407 .callOps = &g_callReqOps, // API for call service requests 408 .simOps = &g_simReqOps, // API for SIM card service requests 409 .smsOps = &g_smsReqOps, // API for SMS and MMS service requests 410 .networkOps = &g_networkReqOps, // API for cellular data service requests 411 .dataOps = &g_dataReqOps, // API for network search service requests 412 .modemOps = &g_modemReqOps, // API for modem service requests 413 }; 414 415 // Implement the API for processing dial requests. 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); // Send the AT command. 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); // Invoke the callback function of the call service. 458 FreeResponseInfo(pResponse); 459 } 460 ``` 461 462 463- **Incoming Call** 464 The following figure shows the API calling of an incoming call. 465 **Figure 2** Time sequence of API calling for an incoming call 466 467  468 469 The **g_reader** thread cyclically reads the messages reported by the modem. When the modem receives an incoming call event, it actively reports the information about the incoming call. 470 471 The **g_reader** thread calls **OnNotifyOps()** to parse the reported information. If the parsed data reported by the modem starts with characters such as **+CRING** or **RING**, it indicates that an incoming call event exists. In this case, the event is reported to RIL Adapter through **OnCallReport(reportInfo, NULL, 0)**. 472 473 ``` 474 // Parse the data reported by the modem as events proactively reported by the corresponding module. 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 // Determine the type of the proactively reported events based on the AT command. 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); // Invoke the callback function of the call service. 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## Integrating Modem Vendor Libraries 502 503 504### Configuring Compilation Information 505 506Compile the modem vendor library into a dynamic library by using **BUILD.gn**. Upon startup, RIL Adapter loads the dynamic library to the system in dlopen mode and then initializes the library. For details about how to implement vendor library initialization, see [Initializing a Modem Vendor Library](#initializing-a-modem-vendor-library). The following is an example of **BUILD.gn**: 507 508 509``` 510import("//build/ohos.gni") 511RIL_ADAPTER = "//base/telephony" 512ohos_shared_library("ril_vendor") { // Modem vendor library 513 sources = [// Source files to be built 514 "at_call.c", 515 "at_data.c", 516 "xxx.c", 517 ] 518 include_dirs = [// Header files 519 "$RIL_ADAPTER/ril_adapter/vendor/include", 520 "$RIL_ADAPTER/ril_adapter/interfaces/innerkits", 521 "include", 522 ] 523 deps = [// Internal dependencies 524 "//drivers/adapter/uhdf2/osal:libhdf_utils", 525 "//base/telephony/core_service/utils:libtelephony_common", 526 ] 527 external_deps = [ "hilog:libhilog" ] // External dependenc 528 529 part_name = "ril_adapter" // Part name 530 subsystem_name = "telephony" // Subsystem name 531} 532``` 533 534 535### Debugging and Verification 536 5371. Build the code. 538 5392. Check whether the **libril_vendor.z.so** file exists in the **/out/{device_name}/telephony/ril_adapter** directory. If the file exists, the integration is successful. Otherwise, correct the code error, and perform compilation and verification again. 540