current position:Home>Telephone subsystem of openharmony source code analysis -- call flow

Telephone subsystem of openharmony source code analysis -- call flow

2022-05-15 07:45:55openharmony

( The following content is shared by developers , Do not represent OpenHarmony Views of project group working committee )

 

Wang Dapeng
Shenzhen KaiHong Digital Industry Development Co., Ltd

 

One 、 brief introduction


OpenAtom OpenHarmony( hereinafter referred to as “OpenHarmony”) The telephone subsystem is OS It provides basic wireless communication capability .


Support TD-LTE/FDD-LTE/TD-SCDMA/WCDMA/EVDO/CDMA1X/GSM And other network communication modules , It can provide high-speed wireless data transmission 、 Internet access and other services , With voice 、 SMS 、 MMS 、SIM Card and other functions .


Unless otherwise specified in the following lines , All statements refer to OpenHarmony System (OpenHarmony 3.0 LTS edition ).

Two 、OpenHarmony Architecture diagram

 

3、 ... and 、 Basic knowledge of


1. The telephone subsystem


The telephone subsystem is used as OpenHarmony A very important part , Provide basic communication functions for the system , Include CS Domain services , Like voice call 、 SMS 、 Call management ; Also include PS Domain related services , such as MMS、 Data services, etc , in addition SIM and RIL Our business is also in this subsystem .


2. Telephone subsystem architecture diagram


OpenHarmony Related frame diagram of cellular call of existing telephone subsystem :

 

 

application layer : All kinds of calls 、SMS、 Data business 、SIM Application of card function , for example call application 、SMS application 、launcher Application and so on .

 

Frame layer :

①SDK : Provide standard interfaces for applications , Include JS Interface and C++ Interface .

②Framework: Provide stable basic capabilities of corresponding modules to the application layer , Include network、call、sms、sim Related functions , Including call management , Short color editing, sending and receiving ,sim The identification of the card is stationed in the network , Data service management, etc . At present OpenHarmony In the version ,call_manager、cellular_call、cellular_data、data_storage、sms_mms、state_registry、core_service And other modules belong to the framework layer .

 

Hril layer : Equivalent to Android RILJ, Because different schemes use Modem Dissimilarity , So various instruction formats , The initialization sequence is different , To eliminate these differences , and Hril It provides an abstraction layer between wireless hardware devices and telephone services .

 

Vendor lib layer : Like Android RILD, Responsible for working with modem Module interaction , Send the corresponding information of each module AT command .

 

Modem layer : Today's baseband processor , It mainly processes digital signals 、 Speech signal encoding and decoding and communication protocol , And baseband processor 、 RF and other peripheral chips as a Modem   modular , Provide AT Command interface to the upper layer for interaction . Communication module Modem Communicate with the communication network 、 Transmit voice and data 、 Complete the call 、 SMS and other related telephone functions .

 

3. Telephone subsystem code structure


Because the telephone subsystem contains many modules , So describe each module separately :

 

Call management module : Main management CS(Circuit Switch, Circuit switching )、IMS(IP Multimedia Subsystem,IP Multimedia subsystem ) and OTT(over the top,OTT Solution ) Three types of calls , Be responsible for applying for audio and video resources required for calls , And deal with various conflicts arising from multi-channel calls .

 

1.  /base/telephony/call_manager  
2.  ├─ frameworks                              # napi Interface storage directory   
3.  ├─ interfaces                              #  Interfaces exposed to the outside   
4.  │  ├─ innerkits                            #  Internal interfaces between components   
5.  │  └─ kits                                 # js Interface storage directory   
6.  ├─ sa_profile                              #  Startup profile   
7.  ├─ services                                #  Service internal code   
8.  │  ├─ audio                                #  Audio management related code   
9.  │  ├─ bluetooth                            #  Bluetooth call related code   
10.  │  ├─ call                                 #  Call service related code   
11.  │  ├─ call_manager_service                 #  Process service management related code   
12.  │  ├─ call_setting                         #  Call settings related codes   
13.  │  ├─ telephony_interaction                #  Telephone core service interaction related code   
14.  │  └─ call_ui_interaction                  # UI Interaction related code   
15.  ├─ test                                    #  Unit test related code   
16.  └─ utils                                   #  General tools   
17.  ``` 

 

Cellular call module : Support the implementation of basic call based on operator network , Include based on 2G/3G Of CS(Circuit Switch, Circuit switching ) Call and based on 4G/5G Of IMS(IP Multimedia Subsystem,IP Multimedia subsystem ) conversation , contain VoLTE/ VoWIFI/ VoNR voice 、 video 、 meeting , Support CS and IMS Domain selection control and switching between calls , Support emergency calls . Support mainstream modem Chip platform .

 

1.  /base/telephony/cellular_call     #  Cellular call subassembly   
2.  ├─ BUILD.gn                       #  compile gn Script   
3.  ├─ README.md                      # Readme file   
4.  ├─ services  
5.  │  ├─ common                      #  Tool warehouse   
6.  │  ├─ connection                  #  adjoining course   
7.  │  ├─ control                     #  Control the business layer   
8.  │  └─ manager                     #  management layer   
9.  ├─ sa_profile                     # sa file   
10.  ├─ ohos.build                     #  compile build  
11.  └─ test                           #  Test related   
12.  ```  


Cellular data module : As a tailorable part of the telephone subsystem , Depend on core_service Core services 、ril_adapter. With cellular data activation 、 Cellular data anomaly detection and recovery 、 Cellular data state management 、 Cellular data switch management 、 Cellular data roaming management 、APN management 、 Network management interaction and other functions .

 

1.  base/telephony/cellular_data  
2.  ├── figures  
3.  ├── frameworks  
4.  │   ├── js                              # js file   
5.  │   │   └── napi  
6.  │   │       ├── include  
7.  │   │       └── src  
8.  │   └── native  
9.  │       └── src  
10.  ├── interfaces  
11.  │   ├── innerkits                       #  External interface   
12.  │   └── kits  
13.  │       └── js                          #  Externally provided js Interface   
14.  │           └── declaration  
15.  ├── sa_profile                          # SA To configure   
16.  ├── services  
17.  │   ├── include                         #  The header file   
18.  │       ├── apn_manager  
19.  │   │   ├── common  
20.  │   │   ├── state_machine  
21.  │   │   └── utils  
22.  │   └── src                             #  Source file   
23.  │       ├── apn_manager  
24.  │       ├── state_machine  
25.  │       └── utils  
26.  └── test  
27.      └── unit_test                       #  Unit test related code   
28.  ```  

 

Telephone core service module : The main function is initialization RIL management 、SIM Card and network search module , And get RIL Adapter service . By registering the callback service , Realization and RIL Adapter communicate ; Subscribe by publishing , To realize the communication with each functional module .

 

1.  /base/telphony/core_service  
2.  ├── interfaces             #  Interface directory   
3.  │   ├── innerkits          #  Internal interfaces between components   
4.  │   └── kits               #  Interface provided for application ( for example JS Interface )  
5.  ├── services               #  Core service implementation code directory   
6.  │   ├── include  
7.  │   └── src  
8.  ├── etc                    #  Driver script directory of core services   
9.  │   └── init  
10.  ├── sa_profile             #  Directory of startup files for core services   
11.  ├── tel_ril                #  Core services and RIL Adapter Communication code directory   
12.  │   ├── include          
13.  │   ├── src  
14.  │   └── test  
15.  ├── network_search         #  Search service code directory   
16.  │   ├── include  
17.  │   ├── src  
18.  │   └── test  
19.  ├── sim                    # SIM Card service code directory   
20.  │   ├── include  
21.  │   ├── src  
22.  │   └── test  
23.  ├── frameworks             # frameworks Catalog   
24.  │   ├── js  
25.  │   ├── nstive  
26.  ├── common                 #  Header file directory of each business module   
27.  │   ├── api  
28.  │   ├── call_manager  
29.  │   ├── network_search  
30.  │   └── sim  
31.  ├── utils  
32.  │   ├── log                #  Core service log print Directory   
33.  │   ├── preferences  
34.  │   ├── common  
35.  ```

 

Database and persistence module : In charge of the telephone service subsystem SIM card / Short MMS and other modules for persistent data storage , Provide DataAbility Access interface .

 

1.  /base/telephony/data_storage     #  Database and persistence   
2.  ├─ BUILD.gn                         #  compile gn Script   
3.  ├─ README.md                        # Readme file   
4.  ├─ common                           #  public 、 General documents   
5.  │  ├─ include                         
6.  │  └─ src                             
7.  ├─ pdp_profile                      #  Network operators   
8.  │  ├─ include                         
9.  │  └─ src                             
10.  ├─ sim                              # sim card   
11.  │  ├─ include                         
12.  │  └─ src                             
13.  ├─ sms_mms                          #  SMS message   
14.  │  ├─ include                        
15.  │  └─ src                             
16.  ├─ ohos.build                       #  compile build  
17.  └─ test                             #  Test related   
18.  ```  

 

RIL Adapter modular : Mainly including vendor library loading , Business interface implementation and event scheduling management . Mainly used to shield different modem Vendor hardware differences , Provide a unified interface for the upper layer , By registering HDF The service communicates with the upper interface .

 

1.  base/telephony/ril_adapter  
2.  ├─ hril                            # hri The interface implementation of each business module of layer   
3.  ├─ hril_hdf                        # HDF service   
4.  ├─ include                         #  Header file storage directory   
5.  ├─ interfaces                      #  Provide corresponding internal interfaces of each business of the upper layer   
6.  │  └─ innerkits  
7.  ├─ test                            #  Unit test related code   
8.  │  ├─ mock  
9.  │  └─ unittest                     #  Unit test code   
10.  └─ vendor                          #  Vendor library code   
11.  │  └─ include  
12.  ``` 

 

Short MMS module : Provide SMS sending and receiving and MMS encoding and decoding functions for mobile data users , The main functions are GSM/CDMA Text messaging 、 SMS PDU(Protocol data unit, Protocol data unit ) codec 、Wap Push Reception processing 、 Cell broadcast reception 、 MMS notification 、 MMS codec and SIM Add, delete, modify and check card SMS records, etc .

 

1.  /base/telephony/sms_mms  
2.  ├─ interfaces               #  Exposed interface   
3.  │  └─ kits  
4.  ├─ sa_profile               #  Startup profile   
5.  ├─ services                 #  Service internal code   
6.  │  ├─ include               #  Header Directory   
7.  │  ├─ cdma                  # CDMA Standard source file   
8.  │  └─ gsm                   # GSM Standard source file   
9.  ├─ test                     #  Unit test directory   
10.  └─ utils                    #  General tools related   
11.  ``` 

 

Status registration module : It is mainly responsible for the subscription and unsubscribe of various message events in the telephone service subsystem API. Event types include network state changes 、 Signal strength changes 、 Cell information changes 、 Cellular data connection status changes 、 Call status changes, etc .

 

1.  /base/telephony/state_registry      #  Status registration forwarding service   
2.  ├─ BUILD.gn                         #  compile gn Script   
3.  ├─ README.md                        # Readme file   
4.  ├─ interfaces                       # API,js file   
5.  ├─ service  
6.  │  ├─ include                       #  The header file   
7.  │  └─ src                           #  Source file   
8.  ├─ sa_profile                       # sa file   
9.  ├─ ohos.build                       #  compile build  
10.  └─ test                             #  Test related   
11.  ```  

 

4. Relevant warehouse

 

Core services :https://gitee.com/openharmony/telephony_core_service

Cellular call :https://gitee.com/openharmony/telephony_cellular_call

call management :https://gitee.com/openharmony/telephony_call_manager

Registration service :https://gitee.com/openharmony/telephony_state_registry

SMS message :https://gitee.com/openharmony/telephony_sms_mms

riladapter:https://gitee.com/openharmony/telephony_ril_adapter

Data business :https://gitee.com/openharmony/telephony_cellular_data

data storage :https://gitee.com/openharmony/telephony_data_storage

Network management :https://gitee.com/openharmony/communication_netmanager_standard


5. The telephone subsystem (call) Core class


 

Four 、 The source code parsing


As the core business of telephone subsystem , Call function (Call) In addition to requiring hardware support , Such as audio module 、 Baseband module, etc , Many services of the system itself need to cooperate with each other to realize this function , such as : call management (call_manager)、 Cellular call service (cellular_call)、Telephony Core services (core_service)、RIL adapter (ril_adapter), Status registration service (state_registry) etc. .

 

At present, calls are mainly divided into three types :CS Call(Circuit Switch, Circuit switching )、IMS Call(IP Multimedia Subsystem,IP Multimedia subsystem ) and OTT Call(over the top,OTT Solution ) Three types of calls . On the upper Call The interfaces exposed by the application include :dial、answer、reject、hangup、holdCall、unHoldCall、switchCal、startDTMF、stopDTMF etc. . Because there are so many incidents , Moreover, the event handling processes are similar , So here we take Call Of Answer Event handling process .

 

1. Call upper layer call code analysis


When there is an incoming call ,Callui The interface will display the incoming call , The user clicks answer Key , Will be activated Call Of Answer technological process .
 

1.  <div class="bottom-btn-wrap">  
2.         <div class="btn-item">  
3.             <div class="btn-box" @click="onReject">  
4.                 <image src="assets/picture/hangUP.png"></image>  
5.             </div>  
6.         </div>  
7.         <div class="btn-item">  
8.             <div class="btn-box" @click="onAnswer">  
9.                 <image src="assets/picture/answer.png"></image>  
10.             </div>  
11.         </div>  
12.     </div>  


  Call here incomingCom.js Of onAnswer function .
 

1.  /** 
2.   * Answer the phone interface 
3.   */  
4.  onAnswer() {  
5.      console.log('onAnswer function start');  
6.      console.log('this.callData: ' + JSON.stringify(this.callData));  
7.      acceptCall(this.callData.callId);  
8.  },  


  Because before has import 了 callServiceProxy.js file .
 

1.  import {acceptCall, rejectCall, hangUpCall} from'../../../model/callServiceProxy.js';


So let's take a look at callServiceProxy Of acceptCall function .

 

1.  /** 
2.   * accept call 
3.   * @param { number } callId - call id 
4.   */  
5.  export const acceptCall = function (callId) {  
6.      call.answer(callId).then((res) => {  
7.          console.log(prefixLog + 'then:acceptCall' + JSON.stringify(res));  
8.      }).catch((err) => {  
9.          console.log(prefixLog + 'catch:acceptCall' + JSON.stringify(err));  
10.      });  
11.  }; 


From the code, we can see that this function actually calls call Of answer function , So where did this come from .call It is the framework layer of telephone subsystem napi The interface of external encapsulation is realized ,call_manager Medium @ohos.telephony.call.d.ts There are corresponding interface descriptions in , From here, the code has been completed from app To framework Call to .
 

1.  import call from '@ohos.telephony.call'; 


2. Call framework layer code analysis


3.2.1 Call frame layer code call sequence diagram

 

3.2.2 Call framework layer code analysis

 

As can be seen from the sequence diagram above , Whole Answer The calling process of is relatively long , The whole frame layer processing span includes call_manager、cellular_call、core_service、IPC、ril_adapter And so on . Because the processing flow is too long , Refer to the sequence diagram for specific calling conditions , Here, we will describe some key parts of the processing of the framework layer according to calling different services .

 

3.2.2.1Answer The incident happened in call_manager Processing in

 

Previously called by the application layer call.answer It's through @ohos.telephony.call Introduced , The actual definition is call_manage In service interfaces Internal napi Interface .

 

1.  static napi_module g_nativeCallManagerModule = {  
2.      .nm_version = NATIVE_VERSION,  
3.      .nm_flags = NATIVE_FLAGS,  
4.      .nm_filename = nullptr,  
5.      .nm_register_func = NapiCallManager::RegisterCallManagerFunc,  
6.      .nm_modname = "telephony.call",  
7.      .nm_priv = ((void *)0),  
8.      .reserved = {0},  
9.  }; 


The interface and some enumeration parameters are required for registration napi_valueNapiCallManager::RegisterCallManagerFunc(napi_env env, napi_value exports)

 

1.  napi_value NapiCallManager::RegisterCallManagerFunc(napi_env env, napi_value exports)  
2.  {  
3.      DeclareCallBasisInterface(env, exports);  
4.      DeclareCallConferenceInterface(env, exports);  
5.      DeclareCallSupplementInterface(env, exports);  
6.      DeclareCallExtendInterface(env, exports);  
7.      DeclareCallMultimediaInterface(env, exports);  
8.      DeclareCallMediaEnum(env, exports);  
9.      DeclareCallDialEnum(env, exports);  
10.      DeclareCallStateEnum(env, exports);  
11.      DeclareCallEventEnum(env, exports);  
12.      DeclareCallRestrictionEnum(env, exports);  
13.      DeclareCallWaitingEnum(env, exports);  
14.      DeclareCallTransferEnum(env, exports);  
15.      std::u16string bundleName = GetBundleName(env);  
16.      Init(bundleName);  
17.      return exports;  
18.  }  

 

What we need here is CallBasis Interface , The details are as follows , These are the handler functions corresponding to some events called by the application layer before .

 

1.  napi_value NapiCallManager::DeclareCallBasisInterface(napi_env env, napi_value exports)  
2.  {  
3.      napi_property_descriptor desc[] = {  
4.          DECLARE_NAPI_FUNCTION("dial", DialCall),  
5.          DECLARE_NAPI_FUNCTION("answer", AnswerCall),  
6.          DECLARE_NAPI_FUNCTION("reject", RejectCall),  
7.          DECLARE_NAPI_FUNCTION("hangup", HangUpCall),  
8.          DECLARE_NAPI_FUNCTION("holdCall", HoldCall),  
9.          DECLARE_NAPI_FUNCTION("unHoldCall", UnHoldCall),  
10.          DECLARE_NAPI_FUNCTION("switchCall", SwitchCall),  
11.          DECLARE_NAPI_FUNCTION("upgradeCall", UpgradeCall),  
12.          DECLARE_NAPI_FUNCTION("downgradeCall", DowngradeCall),  
13.          DECLARE_NAPI_FUNCTION("setCallPreferenceMode", SetCallPreferenceMode),  
14.      };  
15.      NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) /   sizeof(desc[0]), desc));  
16.      return exports;  
17.  } 


Because we correspond to answer event , So the corresponding function here is AnswerCall.
 

1.  napi_value NapiCallManager::AnswerCall(napi_env env, napi_callback_info info)  
2.  {  
3.      GET_PARAMS(env, info, VALUE_MAXIMUM_LIMIT);  
4.      NAPI_ASSERT(env, argc <= VALUE_MAXIMUM_LIMIT, "parameter error!");  
5.      bool matchFlag = MatchValueType(env, argv[ARRAY_INDEX_FIRST], napi_number);  
6.      NAPI_ASSERT(env, matchFlag, "Type error, should be number type");  
7.      auto asyncContext = (std::make_unique<AnswerAsyncContext>()).release();  
8.      napi_get_value_int32(env, argv[ARRAY_INDEX_FIRST], &asyncContext->callId);  
9.      if (argc == TWO_VALUE_LIMIT) {  
10.          if (MatchValueType(env, argv[ARRAY_INDEX_SECOND], napi_function)) {  
11.              napi_create_reference(env, argv[ARRAY_INDEX_SECOND], DATA_LENGTH_ONE, &                       (asyncContext->callbackRef));  
12.          } else if (MatchValueType(env, argv[ARRAY_INDEX_SECOND], napi_number)) {  
13.              asyncContext->videoState = GetIntProperty(env, argv[ARRAY_INDEX_SECOND],                     "videoState");  
14.          }  
15.      } else if (argc == VALUE_MAXIMUM_LIMIT) {  
16.          asyncContext->videoState = GetIntProperty(env, argv[ARRAY_INDEX_SECOND],                     "videoState");  
17.          napi_create_reference(env, argv[ARRAY_INDEX_THIRD], DATA_LENGTH_ONE, &                       (asyncContext->callbackRef));  
18.      }  
19.      return HandleAsyncWork(env, asyncContext, "AnswerCall", NativeAnswerCall,                     NativeVoidCallBack);  
20.  }  


Continue to call , From the previous function AnswerCall It should be processed asynchronously .
 

1.  void NapiCallManager::NativeAnswerCall(napi_env env, void *data)  
2.  {  
3.      if (data == nullptr) {  
4.          TELEPHONY_LOGE("data is nullptr");  
5.          return;  
6.      }  
7.      auto asyncContext = (AnswerAsyncContext *)data;  
8.      int32_t ret = DelayedSingleton<CallManagerProxy>::GetInstance()->AnswerCall(  
9.          asyncContext->callId, asyncContext->videoState);  
10.      asyncContext->result = ret;  
11.  }  


In the process of calling all the way , Would call CallPolicy Class AnswerCallPolicy The function is used to determine the corresponding callId Of CallObject Whether there is , If so, judge Call Status .
 

1.  int32_t CallPolicy::AnswerCallPolicy(int32_t callId)  
2.  {  
3.      if (!IsCallExist(callId)) {  
4.          TELEPHONY_LOGE("callId is invalid, callId:%{public}d", callId);  
5.          return CALL_ERR_CALLID_INVALID;  
6.      }  
7.      TelCallState state = GetCallState(callId);  
8.      if (state != CALL_STATUS_INCOMING && state != CALL_STATUS_WAITING) {  
9.          TELEPHONY_LOGE("current call state is:%{public}d, accept call not allowed",                   state);  
10.          return CALL_ERR_ILLEGAL_CALL_OPERATION;  
11.      }  
12.      return TELEPHONY_SUCCESS;  
13.  }  


In the subsequent call to CallRequestHandlerService Of AnswerCall When processing , If there is CallRequestHandler Of handler_ There is , be make individual AnswerCallPara Of unique_ptr, And then callid and videostate Pass in the pointer . call SendEvent take HANDLER_ANSWER_CALL_REQUEST issue .
 

1.  int32_t CallRequestHandlerService::AnswerCall(int32_t callId, int32_t videoState)   
2.  {  
3.      if (handler_.get() == nullptr) {  
4.          TELEPHONY_LOGE("handler_ is nullptr");  
5.          return TELEPHONY_ERR_FAIL;  
6.      }  
7.      std::unique_ptr<AnswerCallPara> para = std::make_unique<AnswerCallPara>();  
8.      if (para.get() == nullptr) {  
9.          TELEPHONY_LOGE("make_unique AnswerCallPara failed!");  
10.          return TELEPHONY_ERR_FAIL;  
11.      }  
12.      para->callId = callId;  
13.      para->videoState = videoState;  
14.      if (!handler_->SendEvent(HANDLER_ANSWER_CALL_REQUEST, std::move(para))) {  
15.          TELEPHONY_LOGE("send accept event failed!");  
16.          return TELEPHONY_ERR_FAIL;  
17.      }  
18.      return TELEPHONY_SUCCESS;  
19.  } 


From the code processing flow , It's coming from here event Will be by... In the same file CallRequestHandler Class capture , Trigger ProcessEvent Handle .
 

1.  void CallRequestHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)  
2.  {  
3.      if (event == nullptr) {  
4.          TELEPHONY_LOGE("CallRequestHandler::ProcessEvent parameter error");  
5.          return;  
6.      }  
7.      TELEPHONY_LOGD("CallRequestHandler inner event id obtained: %{public}u.", event-             >GetInnerEventId());  
8.      auto itFunc = memberFuncMap_.find(event->GetInnerEventId());  
9.      if (itFunc != memberFuncMap_.end()) {  
10.          auto memberFunc = itFunc->second;  
11.          if (memberFunc != nullptr) {  
12.              return (this->*memberFunc)(event);  
13.          }  
14.      }  
15.  } 


memberFuncMap Will be based on event Of id from memberFuncMap_ Get the corresponding memberFunc, Then enter the corresponding processing function .
 

1.  CallRequestHandler::CallRequestHandler(const std::shared_ptr<AppExecFwk::EventRunner> &runner)  
2.      : AppExecFwk::EventHandler(runner), callRequestProcessPtr_(nullptr)  
3.  {  
4.      memberFuncMap_[CallRequestHandlerService::HANDLER_DIAL_CALL_REQUEST] = &CallRequestHandler::DialCallEvent;  
5.      memberFuncMap_[CallRequestHandlerService::HANDLER_ANSWER_CALL_REQUEST] = &CallRequestHandler::AcceptCallEvent;  
6.      memberFuncMap_[CallRequestHandlerService::HANDLER_REJECT_CALL_REQUEST] = &CallRequestHandler::RejectCallEvent;  
7.      memberFuncMap_[CallRequestHandlerService::HANDLER_HANGUP_CALL_REQUEST] = &CallRequestHandler::HangUpCallEvent;  
8.      memberFuncMap_[CallRequestHandlerService::HANDLER_HOLD_CALL_REQUEST] = &CallRequestHandler::HoldCallEvent;  
9.      memberFuncMap_[CallRequestHandlerService::HANDLER_UNHOLD_CALL_REQUEST] = &CallRequestHandler::UnHoldCallEvent;  
10.      memberFuncMap_[CallRequestHandlerService::HANDLER_SWAP_CALL_REQUEST] = &CallRequestHandler::SwitchCallEvent;  
11.      memberFuncMap_[CallRequestHandlerService::HANDLER_COMBINE_CONFERENCE_REQUEST] =  
12.          &CallRequestHandler::CombineConferenceEvent;  
13.      memberFuncMap_[CallRequestHandlerService::HANDLER_SEPARATE_CONFERENCE_REQUEST] =  
14.          &CallRequestHandler::SeparateConferenceEvent;  
15.      memberFuncMap_[CallRequestHandlerService::HANDLER_UPGRADE_CALL_REQUEST] = &CallRequestHandler::UpgradeCallEvent;  
16.      memberFuncMap_[CallRequestHandlerService::HANDLER_DOWNGRADE_CALL_REQUEST] =  
17.          &CallRequestHandler::DowngradeCallEvent;  
18.  }  


The corresponding processing function here is AcceptCallEvent(), This part of the function has no return value , Again from event Remove from callId and videoState.
 

1.  void CallRequestHandler::AcceptCallEvent(const AppExecFwk::InnerEvent::Pointer &event)  
2.  {  
3.      if (event == nullptr) {  
4.          TELEPHONY_LOGE("CallRequestHandler::ProcessEvent parameter error");  
5.          return;  
6.      }  
7.      auto object = event->GetUniqueObject<AnswerCallPara>();  
8.      if (object == nullptr) {  
9.          TELEPHONY_LOGE("object is nullptr!");  
10.          return;  
11.      }  
12.      AnswerCallPara acceptPara = *object;  
13.      if (callRequestProcessPtr_ == nullptr) {  
14.          TELEPHONY_LOGE("callRequestProcessPtr_ is nullptr");  
15.          return;  
16.      }  
17.      callRequestProcessPtr_->AnswerRequest(acceptPara.callId, acceptPara.videoState);  
18.  } 


Continue to call CallRequestProcessl Class AnswerReques Function time , Will pass GetOneCallObject Get different CallObject.
 

1.  void CallRequestProcess::AnswerRequest(int32_t callId, int32_t videoState)  
2.  {  
3.      sptr<CallBase> call = GetOneCallObject(callId);  
4.      if (call == nullptr) {  
5.          TELEPHONY_LOGE("the call object is nullptr, callId:%{public}d", callId);  
6.          return;  
7.      }  
8.      int32_t ret = call->AnswerCall(videoState);  
9.      if (ret != TELEPHONY_SUCCESS) {  
10.          TELEPHONY_LOGE("AnswerCall failed!");  
11.          return;  
12.      }  
13.      DelayedSingleton<CallControlManager>::GetInstance()->NotifyIncomingCallAnswered(call);  
14.  } 


Got the corresponding call after , You can call the corresponding call Of AnswerCall function , This function will override BaseCall The virtual function . because CSCall、IMSCall、OTTCall There are corresponding AnswerCall function , So the actual use of that is by BaseCall Class AnswerCall Overridden by that subclass , To call different AnswerCall function . Let's assume here that CsCall .
 

1.  int32_t CSCall::AnswerCall(int32_t videoState)  
2.  {  
3.      return CarrierAcceptCall(videoState);  
4.  }  


Call to CarrierCall Of CarrierAcceptCall Follow up . among AcceptCallBase() The function will judge Call state , If it is CALL_RUNNING_STATE_RINGING state , It will call AudioControlManager Of SetVolumeAudible To set up audio Related content of .
 

1.  int32_t CarrierCall::CarrierAcceptCall(int32_t videoState)  
2.  {  
3.      CellularCallInfo callInfo;  
4.      AcceptCallBase();     
5.      PackCellularCallInfo(callInfo);  
6.      int32_t ret = DelayedSingleton<CellularCallIpcInterfaceProxy>::GetInstance()->Answer(callInfo);  
7.      if (ret != TELEPHONY_SUCCESS) {  
8.          TELEPHONY_LOGE("Accept failed!");  
9.          return CALL_ERR_ACCEPT_FAILED;  
10.      }  
11.      return TELEPHONY_SUCCESS;  
12.  }  


processed AcceptCallBase() after , Need to use PackCellularCallInfo take call The information is packaged callinfo in , Follow up directly to this callInfo Pass out .
 

1.  void CarrierCall::PackCellularCallInfo(CellularCallInfo &callInfo)  
2.  {  
3.      callInfo.callId = callId_;  
4.      callInfo.callType = callType_;  
5.      callInfo.videoState = (int32_t)videoState_;  
6.      callInfo.index = index_;  
7.      callInfo.slotId = slotId_;  
8.      (void)memset_s(callInfo.phoneNum, kMaxNumberLen, 0, kMaxNumberLen);  
9.      if (memcpy_s(callInfo.phoneNum, kMaxNumberLen, accountNumber_.c_str(), accountNumber_.length()) != 0) {  
10.          TELEPHONY_LOGW("memcpy_s failed!");  
11.          return;  
12.      }  
13.  }  


The next step is to call CellularCallIpcInterfaceProxy Class come Answer Function to continue processing . First, judge whether there is ReConnectService The necessary , This operation is to ensure that there are available cellularCallInterfacePtr_.cellularCallInterfacePtr_ It's a IRemoteBroker class , This class is a IPC The base class interface is used for IPC signal communication .
 

1.  int CellularCallIpcInterfaceProxy::Answer(const CellularCallInfo &callInfo)  
2.  {  
3.      if (ReConnectService() != TELEPHONY_SUCCESS) {  
4.          return TELEPHONY_ERR_IPC_CONNECT_STUB_FAIL;  
5.      }  
6.      std::lock_guard<std::mutex> lock(mutex_);  
7.      int errCode = cellularCallInterfacePtr_->Answer(callInfo);    
8.      if (errCode != TELEPHONY_SUCCESS) {  
9.          TELEPHONY_LOGE("answering call failed, errcode:%{public}d", errCode);  
10.          return TELEPHONY_ERR_FAIL;  
11.      }  
12.      return TELEPHONY_SUCCESS;  
13.  }  


Before that call_manager Already in CellularCallIpcInterfaceProxy The initialization of will systemAbilityId(TELEPHONY_CELLULAR_CALL_SYS_ABILITY_ID) adopt ConnectService() Complete the correspondence SA agent IRemoteObject Acquisition , Then construct the corresponding Proxy class , So you can make sure IPC communication proxy and stub Corresponding . In the next section we will see , Corresponding stub In fact cellular_call Registered in .
 

1.  void CellularCallIpcInterfaceProxy::Init(int32_t systemAbilityId)  
2.  {  
3.      systemAbilityId_ = systemAbilityId;  
4.    
5.      int32_t result = ConnectService();  
6.      if (result != TELEPHONY_SUCCESS) {  
7.          TELEPHONY_LOGE("connect service failed,errCode: %{public}X", result);  
8.          Timer::start(CONNECT_SERVICE_WAIT_TIME, CellularCallIpcInterfaceProxy::task);  
9.          return;  
10.      }  
11.      TELEPHONY_LOGI("connected to cellular call service successfully!");  
12.  }  


When called to cellularCallInterfacePtr_->Answer when ,CellularCallInterface Of Answer Virtual functions , Will be CellularCallProxy Of Answer rewrite , So actually implement CellularCallProxy Of Answer function , It's a IRemoteProxy class . and callInfo Information is converted into MessageParcel Form through IPC Of SendRequest issue .
 
class CellularCallProxy : public IRemoteProxy<CellularCallInterface> { 
 

1.  int32_t CellularCallProxy::Answer(const CellularCallInfo &callInfo)  
2.  {  
3.      MessageOption option;  
4.      MessageParcel in;  
5.      MessageParcel out;  
6.    
7.      if (!in.WriteInterfaceToken(CellularCallProxy::GetDescriptor())) {  
8.          return TELEPHONY_ERR_WRITE_DESCRIPTOR_TOKEN_FAIL;  
9.      }  
10.      if (!in.WriteInt32(MAX_SIZE)) {  
11.          return TELEPHONY_ERR_WRITE_DATA_FAIL;  
12.      }  
13.      if (!in.WriteRawData((const void *)&callInfo, sizeof(CellularCallInfo))) {  
14.          return TELEPHONY_ERR_WRITE_DATA_FAIL;  
15.      }  
16.      int32_t error = Remote()->SendRequest(ANSWER, in, out, option);  
17.      if (error == ERR_NONE) {  
18.          return out.ReadInt32();  
19.      }  
20.      return error;  
21.  }  

 

So let's start here ,Answer Process in call_manager The processing of has been completed .

 

3.2.2.2 Answer The incident happened in cellular_call Processing in

 

IPC(Inter-Process Communication) And RPC(Remote Procedure Call) Mechanism is used to realize cross process communication , The difference is that the former uses Binder drive , Used for cross process communication within the device , The latter uses soft bus driver , Used for cross device and cross process communication .IPC and RPC The client is usually used - The server (Client-Server) Model , Service requester (Client) Available service providers (Server) Agent for (Proxy), The data communication between processes is realized by reading and writing data through this agent .

 

Usually ,Server Will register the system capability first (System Ability) To the System Capability Manager (System Ability Manager, abbreviation SAMgr) in ,SAMgr Responsible for managing these SA And to Client Provide relevant interfaces .Client With a specific SA signal communication , You have to start with SAMgr Get the SA Agent for , Then use agents and SA signal communication . Use Proxy Indicates the service requestor ,Stub Indicates that the service provider . Implementation code in /foundation/communication/ipc Under the table of contents .

 

SA Register and start :SA Need to put your own AbilityStub Case passed AddSystemAbility Interface registered to SystemAbilityManager.

 

SA Get and call : adopt SystemAbilityManager Of GetSystemAbility Method to get the corresponding SA Agent for IRemoteObject, And then construct AbilityProxy. So you can make sure proxy and stub Corresponding .

 

Last time we were in call_manager I see SA The acquisition process of , Let's take a look at this SA The registration process , Remember TELEPHONY_CELLULAR_CALL_SYS_ABILITY_ID This systemAbilityId Do you ? It's our registration SA The key to .

 

1.  bool g_registerResult =  
2.      SystemAbility::MakeAndRegisterAbility(DelayedSingleton<CellularCallService>::GetInstance().get());  
3.    
4.  CellularCallService::CellularCallService() : SystemAbility(TELEPHONY_CELLULAR_CALL_SYS_ABILITY_ID, true)  
5.  {  
6.      state_ = ServiceRunningState::STATE_STOPPED;  
7.  }  


So we can finish stub Registration of , Passed before proxy The message will pass IPC It's been delivered here stub in .IPC The process is complicated , There will be no further discussion here , Interested students can learn by themselves .

 

because IPCObjectStub Of OnRemoteRequest Are virtual functions that will be inherited IPCObjectStub Class CellularCallStub Of OnRemoteRequest Function rewriting .

 

1.  int32_t CellularCallStub::OnRemoteRequest(  
2.      uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)  
3.  {  
4.      std::u16string myDescriptor = CellularCallStub::GetDescriptor();  
5.      std::u16string remoteDescriptor = data.ReadInterfaceToken();  
6.      if (myDescriptor != remoteDescriptor) {  
7.          TELEPHONY_LOGE("descriptor checked fail");  
8.          return TELEPHONY_ERR_DESCRIPTOR_MISMATCH;  
9.      }  
10.    
11.      auto itFunc = requestFuncMap_.find(code);  
12.      if (itFunc != requestFuncMap_.end()) {  
13.          auto requestFunc = itFunc->second;  
14.          if (requestFunc != nullptr) {  
15.              return (this->*requestFunc)(data, reply);  
16.          }  
17.      }  
18.      TELEPHONY_LOGD("CellularCallStub::OnRemoteRequest, default case, need check.");  
19.      return IPCObjectStub::OnRemoteRequest(code, data, reply, option);  
20.  }  


Here will be based on map Table to find the corresponding processing function , Before our code = 4 yes ANSWER, Corresponding processing should be performed here .
 

1.  CellularCallStub::CellularCallStub()  
2.  {  
3.      Init();  
4.      TELEPHONY_LOGD("CellularCallStub::CellularCallStub");  
5.      requestFuncMap_[DIAL] = &CellularCallStub::DialInner;  
6.      requestFuncMap_[HANG_UP] = &CellularCallStub::HangUpInner;  
7.      requestFuncMap_[REJECT] = &CellularCallStub::RejectInner;  
8.      requestFuncMap_[ANSWER] = &CellularCallStub::AnswerInner;  
9.      requestFuncMap_[EMERGENCY_CALL] = &CellularCallStub::IsEmergencyPhoneNumberInner;  
10.      requestFuncMap_[HOLD_CALL] = &CellularCallStub::HoldCallInner;  
11.      requestFuncMap_[UN_HOLD_CALL] = &CellularCallStub::UnHoldCallInner;  
12.      requestFuncMap_[SWITCH_CALL] = &CellularCallStub::SwitchCallInner;  
13.      requestFuncMap_[COMBINE_CONFERENCE] = &CellularCallStub::CombineConferenceInner;  
14.      requestFuncMap_[SEPARATE_CONFERENCE] = &CellularCallStub::SeparateConferenceInner;  
15.      requestFuncMap_[CALL_SUPPLEMENT] = &CellularCallStub::CallSupplementInner;  
16.      requestFuncMap_[REGISTER_CALLBACK] = &CellularCallStub::RegisterCallBackInner;  
17.      requestFuncMap_[UNREGISTER_CALLBACK] = &CellularCallStub::UnRegisterCallBackInner;  
18.      requestFuncMap_[START_DTMF] = &CellularCallStub::StartDtmfInner;  
19.      requestFuncMap_[STOP_DTMF] = &CellularCallStub::StopDtmfInner;  
20.      requestFuncMap_[SEND_DTMF] = &CellularCallStub::SendDtmfInner;  
21.      requestFuncMap_[SEND_DTMF_STRING] = &CellularCallStub::SendDtmfStringInner;  
22.      requestFuncMap_[SET_CALL_TRANSFER] = &CellularCallStub::SetCallTransferInner;  
23.      requestFuncMap_[GET_CALL_TRANSFER] = &CellularCallStub::GetCallTransferInner;  
24.      requestFuncMap_[SET_CALL_WAITING] = &CellularCallStub::SetCallWaitingInner;  
25.      requestFuncMap_[GET_CALL_WAITING] = &CellularCallStub::GetCallWaitingInner;  
26.      requestFuncMap_[SET_CALL_RESTRICTION] = &CellularCallStub::SetCallRestrictionInner;  
27.      requestFuncMap_[GET_CALL_RESTRICTION] = &CellularCallStub::GetCallRestrictionInner;  
28.      requestFuncMap_[SET_CALL_PREFERENCE_MODE] = &CellularCallStub::SetCallPreferenceModeInner;  
29.      requestFuncMap_[GET_CALL_PREFERENCE_MODE] = &CellularCallStub::GetCallPreferenceModeInner;  
30.      requestFuncMap_[SET_LTE_IMS_SWITCH_STATUS] = &CellularCallStub::SetLteImsSwitchStatusInner;  
31.      requestFuncMap_[GET_LTE_IMS_SWITCH_STATUS] = &CellularCallStub::GetLteImsSwitchStatusInner;  
32.      requestFuncMap_[CTRL_CAMERA] = &CellularCallStub::CtrlCameraInner;  
33.      requestFuncMap_[SET_PREVIEW_WINDOW] = &CellularCallStub::SetPreviewWindowInner;  
34.      requestFuncMap_[SET_DISPLAY_WINDOW] = &CellularCallStub::SetDisplayWindowInner;  
35.      requestFuncMap_[SET_CAMERA_ZOOM] = &CellularCallStub::SetCameraZoomInner;  
36.      requestFuncMap_[SET_PAUSE_IMAGE] = &CellularCallStub::SetPauseImageInner;  
37.      requestFuncMap_[SET_DEVICE_DIRECTION] = &CellularCallStub::SetDeviceDirectionInner;  
38.  } 


AnswerInner Subsequent processing will be carried out , This is from data The corresponding callinfo Information , At the end of the function, the... Calling this file is listed Answer(), And write the returned result to reply in , This return value is the result of the function execution , by Int32 Shaping values .
 

1.  int32_t CellularCallStub::AnswerInner(MessageParcel &data, MessageParcel &reply)  
2.  {  
3.      TELEPHONY_LOGD("CellularCallStub::AnswerInner ANSWER");  
4.      int32_t size = data.ReadInt32();  
5.      TELEPHONY_LOGD("CellularCallStub::OnRemoteRequest:size=%{public}u, MAX_SIZE=%{public}u\n", size, MAX_SIZE);  
6.      size = ((size > MAX_SIZE) ? 0 : size);  
7.      if (size <= 0) {  
8.          TELEPHONY_LOGE("CellularCallStub::OnRemoteRequest data size error");  
9.          return TELEPHONY_ERR_FAIL;  
10.      }  
11.      auto pCallInfo = (CellularCallInfo *)data.ReadRawData(sizeof(CellularCallInfo));  
12.      if (pCallInfo == nullptr) {  
13.          TELEPHONY_LOGE("AnswerInner return, pCallInfo is nullptr.");  
14.          return TELEPHONY_ERR_ARGUMENT_INVALID;  
15.      }  
16.      reply.WriteInt32(Answer(*pCallInfo));  
17.      return TELEPHONY_SUCCESS;  
18.  }  


Answer The function is to complete with ril Key to interaction . First of all, according to the callInfo Get information about calltype, There are currently three kinds of calltype, Respectively cs_call、ims_call、ott_call. In determining calltype after , adopt slotId_ stay GetCsControl() Get the corresponding CSControl object .
 

1.  int32_t CellularCallStub::Answer(const CellularCallInfo &callInfo)  
2.  {  
3.      if (!IsValidSlotId(callInfo.slotId)) {  
4.          TELEPHONY_LOGE("CellularCallStub::Answer return, invalid slot id");  
5.          return CALL_ERR_INVALID_SLOT_ID;  
6.      }  
7.      if (CallType::TYPE_CS == callInfo.callType) {  
8.          auto control = GetCsControl(slotId_);  
9.          if (control == nullptr) {  
10.              TELEPHONY_LOGE("CellularCallStub::Answer return, control is nullptr");  
11.              return TELEPHONY_ERR_LOCAL_PTR_NULL;  
12.          }  
13.          return control->Answer(callInfo);  
14.      } else if (CallType::TYPE_IMS == callInfo.callType) {  
15.          auto imsControl = GetImsControl(slotId_);  
16.          if (imsControl == nullptr) {  
17.              TELEPHONY_LOGE("CellularCallStub::Answer return, imsControl is nullptr");  
18.              return TELEPHONY_ERR_LOCAL_PTR_NULL;  
19.          }  
20.          return imsControl->Answer(callInfo);  
21.      }  
22.      TELEPHONY_LOGE("CellularCallStub::Answer return, call type error.");  
23.      return TELEPHONY_ERR_ARGUMENT_INVALID;  
24.  }  


This calls to CSControl::Answer function , Will be based on callInfo Get the corresponding CellularCallConnectionCS and CALL_STATUS, The status is incoming 、 Ring the bell 、 Wait state , It will call CellularCallConnectionCS Corresponding function .
 

1.  int32_t CSControl::Answer(const CellularCallInfo &callInfo)  
2.  {  
3.      auto pConnection =  
4.          GetConnectionData<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callInfo.phoneNum);  
5.      if (pConnection == nullptr) {  
6.          TELEPHONY_LOGI("Answer: connection cannot be matched, use index directly");  
7.          pConnection =  
8.              FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callInfo.index);  
9.      }  
10.      if (pConnection == nullptr) {  
11.          TELEPHONY_LOGE("Answer return, error type: connection is null");  
12.          return CALL_ERR_CALL_CONNECTION_NOT_EXIST;  
13.      }  
14.    
15.      /** 
16.       * <stat> (state of the call): 
17.       * 0 active 
18.       * 1 held 
19.       * 2 dialing (MO call) 
20.       * 3 alerting (MO call) 
21.       * 4 incoming (MT call) 
22.       * 5 waiting (MT call) 
23.       */  
24.      // There is an active call when you call, or third party call waiting  
25.      if (IsInState(connectionMap_, CALL_STATUS_ACTIVE) || pConnection->GetStatus() == CALL_STATUS_WAITING) {  
26.          TELEPHONY_LOGD("Answer there is an active call when you call, or third party call waiting");  
27.          auto con =  
28.              FindConnectionByState<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, CALL_STATUS_ACTIVE);  
29.          if (con != nullptr) {  
30.              /** 
31.               * shows commands to start the call, to switch from voice to data (In Call Modification) and to hang up 
32.               * the call. +CMOD and +FCLASS commands indicate the current settings before dialling or answering 
33.               * command, not that they shall be given just before D or A command. 
34.               */  
35.              TELEPHONY_LOGD("Answer: There is an active session currently, and it needs to hold");  
36.              con->SwitchCallRequest(GetSlotId());  
37.          } else {  
38.              TELEPHONY_LOGE("Answer return, error type: con is null, there are no active calls");  
39.          }  
40.      }  
41.      if (pConnection->GetStatus() == CALL_STATUS_INCOMING || pConnection->GetStatus() == CALL_STATUS_ALERTING ||  
42.          pConnection->GetStatus() == CALL_STATUS_WAITING) {  
43.          return pConnection->AnswerRequest(GetSlotId());  
44.      }  
45.    
46.      TELEPHONY_LOGE("CSControl::Answer return, error type: call state error, phone not ringing.");  
47.      return CALL_ERR_CALL_STATE;  
48.  }  


Later, it will call CellularCallConnectionCS::AnswerRequest and core_service It's interactive .GetCore Will be based on slotId Get the corresponding Core, And then use Get Function to get the corresponding event, Set up Owner by CellularCallHandler, When waiting for the return, call back the corresponding handler.

1.  int32_t CellularCallConnectionCS::AnswerRequest(int32_t slotId)  
2.  {  
3.      auto core = GetCore(slotId);  
4.      if (core == nullptr) {  
5.          TELEPHONY_LOGE("AnswerRequest return, error type: core is nullptr.");  
6.          return CALL_ERR_RESOURCE_UNAVAILABLE;  
7.      }  
8.      auto event = AppExecFwk::InnerEvent::Get(ObserverHandler::RADIO_ACCEPT_CALL);  
9.      if (event == nullptr) {  
10.          TELEPHONY_LOGE("AnswerRequest return, error type: event is nullptr.");  
11.          return CALL_ERR_RESOURCE_UNAVAILABLE;  
12.      }  
13.      if (DelayedSingleton<CellularCallService>::GetInstance() == nullptr) {  
14.          TELEPHONY_LOGE("AnswerRequest return, error type: GetInstance() is nullptr.");  
15.          return CALL_ERR_RESOURCE_UNAVAILABLE;  
16.      }  
17.      event->SetOwner(DelayedSingleton<CellularCallService>::GetInstance()->GetHandler(slotId));  
18.      core->Answer(event);  
19.      return TELEPHONY_SUCCESS;  
20.  }  


It's done here Answer Process in cellular_call Call to .

 

3.2.2.3 Answer The incident happened in core_servicel Processing in

 

This part of the code will call core Corresponding Answer function , The message will be delivered to those responsible for the core services and RIL Adapter Communication interaction tel_ril In the code .

 

1.  void Core::Answer(const AppExecFwk::InnerEvent::Pointer &result)  
2.  {  
3.      if (telRilManager_ == nullptr) {  
4.          TELEPHONY_LOGE("telRilManager is null!");  
5.          return;  
6.      }  
7.      telRilManager_->Answer(result);  
8.  }  


Go further to be responsible for tel_ril Management category TelRilManager in , Judge the corresponding telRilCall_ Is it empty , If it is not empty, you can continue to call .
 

1.  void TelRilManager::Answer(const AppExecFwk::InnerEvent::Pointer &result)  
2.  {  
3.      if (telRilCall_ != nullptr) {  
4.          telRilCall_->Answer(result);  
5.      } else {  
6.          TELEPHONY_LOGE("telRilCall_ is null");  
7.      }  
8.  }  

 

telRilCall_ Is in TelRilManager In the initialization of . among InitCellularRadio First, through ServiceManager Get cellular_radio1 Corresponding service. And then in InitTelInfo of use cellularRadio_ and observerHandler_ structure telRilCall_.
 

1.  bool TelRilManager::OnInit()  
2.  {  
3.      bool res = false;  
4.      int i = 0;  
5.    
6.      do {  
7.          res = InitCellularRadio(true);  
8.          if (!res) {  
9.              i++;  
10.              sleep(1);  
11.              TELEPHONY_LOGD("Initialization cellular radio failed. Try initialization again!");  
12.          } else {  
13.              InitTelInfo();  
14.          }  
15.      } while (!res && (i < RIL_INIT_COUNT_MAX));  
16.      return res;  
17.  }  


Call to teRilCall Of Answer Function to process , use CreateTelRilRequest structure telRilRequest , adopt TelRilBase Of SendInt32Event issue .
 

1.  void TelRilCall::Answer(const AppExecFwk::InnerEvent::Pointer &result)  
2.  {  
3.      std::shared_ptr<TelRilRequest> telRilRequest = CreateTelRilRequest(HREQ_CALL_ANSWER, result);  
4.      if (telRilRequest == nullptr) {  
5.          TELEPHONY_LOGE("telRilRequest is nullptr");  
6.          return;  
7.      }  
8.      if (cellularRadio_ == nullptr) {  
9.          TELEPHONY_LOGE("%{public}s  cellularRadio_ == nullptr", __func__);  
10.          ErrorResponse(telRilRequest->serialId_, HRilErrType::HRIL_ERR_GENERIC_FAILURE);  
11.          return;  
12.      }  
13.    
14.      int ret = SendInt32Event(HREQ_CALL_ANSWER, telRilRequest->serialId_);  
15.      TELEPHONY_LOGD("HREQ_CALL_ANSWER ret %{public}d", ret);  
16.  }  


From the situation of calling , Then through IPC Of SendRequest The request will be dispatchId and data issue cellular_radio1.
 

1.  int32_t TelRilBase::SendInt32Event(int32_t dispatchId, int32_t value)  
2.  {  
3.      int status = 0;  
4.      if (cellularRadio_ != nullptr) {  
5.          MessageParcel data;  
6.          MessageParcel reply;  
7.          data.WriteInt32(value);  
8.          OHOS::MessageOption option = {OHOS::MessageOption::TF_ASYNC};  
9.          status = cellularRadio_->SendRequest(dispatchId, data, reply, option);  
10.          TELEPHONY_LOGD("TelRilBase SendInt32Event, dispatchId:%{public}d, status:%{public}d", dispatchId, status);  
11.      } else {  
12.          TELEPHONY_LOGE("cellularRadio_ is nullptr!!!");  
13.      }  
14.      return status;  
15.  }  


Come here Answer Process in core_service The processing in the service is finished .

 

3.2.2.4 Answer The incident happened in ril_adapter Processing in

 

From the current code call, it may be from vendor call hril_hdf Of dispatch, Then deliver the message to ril_adapter in

Below is hril_hdf The initialization process .

 

1.  struct HdfDriverEntry g_rilAdapterDevEntry = {  
2.      .moduleVersion = 1,  
3.      .moduleName = MODULE_NAME,  
4.      .Bind = RilAdapterBind,  
5.      .Init = RilAdapterInit,  
6.      .Release = RilAdapterRelease,  
7.  };  
8.  HDF_INIT(g_rilAdapterDevEntry);  


You can see hdf Initialization of includes MODULE_ NAME、RilAdapterBind、RilAdapterInit.

Bind The process is as follows .

 

1.  static int32_t RilAdapterBind(struct HdfDeviceObject *device)  
2.  {  
3.      if (device == NULL) {  
4.          return HDF_ERR_INVALID_OBJECT;  
5.      }  
6.      device->service = &g_rilAdapterService;  
7.      return HDF_SUCCESS;  
8.  }  


You can see service Of dispatch Corresponding to RilAdapterDispatch.

 

1.  static struct IDeviceIoService g_rilAdapterService = {  
2.      .Dispatch = RilAdapterDispatch,  
3.      .Open = NULL,  
4.      .Release = NULL,  
5.  };  


 Init The process is as follows :
 

1.  static int32_t RilAdapterInit(struct HdfDeviceObject *device)  
2.  {  
3.      if (device == NULL) {  
4.          return HDF_ERR_INVALID_OBJECT;  
5.      }  
6.      DFX_InstallSignalHandler();  
7.      TELEPHONY_LOGD("Start %{public}s hdf service!", HdfDeviceGetServiceName(device));  
8.      struct HdfSBuf *sbuf = HdfSBufTypedObtain(SBUF_IPC);  
9.      if (sbuf == NULL) {  
10.          TELEPHONY_LOGE("HdfSampleDriverBind, failed to obtain ipc sbuf");  
11.          return HDF_ERR_INVALID_OBJECT;  
12.      }  
13.      if (!HdfSbufWriteString(sbuf, "string")) {  
14.          TELEPHONY_LOGE("HdfSampleDriverBind, failed to write string to ipc sbuf");  
15.          HdfSBufRecycle(sbuf);  
16.          return HDF_FAILURE;  
17.      }  
18.      if (sbuf != NULL) {  
19.          HdfSBufRecycle(sbuf);  
20.      }  
21.      TELEPHONY_LOGD("sbuf IPC obtain test success!");  
22.      if (!IsLoadedVendorLib()) {  
23.          LoadVendor();  
24.      } else {  
25.          TELEPHONY_LOGI("The vendor library has been loaded!");  
26.      }  
27.      return HDF_SUCCESS;  
28.  }  

 

among LoadVendor The corresponding... Will be loaded vendor Of rilLib.

 

1.  static void LoadVendor(void)  
2.  {  
3.      const char *rilLibPath = NULL;  
4.      char vendorLibPath[PARAMETER_ZISE] = {0};  
5.      // Pointer to ril init function in vendor ril  
6.      const HRilOps *(*rilInitOps)(const struct HRilReport *) = NULL;  
7.      // functions returned by ril init function in vendor ril  
8.      const HRilOps *ops = NULL;  
9.    
10.      if (GetVendorLibPath(vendorLibPath) == HDF_SUCCESS) {  
11.          rilLibPath = vendorLibPath;  
12.      } else {  
13.          rilLibPath = g_modem_list[MODEM_INDEX].path;  
14.      }  
15.      if (rilLibPath == NULL) {  
16.          TELEPHONY_LOGE("dynamic library path is empty");  
17.          return;  
18.      }  
19.      TELEPHONY_LOGD("RilInit LoadVendor start with rilLibPath:%{public}s", rilLibPath);  
20.      g_dlHandle = dlopen(rilLibPath, RTLD_NOW);  
21.      if (g_dlHandle == NULL) {  
22.          TELEPHONY_LOGE("dlopen %{public}s is fail. %{public}s", rilLibPath, dlerror());  
23.          return;  
24.      }  
25.      rilInitOps = (const HRilOps *(*)(const struct HRilReport *))dlsym(g_dlHandle, "RilInitOps");  
26.      if (rilInitOps == NULL) {  
27.          dlclose(g_dlHandle);  
28.          TELEPHONY_LOGE("RilInit not defined or exported");  
29.          return;  
30.      }  
31.      ops = rilInitOps(&g_reportOps);  
32.      TELEPHONY_LOGD("RilInit completed");  
33.      HRilRegOps(ops);  
34.  }  


As I said before, it could be vendor Called dispatch, Now the corresponding RilAdapterDispatch, The follow-up treatment is as follows .

 

C++ Written IPC and C Written language IPC Can communicate with each other , The format is not the same .HdfSBuf Can also be combined with MessageParcel Interturn .

 

1.  static int32_t RilAdapterDispatch(  
2.      struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)  
3.  {  
4.      int32_t ret;  
5.      static pthread_mutex_t dispatchMutex = PTHREAD_MUTEX_INITIALIZER;  
6.      pthread_mutex_lock(&dispatchMutex);  
7.      TELEPHONY_LOGD("RilAdapterDispatch cmd:%{public}d", cmd);  
8.      ret = DispatchRequest(SLOTID, cmd, data);  
9.      pthread_mutex_unlock(&dispatchMutex);  
10.      return ret;  
11.  }  


Request Message through IPC to RilAdapter It will pass DispatchRequest Distribute .
 

1.  int32_t DispatchRequest(int32_t slotId, int32_t cmd, struct HdfSBuf *data)  
2.  {  
3.      if (data == nullptr) {  
4.          TELEPHONY_LOGE("miss callback parameter");  
5.          return HDF_ERR_INVALID_PARAM;  
6.      }  
7.      switch (cmd) {  
8.          case HRIL_ADAPTER_RADIO_INDICATION: {  
9.              HdfRemoteService *serviceCallbackInd = HdfSBufReadRemoteService(data);  
10.              if (serviceCallbackInd == nullptr) {  
11.                  TELEPHONY_LOGE("miss callback parameter");  
12.                  return HDF_ERR_INVALID_PARAM;  
13.              }  
14.              RegisterManagerNotifyCallback(slotId, serviceCallbackInd);  
15.              break;  
16.          }  
17.          case HRIL_ADAPTER_RADIO_RESPONSE: {  
18.              HdfRemoteService *serviceCallback = HdfSBufReadRemoteService(data);  
19.              if (serviceCallback == nullptr) {  
20.                  TELEPHONY_LOGE("miss callback parameter");  
21.                  return HDF_ERR_INVALID_PARAM;  
22.              }  
23.              RegisterManagerResponseCallback(slotId, serviceCallback);  
24.              break;  
25.          }  
26.          default:  
27.              DispatchModule(slotId, cmd, data);  
28.      }  
29.      return HDF_SUCCESS;  
30.  }  


In subsequent calls, we know code by HREQ_CALL_ANSWER, So I call DispatchModule.
 

1.  static void DispatchModule(int32_t slotId, int32_t cmd, struct HdfSBuf *data)  
2.  {  
3.      auto itFunc = g_manager.find(slotId);  
4.      if (itFunc != g_manager.end()) {  
5.          auto &manager = itFunc->second;  
6.          if (manager != nullptr) {  
7.              int32_t ret = manager->Dispatch(slotId, cmd, data);  
8.              if (ret != HDF_SUCCESS) {  
9.                  TELEPHONY_LOGE("HRilManager::Dispatch is failed!");  
10.              }  
11.          } else {  
12.              TELEPHONY_LOGE("Manager is nullptr, id:%{public}d, addr:%{public}p!", slotId, &manager);  
13.          }  
14.      } else {  
15.          TELEPHONY_LOGE("Can not find slotId in g_manager: %{public}d!", slotId);  
16.      }  
17.  }  


according to slotId Get the corresponding g_manager Of Dispatch function .
 

1.  int32_t HRilManager::Dispatch(int32_t slotId, int32_t code, struct HdfSBuf *data)  
2.  {  
3.      if (hrilCall_ != nullptr && hrilCall_->IsCallRespOrNotify(code)) {  
4.          hrilCall_->ProcessCallRequest(slotId, code, data);  
5.          return HDF_SUCCESS;  
6.      }  
7.      if (hrilSms_ != nullptr && hrilSms_->IsSmsRespOrNotify(code)) {  
8.          hrilSms_->ProcessSmsRequest(slotId, code, data);  
9.          return HDF_SUCCESS;  
10.      }  
11.      if (hrilSim_ != nullptr && hrilSim_->IsSimRespOrNotify(code)) {  
12.          hrilSim_->ProcessSimRequest(slotId, code, data);  
13.          return HDF_SUCCESS;  
14.      }  
15.      if (hrilNetwork_ != nullptr && hrilNetwork_->IsNetworkRespOrNotify(code)) {  
16.          hrilNetwork_->ProcessNetworkRequest(slotId, code, data);  
17.          return HDF_SUCCESS;  
18.      }  
19.      if (hrilModem_ != nullptr && hrilModem_->IsModemRespOrNotify(code)) {  
20.          hrilModem_->ProcessCommonRequest(slotId, code, data);  
21.          return HDF_SUCCESS;  
22.      }  
23.      if (hrilData_ != nullptr && hrilData_->IsDataRespOrNotify(code)) {  
24.          hrilData_->ProcessDataRequest(slotId, code, data);  
25.          return HDF_SUCCESS;  
26.      }  
27.      return HDF_FAILURE;  
28.  }  


Because of our code = 4, stay 0 To 100 Between , So it will be judged as callrequest

So call the following function .

 

1.  void HRilCall::ProcessCallRequest(int32_t slotId, int32_t code, struct HdfSBuf *data)  
2.  {  
3.      auto itFunc = reqMemberFuncMap_.find(code);  
4.      if (itFunc != reqMemberFuncMap_.end()) {  
5.          auto memberFunc = itFunc->second;  
6.          if (memberFunc != nullptr) {  
7.              (this->*memberFunc)(slotId, data);  
8.          }  
9.      } else {  
10.          TELEPHONY_LOGE("Can not find CallRequest code in reqMemberFuncMap_!");  
11.      }  
12.  }  


Request as follows .
 

1.  // request  
2.      reqMemberFuncMap_[HREQ_CALL_GET_CALL_LIST] = &HRilCall::GetCallList;  
3.      reqMemberFuncMap_[HREQ_CALL_DIAL] = &HRilCall::Dial;  
4.      reqMemberFuncMap_[HREQ_CALL_HANGUP] = &HRilCall::Hangup;  
5.      reqMemberFuncMap_[HREQ_CALL_REJECT] = &HRilCall::Reject;  
6.      reqMemberFuncMap_[HREQ_CALL_ANSWER] = &HRilCall::Answer;  
7.      reqMemberFuncMap_[HREQ_CALL_HOLD_CALL] = &HRilCall::HoldCall;  
8.      reqMemberFuncMap_[HREQ_CALL_UNHOLD_CALL] = &HRilCall::UnHoldCall;  
9.      reqMemberFuncMap_[HREQ_CALL_SWITCH_CALL] = &HRilCall::SwitchCall;  
10.      reqMemberFuncMap_[HREQ_CALL_GET_CLIP] = &HRilCall::GetClip;  
11.      reqMemberFuncMap_[HREQ_CALL_SET_CLIP] = &HRilCall::SetClip;  
12.      reqMemberFuncMap_[HREQ_CALL_COMBINE_CONFERENCE] = &HRilCall::CombineConference;  
13.      reqMemberFuncMap_[HREQ_CALL_SEPARATE_CONFERENCE] = &HRilCall::SeparateConference;  
14.      reqMemberFuncMap_[HREQ_CALL_CALL_SUPPLEMENT] = &HRilCall::CallSupplement;  
15.      reqMemberFuncMap_[HREQ_CALL_GET_CALL_WAITING] = &HRilCall::GetCallWaiting;  
16.      reqMemberFuncMap_[HREQ_CALL_SET_CALL_WAITING] = &HRilCall::SetCallWaiting;  
17.      reqMemberFuncMap_[HREQ_CALL_GET_CALL_TRANSFER_INFO] = &HRilCall::GetCallTransferInfo;  
18.      reqMemberFuncMap_[HREQ_CALL_SET_CALL_TRANSFER_INFO] = &HRilCall::SetCallTransferInfo;  
19.      reqMemberFuncMap_[HREQ_CALL_GET_CALL_RESTRICTION] = &HRilCall::GetCallRestriction;  
20.      reqMemberFuncMap_[HREQ_CALL_SET_CALL_RESTRICTION] = &HRilCall::SetCallRestriction;  
21.      reqMemberFuncMap_[HREQ_CALL_GET_CLIR] = &HRilCall::GetClir;  
22.      reqMemberFuncMap_[HREQ_CALL_SET_CLIR] = &HRilCall::SetClir;  
23.      reqMemberFuncMap_[HREQ_CALL_START_DTMF] = &HRilCall::StartDtmf;  
24.      reqMemberFuncMap_[HREQ_CALL_SEND_DTMF] = &HRilCall::SendDtmf;  
25.      reqMemberFuncMap_[HREQ_CALL_STOP_DTMF] = &HRilCall::StopDtmf;  
26.      reqMemberFuncMap_[HREQ_CALL_GET_IMS_CALL_LIST] = &HRilCall::GetImsCallList;  
27.      reqMemberFuncMap_[HREQ_CALL_GET_CALL_PREFERENCE] = &HRilCall::GetCallPreferenceMode;  
28.      reqMemberFuncMap_[HREQ_CALL_SET_CALL_PREFERENCE] = &HRilCall::SetCallPreferenceMode;  
29.      reqMemberFuncMap_[HREQ_CALL_GET_LTEIMSSWITCH_STATUS] = &HRilCall::GetLteImsSwitchStatus;  
30.      reqMemberFuncMap_[HREQ_CALL_SET_LTEIMSSWITCH_STATUS] = &HRilCall::SetLteImsSwitchStatus;  


call request The corresponding processing function is Answer.
 

1.  void HRilCall::Answer(int32_t slotId, struct HdfSBuf *data)  
2.  {  
3.      int32_t serial = 0;  
4.      if (!HdfSbufReadInt32(data, &serial)) {  
5.          TELEPHONY_LOGE("miss serial parameter");  
6.          return;  
7.      }  
8.      ReqDataInfo *requestInfo = CreateHRilRequest(serial, slotId, HREQ_CALL_ANSWER);  
9.      if (requestInfo == nullptr) {  
10.          TELEPHONY_LOGE("RilAdapter failed to do Create Answer HRilRequest!");  
11.          return;  
12.      }  
13.      if (callFuncs_ == nullptr) {  
14.          TELEPHONY_LOGE("RilAdapter HRilCall::Dial  callFuncs_ is nullptr!");  
15.          SafeFrees(requestInfo);  
16.          return;  
17.      }  
18.      callFuncs_->Answer(requestInfo);  
19.      SafeFrees(requestInfo);  
20.  }  


The first thing to do is to create HRilRequest, Encapsulate information into requestInfo in .
 

1.  ReqDataInfo *CreateHRilRequest(int32_t serial, int32_t slotId, int32_t request)  
2.  {  
3.      ReqDataInfo *requestInfo = nullptr;  
4.      HRilSimSlotId simSlotId = (HRilSimSlotId)slotId;  
5.      requestInfo = (ReqDataInfo *)calloc(1, sizeof(ReqDataInfo));  
6.      if (requestInfo == nullptr) {  
7.          return nullptr;  
8.      }  
9.      requestInfo->slotId = simSlotId;  
10.      requestInfo->request = request;  
11.      requestInfo->serial = serial;  
12.      return requestInfo;  
13.  }  


stay LoadVendor Called when the HRilRegOps(ops) It's going to be register.
 

1.  void HRilRegOps(const HRilOps *hrilOps)  
2.  {  
3.      int i;  
4.      if (hrilOps == nullptr) {  
5.          TELEPHONY_LOGE("HRilRegOps: HRilRegOps * nullptr");  
6.          return;  
7.      }  
8.      if (rilRegisterStatus > RIL_REGISTER_IS_NONE) {  
9.          TELEPHONY_LOGE("HRilRegOps is running!!!!");  
10.          return;  
11.      }  
12.      rilRegisterStatus = RIL_REGISTER_IS_RUNNING;  
13.      vendorLibLoadStatus = RIL_REGISTER_IS_RUNNING;  
14.      (void)memcpy_s(&g_callBacks, sizeof(HRilOps), hrilOps, sizeof(HRilOps));  
15.    
16.      for (i = HRIL_SIM_SLOT_1; i < HRIL_SIM_SLOT_NUM; i++) {  
17.          g_manager[i] = std::make_unique<HRilManager>();  
18.          if (g_callBacks.smsOps != nullptr) {  
19.              g_manager[i]->RegisterSmsFuncs(g_callBacks.smsOps);  
20.          }  
21.          if (g_callBacks.callOps != nullptr) {  
22.              g_manager[i]->RegisterCallFuncs(g_callBacks.callOps);  
23.          }  
24.          if (g_callBacks.dataOps != nullptr) {  
25.              g_manager[i]->RegisterDataFuncs(g_callBacks.dataOps);  
26.          }  
27.          if (g_callBacks.modemOps != nullptr) {  
28.              g_manager[i]->RegisterModemFuncs(g_callBacks.modemOps);  
29.          }  
30.          if (g_callBacks.networkOps != nullptr) {  
31.              g_manager[i]->RegisterNetworkFuncs(g_callBacks.networkOps);  
32.          }  
33.          if (g_callBacks.simOps != nullptr) {  
34.              g_manager[i]->RegisterSimFuncs(g_callBacks.simOps);  
35.          }  
36.      }  
37.  }  


Here will be callOps Sign up to callFuncs_ in , and g_callBacks It actually corresponds to hrilOps.
 

1.  HRilOps g_hrilOps = {  
2.      .callOps = &g_callReqOps,  
3.      .simOps = &g_simReqOps,  
4.      .smsOps = &g_smsReqOps,  
5.      .networkOps = &g_networkReqOps,  
6.      .dataOps = &g_dataReqOps,  
7.      .modemOps = &g_modemReqOps,  
8.  };  


.callOps Corresponding to &g_callReqOps, The corresponding function comparison table is as follows .
 

1.  static const HRilCallReq g_callReqOps = {  
2.      .GetCallList = ReqGetCallList,  
3.      .Dial = ReqDial,  
4.      .Hangup = ReqHangup,  
5.      .Reject = ReqReject,  
6.      .Answer = ReqAnswer,  
7.      .GetClip = ReqGetClip,  
8.      .SetClip = ReqSetClip,  
9.      .HoldCall = ReqHoldCall,  
10.      .UnHoldCall = ReqUnHoldCall,  
11.      .SwitchCall = ReqSwitchCall,  
12.      .CombineConference = ReqCombineConference,  
13.      .SeparateConference = ReqSeparateConference,  
14.      .CallSupplement = ReqCallSupplement,  
15.      .GetCallWaiting = ReqGetCallWaiting,  
16.      .SetCallWaiting = ReqSetCallWaiting,  
17.      .GetCallTransferInfo = ReqGetCallTransferInfo,  
18.      .SetCallTransferInfo = ReqSetCallTransferInfo,  
19.      .GetCallRestriction = ReqGetCallRestriction,  
20.      .SetCallRestriction = ReqSetCallRestriction,  
21.      .GetClir = ReqGetClir,  
22.      .SetClir = ReqSetClir,  
23.      .StartDtmf = ReqStartDtmf,  
24.      .SendDtmf = ReqSendDtmf,  
25.      .StopDtmf = ReqStopDtmf,  
26.      .GetImsCallList = ReqGetImsCallList,  
27.      .GetCallPreferenceMode = ReqGetCallPreferenceMode,  
28.      .SetCallPreferenceMode = ReqSetCallPreferenceMode,  
29.      .GetLteImsSwitchStatus = ReqGetLteImsSwitchStatus,  
30.      .SetLteImsSwitchStatus = ReqSetLteImsSwitchStatus,  
31.  }; 

 

Find the right one ReqAnswer Follow up , In fact, we have reached AT Command processing layer .
 

1.  void ReqAnswer(const ReqDataInfo *requestInfo)  
2.  {  
3.      int32_t ret;  
4.      int32_t err = HRIL_ERR_SUCCESS;  
5.      struct ReportInfo reportInfo = {0};  
6.      ResponseInfo *pResponse = NULL;  
7.    
8.      ret = SendCommandLock("ATA", NULL, 0, &pResponse);  
9.      if (ret != HRIL_ERR_SUCCESS || !pResponse->success) {  
10.          err = HRIL_ERR_GENERIC_FAILURE;  
11.      }  
12.      reportInfo = CreateReportInfo(requestInfo, err, HRIL_RESPONSE, 0);  
13.      OnCallReport(HRIL_SIM_SLOT_1, reportInfo, NULL, 0);  
14.      FreeResponseInfo(pResponse);  
15.  }  


Subsequent calls SendCommandLock function , Here will be requestInfo Processing into AT command .
 

1.  int SendCommandLock(const char *command, const char *prefix, long long timeout, ResponseInfo **outResponse)  
2.  {  
3.      const char *atCmd = "AT";  
4.      int err;  
5.      if (pthread_equal(g_reader, pthread_self()) != 0) {  
6.          TELEPHONY_LOGE("The read thread prohibits sending commands.");  
7.          return AT_ERR_INVALID_THREAD;  
8.      }  
9.    
10.      TELEPHONY_LOGD("command %{public}s, NeedATPause:%{public}d, atCmd:%{public}s", command, g_isNeedATPause, atCmd);  
11.      pthread_mutex_lock(&g_commandmutex);  
12.      if (g_isNeedATPause) {  
13.          pthread_cond_signal(&g_commandcond);  
14.          err = SendCommandNoLock(atCmd, timeout, outResponse);  
15.          if (err != 0) {  
16.              TELEPHONY_LOGD("NeedATPause err = %{public}d cmd:%{public}s", err, command);  
17.          }  
18.          if (g_atWatch != NULL) {  
19.              g_atWatch();  
20.          }  
21.          g_isNeedATPause = false;  
22.          alarm(0);  
23.      }  
24.      g_prefix = prefix;  
25.      err = SendCommandNoLock(command, timeout, outResponse);  
26.      pthread_mutex_unlock(&g_commandmutex);  
27.      TELEPHONY_LOGD("err = %{public}d, cmd:%{public}s", err, command);  
28.      // when timeout to process  
29.      if (err == AT_ERR_TIMEOUT && g_onTimeout != NULL) {  
30.          g_onTimeout();  
31.      } else if (err == AT_ERR_GENERIC) {  
32.          TELEPHONY_LOGD("OnReaderClosed() err = %{public}d", err);  
33.          OnReaderClosed();  
34.      }  
35.      return err;  
36.  }  


The actual processing is in this function SendCommandNoLock.
 

1.  int SendCommandNoLock(const char *command, long long timeout, ResponseInfo **outResponse)  
2.  {  
3.      long long defaultTimeout = 50000;  
4.      int err = 0;  
5.      struct timespec time;  
6.      if (g_response != NULL) {  
7.          err = AT_ERR_COMMAND_PENDING;  
8.          TELEPHONY_LOGE("g_response is not null, so the command cannot be sent.");  
9.          ClearCurCommand();  
10.          return err;  
11.      }  
12.      g_response = (ResponseInfo *)calloc(1, sizeof(ResponseInfo));  
13.      if (g_response == NULL) {  
14.          err = AT_ERR_GENERIC;  
15.          TELEPHONY_LOGE("g_response calloc is fail, err:%{public}d.", err);  
16.          ClearCurCommand();  
17.          return err;  
18.      }  
19.      err = WriteATCommand(command, 0, g_atFd);  
20.      if (err != VENDOR_SUCCESS) {  
21.          TELEPHONY_LOGE("send AT cmd is fail, err:%{public}d.", err);  
22.          ClearCurCommand();  
23.          return err;  
24.      }  
25.      SetWaitTimeout(&time, (timeout != 0) ? timeout : defaultTimeout);  
26.      while (g_response->result == NULL && g_readerClosed == 0) {  
27.          err = pthread_cond_timedwait(&g_commandcond, &g_commandmutex, &time);  
28.          if (err == ETIMEDOUT) {  
29.              err = AT_ERR_TIMEOUT;  
30.              TELEPHONY_LOGE("pthread cond timedwait is timeout, err:%{public}d.", err);  
31.              ClearCurCommand();  
32.              return err;  
33.          }  
34.      }  
35.      if (outResponse == NULL) {  
36.          FreeResponseInfo((ResponseInfo *)g_response);  
37.      } else {  
38.          *outResponse = (ResponseInfo *)g_response;  
39.      }  
40.      g_response = NULL;  
41.      if (g_readerClosed > 0) {  
42.          err = AT_ERR_CHANNEL_CLOSED;  
43.          TELEPHONY_LOGE("g_readerClosed is closed, err:%{public}d.", err);  
44.          ClearCurCommand();  
45.          return err;  
46.      }  
47.      err = 0;  
48.      return err;  
49.  } 


adopt WriteATCommand take AT Command to modem, And then wait modem The result of reply processing .
 

1.  int WriteATCommand(const char *s, int isPdu, int atFd)  
2.  {  
3.      TELEPHONY_LOGD("cmd:%{public}s", s);  
4.      ssize_t ret;  
5.      size_t i = 0;  
6.      size_t len = strlen(s);  
7.      if (atFd < 0) {  
8.          return AT_ERR_CHANNEL_CLOSED;  
9.      }  
10.    
11.      while (i < len) {  
12.          do {  
13.              ret = write(atFd, s + i, len - i);  
14.          } while (ret < 0 && errno == EINTR);  
15.          if (ret < 0) {  
16.              return AT_ERR_GENERIC;  
17.          }  
18.          i += ret;  
19.      }  
20.      if (isPdu != 0) {  
21.          do {  
22.              ret = write(atFd, "\x1A", 1);  
23.          } while ((ret < 0 && errno == EINTR) || (ret == 0));  
24.      } else {  
25.          do {  
26.              ret = write(atFd, "\r", 1);  
27.          } while ((ret < 0 && errno == EINTR) || (ret == 0));  
28.      }  
29.      if (ret < 0) {  
30.          return AT_ERR_GENERIC;  
31.      }  
32.      return VENDOR_SUCCESS;  
33.  } 


So far ,Answer The process has been completed from app To modem The transmission of information .


5、 ... and 、 summary


From the analysis process of the third chapter , We've finished from Call ui Respond to incoming calls , Then the whole framework layer call process is completed step by step , In fact, at the end, we just finished the downward transmission of the message modem, After this process modem Also reply , This process is also relatively long, so I won't repeat it here . If we have the opportunity, we can analyze it in the following articles .

 

The whole document is limited by my ability and time , Make up the missing parts as much as possible . from core_service To ril_adapter Call to , Is in vendor In the directory cellular_radio1 Of libhril_hdf.z.so load . Because the current code is still improving , It is possible that the latest version of the code will change .

 

HD flowchart download :https://ost.51cto.com/resource/1716

 

 

copyright notice
author[openharmony],Please bring the original link to reprint, thank you.
https://en.chowdera.com/2022/131/202205102113102966.html

Random recommended