1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "host/commands/modem_simulator/network_service.h"
17 
18 #include <android-base/logging.h>
19 
20 #include <map>
21 #include <sstream>
22 
23 #include "common/libs/utils/files.h"
24 #include "host/commands/modem_simulator/device_config.h"
25 #include "host/commands/modem_simulator/nvram_config.h"
26 #include "host/commands/modem_simulator/thread_looper.h"
27 namespace cuttlefish {
28 
29 // string type; two byte location area code in hexadecimal format
30 static const std::string kAreaCode = "2142";
31 // string type; four byte GERAN/UTRAN cell ID in hexadecimal format
32 static const std::string kCellId = "0000B804";
33 
NetworkService(int32_t service_id,ChannelMonitor * channel_monitor,ThreadLooper * thread_looper)34 NetworkService::NetworkService(int32_t service_id,
35                                ChannelMonitor* channel_monitor,
36                                ThreadLooper* thread_looper)
37     : ModemService(service_id, this->InitializeCommandHandlers(),
38                    channel_monitor, thread_looper),
39       keep_signal_strength_changing_loop_(*this) {
40   InitializeServiceState();
41 }
42 
InitializeCommandHandlers()43 std::vector<CommandHandler> NetworkService::InitializeCommandHandlers() {
44   std::vector<CommandHandler> command_handlers = {
45       CommandHandler(
46           "+CFUN?",
47           [this](const Client& client) { this->HandleRadioPowerReq(client); }),
48       CommandHandler("+CFUN=",
49                      [this](const Client& client, std::string& cmd) {
50                        this->HandleRadioPower(client, cmd);
51                      }),
52       CommandHandler("+REMOTECFUN=",
53                      [this](const Client& client, std::string& cmd) {
54                        this->HandleRadioPower(client, cmd);
55                      }),
56       CommandHandler(
57           "+CSQ",
58           [this](const Client& client) { this->HandleSignalStrength(client); }),
59       CommandHandler("+COPS?",
60                      [this](const Client& client) {
61                        this->HandleQueryNetworkSelectionMode(client);
62                      }),
63       CommandHandler("+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
64                      [this](const Client& client) {
65                        this->HandleRequestOperator(client);
66                      }),
67       CommandHandler("+COPS=?",
68                      [this](const Client& client) {
69                        this->HandleQueryAvailableNetwork(client);
70                      }),
71       CommandHandler("+COPS=",
72                      [this](const Client& client, std::string& cmd) {
73                        this->HandleSetNetworkSelectionMode(client, cmd);
74                      }),
75       CommandHandler("+CREG",
76                      [this](const Client& client, std::string& cmd) {
77                        this->HandleVoiceNetworkRegistration(client, cmd);
78                      }),
79       CommandHandler("+CGREG",
80                      [this](const Client& client, std::string& cmd) {
81                        this->HandleDataNetworkRegistration(client, cmd);
82                      }),
83       CommandHandler("+CEREG",
84                      [this](const Client& client, std::string& cmd) {
85                        this->HandleDataNetworkRegistration(client, cmd);
86                      }),
87       CommandHandler("+CTEC?",
88                      [this](const Client& client) {
89                        this->HandleGetPreferredNetworkType(client);
90                      }),
91       CommandHandler("+CTEC=?",
92                      [this](const Client& client) {
93                        this->HandleQuerySupportedTechs(client);
94                      }),
95       CommandHandler("+CTEC=",
96                      [this](const Client& client, std::string& cmd) {
97                        this->HandleSetPreferredNetworkType(client, cmd);
98                      }),
99       CommandHandler("+REMOTECTEC",
100                      [this](const Client& client, std::string& cmd) {
101                        this->HandleReceiveRemoteCTEC(client, cmd);
102                      }),
103       CommandHandler("+REMOTESIGNAL",
104                      [this](const Client& client, std::string& cmd) {
105                        this->HandleReceiveRemoteSignal(client, cmd);
106                      }),
107       CommandHandler("+REMOTEREG",
108                      [this](const Client& client, std::string& cmd) {
109                        this->HandleReceiveRemoteVoiceDataReg(client, cmd);
110                      }),
111       CommandHandler("+REMOTEIDDISCLOSURE",
112                      [this](const Client& client, std::string& cmd) {
113                        (void)client;
114                        this->HandleIdentifierDisclosure(cmd);
115                      }),
116       CommandHandler("+UPDATESECURITYALGORITHM",
117                      [this](const Client& client, std::string& cmd) {
118                        (void)client;
119                        this->HandleSecurityAlgorithmUpdate(cmd);
120                      }),
121   };
122   return (command_handlers);
123 }
124 
InitializeServiceState()125 void NetworkService::InitializeServiceState() {
126   radio_state_ = RadioState::RADIO_STATE_OFF;
127 
128   modem_radio_capability_ =
129       M_MODEM_TECH_GSM | M_MODEM_TECH_WCDMA | M_MODEM_TECH_LTE | M_MODEM_TECH_NR;
130 
131   auto nvram_config = NvramConfig::Get();
132   auto instance = nvram_config->ForInstance(service_id_);
133 
134   // Default to be ""
135   current_operator_numeric_ = instance.operator_numeric();
136   // Default to be OPER_SELECTION_AUTOMATIC
137   oper_selection_mode_ = (OperatorSelectionMode)instance.network_selection_mode();
138   // Default to be M_MODEM_TECH_LTE | M_MODEM_TECH_WCDMA | M_MODEM_TECH_GSM;
139   preferred_network_mode_ = instance.preferred_network_mode();
140   // Default to be M_MODEM_TECH_LTE
141   current_network_mode_ = (ModemTechnology)instance.modem_technoloy();
142 
143   InitializeNetworkOperator();
144 
145   first_signal_strength_request_ = true;
146   android_last_signal_time_ = 0;
147 
148   keep_signal_strength_changing_loop_.Start();
149 }
150 
InitializeNetworkOperator()151 void NetworkService::InitializeNetworkOperator() {
152   operator_list_.push_back(
153       {"311740", "Android Virtual Operator", "Android", NetworkOperator::OPER_STATE_AVAILABLE});
154   operator_list_.push_back(
155       {"310300", "Alternative Operator", "Alternative", NetworkOperator::OPER_STATE_AVAILABLE});
156   operator_list_.push_back(
157       {"310400", "Hermetic Network Operator", "Hermetic", NetworkOperator::OPER_STATE_FORBIDDEN});
158 
159   if (oper_selection_mode_ == OperatorSelectionMode::OPER_SELECTION_AUTOMATIC) {
160     current_operator_numeric_ = operator_list_.begin()->numeric;
161     operator_list_.begin()->operator_state = NetworkOperator::OPER_STATE_CURRENT;
162   } else if (oper_selection_mode_ == OperatorSelectionMode::OPER_SELECTION_MANUAL_AUTOMATIC) {
163     for (auto& iter : operator_list_) {
164       if (iter.numeric == current_operator_numeric_) {
165         iter.operator_state = NetworkOperator::OPER_STATE_CURRENT;
166         return;
167       }
168     }
169     current_operator_numeric_ = operator_list_.begin()->numeric;
170     operator_list_.begin()->operator_state =
171         NetworkOperator::OPER_STATE_CURRENT;
172   }
173 }
174 
InitializeSimOperator()175 void NetworkService::InitializeSimOperator() {
176   if (sim_service_ == nullptr) {
177     return;
178   }
179   auto sim_operator_numeric = sim_service_->GetSimOperator();
180   if (sim_operator_numeric == "") {
181     return;
182   }
183 
184   // ensure the first element is sim_operator_numeric
185   for (auto iter = operator_list_.begin(); iter != operator_list_.end();
186        ++iter) {
187     if (iter->numeric == sim_operator_numeric) {
188       std::swap(*iter, *(operator_list_.begin()));
189       return;
190     }
191   }
192 
193   {
194     const char *operator_numeric_xml = "etc/modem_simulator/files/numeric_operator.xml";
195     auto file = cuttlefish::modem::DeviceConfig::DefaultHostArtifactsPath(
196         operator_numeric_xml);
197     if (!cuttlefish::FileExists(file) || !cuttlefish::FileHasContent(file)) {
198       return;
199     }
200 
201     XMLDocument doc;
202     auto err = doc.LoadFile(file.c_str());
203     if (err != tinyxml2::XML_SUCCESS) {
204       LOG(ERROR) << "unable to load XML file '" << file << " ', error " << err;
205       return;
206     }
207 
208     XMLElement* resources = doc.RootElement();
209     if (resources == NULL) {
210       return;
211     }
212 
213     XMLElement* stringArray = resources->FirstChildElement("string-array");
214     if (stringArray == NULL) {
215       return;
216     }
217 
218     XMLElement *item = stringArray->FirstChildElement("item");
219     while (item) {
220       const XMLAttribute *attr_numeric = item->FindAttribute("numeric");
221       std::string numeric = attr_numeric ? attr_numeric->Value() : "";
222       if (numeric == sim_operator_numeric) {
223         break;
224       }
225       item = item->NextSiblingElement("item");
226     }
227     if (item) {
228       std::string names = item->GetText();
229       auto pos = names.find('=');
230       if (pos != std::string::npos) {
231         auto long_name = names.substr(0, pos);
232         auto short_name = names.substr(pos + 1);
233         NetworkOperator sim_operator(sim_operator_numeric, long_name,
234             short_name, NetworkOperator::OPER_STATE_AVAILABLE);
235         operator_list_.insert(operator_list_.begin(), sim_operator);
236       }
237     }
238   }
239   InitializeNetworkOperator();
240 }
241 
SetupDependency(MiscService * misc,SimService * sim,DataService * data)242 void NetworkService::SetupDependency(MiscService* misc, SimService* sim,
243                                      DataService* data) {
244   misc_service_ = misc;
245   sim_service_ = sim;
246   data_service_ = data;
247   InitializeSimOperator();
248 }
249 
OnSimStatusChanged(SimService::SimStatus sim_status)250 void NetworkService::OnSimStatusChanged(SimService::SimStatus sim_status) {
251   if (radio_state_ == RadioState::RADIO_STATE_OFF) {
252     return;  // RegistrationState::NET_REGISTRATION_UNREGISTERED unchanged
253   }
254   if (sim_status == SimService::SIM_STATUS_READY) {
255     voice_registration_status_.registration_state = NET_REGISTRATION_HOME;
256   } else {
257     voice_registration_status_.registration_state = NET_REGISTRATION_EMERGENCY;
258     // 3GPP TS 24.008 [8] and 3GPP TS 24.301 [83] specify the condition
259     // when the MT is considered as attached for emergency bearer services.
260     // applicable only when <AcT> indicates 2,4,5,6
261     // Note: not saved to nvram config due to sim status may change after reboot
262     current_network_mode_ = M_MODEM_TECH_WCDMA;
263   }
264   thread_looper_->Post(
265       makeSafeCallback(this, &NetworkService::UpdateRegisterState,
266                        voice_registration_status_.registration_state),
267       std::chrono::seconds(1));
268 }
269 
270 /**
271  * AT+CFUN
272  *   Set command selects the level of functionality <fun> in the MT. Level
273  * "full functionality" is where the highest level of power is drawn.
274  * "Minimum functionality" is where minimum power is drawn. Level of functionality
275  * between these may also be specified by manufacturers. When supported by
276  * manufacturers, MT resetting with <rst> parameter may be utilized
277  *
278  * Command                Possible response(s)
279  * +CFUN=[<fun>[,<rst>]]    +CME ERROR: <err>
280  * +CFUN?                   +CFUN: <fun>
281  *                          +CME ERROR: <err>
282  *
283  * <fun>: integer type
284  *   0 minimum functionality
285  *   1 full functionality. Enable (turn on) the transmit and receive RF circuits
286  *     for all supported radio access technologies.
287  *   2 disable (turn off) MT transmit RF circuits only
288  *   3 disable (turn off) MT receive RF circuits only
289  *   4 disable (turn off) both MT transmit and receive RF circuits
290  *   5...127 reserved for manufacturers as intermediate states between full
291  *           and minimum functionality
292  *   128 Full functionality with radio access support according to the setting of +CSRA.
293  *   129 Prepare for shutdown.
294  *
295  * see RIL_REQUEST_RADIO_POWER in RIL
296  */
HandleRadioPowerReq(const Client & client)297 void NetworkService::HandleRadioPowerReq(const Client& client) {
298   std::stringstream ss;
299   ss << "+CFUN: " << radio_state_;
300 
301   std::vector<std::string> responses;
302   responses.push_back(ss.str());
303   responses.push_back("OK");
304 
305   client.SendCommandResponse(responses);
306 }
307 
HandleRadioPower(const Client & client,std::string & command)308 void NetworkService::HandleRadioPower(const Client& client, std::string& command) {
309   CommandParser cmd(command);
310   cmd.SkipPrefix();
311   int on = cmd.GetNextInt();
312   switch (on) {
313     case 0:
314       radio_state_ = RadioState::RADIO_STATE_OFF;
315       UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
316       break;
317     case 1:
318       radio_state_ = RadioState::RADIO_STATE_ON;
319       if (sim_service_ != nullptr) {
320         auto sim_status = sim_service_->GetSimStatus();
321         OnSimStatusChanged(sim_status);
322       }
323       break;
324     default:
325       client.SendCommandResponse(kCmeErrorOperationNotSupported);
326       return;
327   }
328 
329   client.SendCommandResponse("OK");
330 }
331 
WakeupFromSleep()332 bool NetworkService::WakeupFromSleep() {
333   // It has not called once yet
334   if (android_last_signal_time_.load() == 0) {
335       return false;
336   }
337   // Heuristics: if guest has not asked for signal strength
338   // for 2 minutes, we assume it is caused by host sleep
339   time_t now = time(0);
340   const bool wakeup_from_sleep = (now > android_last_signal_time_.load() + 120);
341   return wakeup_from_sleep;
342 }
343 
344 /**
345  * IMPORTANT NOTE: Current implementation of AT+CSQ differs from standards
346  * described in TS 27.007 8.5 which only only supports RSSI and BER.
347  *
348  * TODO(b/206814247): Rename AT+CSQ command.
349  *
350  * AT+CSQ
351  *   Execution command returns received signal strength indication. This is a
352  *   Cuttlefish specific command.
353  *
354  * Command            Possible response(s)
355  * AT+CSQ             +CSQ: <gsm_rssi>,<gsm_ber>,<cdma_dbm>,
356  *                      <cdma_ecio>,<evdo_dbm>,<evdo_ecio>,<evdo_snr>,
357  *                      <lte_rssi>,<lte_rsrp>,<lte_rsrq>,<lte_rssnr>,
358  *                      <lte_cqi>,<lte_ta>,<tdscdma_rscp>,<wcdma_rssi>,
359  *                      <wcdma_ber>,<nr_ss_rsrp>,<nr_ss_rsrq>,<nr_ss_sinr>,
360  *                      <nr_csi_rsrp>,<nr_csi_rsrq>,<nr_csi_sinr>
361  *                    +CME ERROR: <err>
362  *
363  * <gsm_rssi>: Valid values are (0-31, 99) as defined in TS 27.007 8.5.
364  * <gsm_ber>: Bit error rate (0-7, 99) as defined in TS 27.007 8.5.
365  * <cdma_dbm>: Valid values are positive integers.
366  *   This value is the actual RSSI value multiplied by -1.
367  *   Example: If the actual RSSI is -75, then this response value will be 75.
368  * <cdma_ecio>: Valid values are positive integers.
369  *   This value is the actual Ec/Io multiplied by -10.
370  *   Example: If the actual Ec/Io is -12.5 dB, then this response value will
371  *   be 125.
372  * <evdo_dbm>: Refer cdma_dbm.
373  * <evdo_ecio>: Refer cdma_ecio.
374  * <evdo_snr>: Valid values are 0-8.
375  *   8 is the highest signal to noise ratio.
376  * <lte_rssi>: Refer gsm_rssi.
377  * <lte_rsrp>:
378  *   The current Reference Signal Receive Power in dBm multiplied by -1.
379  *   Range: 44 to 140 dBm.
380  *   INT_MAX: 0x7FFFFFFF denotes invalid value.
381  *   Reference: 3GPP TS 36.133 9.1.4.
382  * <lte_rsrq>:
383  *   The current Reference Signal Receive Quality in dB multiplied by -1.
384  *   Range: 20 to 3 dB.
385  *   INT_MAX: 0x7FFFFFFF denotes invalid value.
386  *   Reference: 3GPP TS 36.133 9.1.7.
387  * <lte_rssnr>:
388  *   The current reference signal signal-to-noise ratio in 0.1 dB units.
389  *   Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB).
390  *   INT_MAX : 0x7FFFFFFF denotes invalid value.
391  *   Reference: 3GPP TS 36.101 8.1.1.
392  * <lte_cqi>: The current Channel Quality Indicator.
393  *   Range: 0 to 15.
394  *   INT_MAX : 0x7FFFFFFF denotes invalid value.
395  *   Reference: 3GPP TS 36.101 9.2, 9.3, A.4.
396  * <lte_ta>:
397  *   Timing advance in micro seconds for a one way trip from cell to device.
398  *   Approximate distance can be calculated using 300m/us * timingAdvance.
399  *   Range: 0 to 0x7FFFFFFE.
400  *   INT_MAX : 0x7FFFFFFF denotes invalid value.
401  *   Reference: 3GPP 36.321 section 6.1.3.5.
402  * <tdscdma_rscp>: P-CCPCH RSCP as defined in TS 25.225 5.1.1.
403  *   Valid values are (0-96, 255) as defined in TS 27.007 8.69.
404  *   INT_MAX denotes that the value is invalid/unreported.
405  * <wcdma_rssi>: Refer gsm_rssi.
406  * <wcdma_ber>: Refer gsm_ber.
407  * <nr_ss_rsrp>: SS reference signal received power, multiplied by -1.
408  *   Reference: 3GPP TS 38.215.
409  *   Range [44, 140], INT_MAX means invalid/unreported.
410  * <nr_ss_rsrq>: SS reference signal received quality, multiplied by -1.
411  *   Reference: 3GPP TS 38.215.
412  *   Range [3, 20], INT_MAX means invalid/unreported.
413  * <nr_ss_sinr>: SS signal-to-noise and interference ratio.
414  *   Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
415  *   Range [-23, 40], INT_MAX means invalid/unreported.
416  * <nr_csi_rsrp>: CSI reference signal received power, multiplied by -1.
417  *   Reference: 3GPP TS 38.215.
418  *   Range [44, 140], INT_MAX means invalid/unreported.
419  * <nr_csi_rsrq>: CSI reference signal received quality, multiplied by -1.
420  *   Reference: 3GPP TS 38.215.
421  *   Range [3, 20], INT_MAX means invalid/unreported.
422  * <nr_csi_sinr>: CSI signal-to-noise and interference ratio.
423  *   Reference: 3GPP TS 138.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
424  *   Range [-23, 40], INT_MAX means invalid/unreported.
425  *
426  * see RIL_REQUEST_SIGNAL_STRENGTH in RIL
427  */
HandleSignalStrength(const Client & client)428 void NetworkService::HandleSignalStrength(const Client& client) {
429   std::vector<std::string> responses;
430   std::stringstream ss;
431   bool expected = true;
432   if (WakeupFromSleep()) {
433     misc_service_->TimeUpdate();
434   } else if (first_signal_strength_request_.compare_exchange_strong(expected, false)) {
435     misc_service_->TimeUpdate();
436   }
437 
438   android_last_signal_time_ = time(0);
439 
440   auto response = BuildCSQCommandResponse(GetCurrentSignalStrength());
441 
442   responses.push_back(response);
443   responses.push_back("OK");
444   client.SendCommandResponse(responses);
445 }
446 
IsHasNetwork()447 bool NetworkService::IsHasNetwork() {
448   return radio_state_ != RADIO_STATE_OFF &&
449          oper_selection_mode_ !=
450              OperatorSelectionMode::OPER_SELECTION_DEREGISTRATION;
451 }
452 
453 /**
454  * AT+COPS
455  *    Set command forces an attempt to select and register to the
456  *    GSM/UMTS/EPS/5GS network operator using the SIM/USIM card installed
457  *    in the currently selected card slot.
458  *
459  * command                         Possible response(s)
460  * +COPS=[<mode>[,<format>          +CME ERROR: <err>
461  *       [,<oper>[,<AcT>]]]]
462  *
463  * +COPS?                           +COPS: <mode>[,<format>,<oper>[,<AcT>]]
464  *                                  +CME ERROR: <err>
465  *
466  * +COPS=?                          +COPS: [list of supported (<stat>,
467  *                                         long alphanumeric <oper>,
468  *                                         short alphanumeric <oper>,
469  *                                         numeric <oper>[,<AcT>])s]
470  *                                      [,,(list of supported <mode>s),
471  *                                      (list of supported <format>s)]
472  *                                  +CME ERROR: <err>
473  *
474  * <mode>: integer type
475  *       0 automatic (<oper> field is ignored)
476  *       1 manual (<oper> field shall be present, and <AcT> optionally)
477  *       2 deregister from network
478  *       3 set only <format> (for read command +COPS?), do not attempt
479  *       registration/deregistration (<oper> and <AcT> fields are ignored);
480  *        this value is not applicable in read command response
481  *       4 manual/automatic (<oper> field shall be present); if manual selection fails, automatic mode (<mode>=0) is entered
482  * <format>: integer type
483  *         0 long format alphanumeric <oper>
484  *         1 short format alphanumeric <oper>
485  *         2 numeric <oper>
486  * <oper>: string type;
487  * <format> indicates if the format is alphanumeric or numeric;
488  * <stat>: integer type
489  *       0 unknown
490  *       1 available
491  *       2 current
492  *       3 forbidden
493  * <AcT>: integer type; access technology selected
494  *      0 GSM
495  *      1 GSM Compact
496  *      2 UTRAN
497  *      3 GSM w/EGPRS (see NOTE 1)
498  *      4 UTRAN w/HSDPA (see NOTE 2)
499  *      5 UTRAN w/HSUPA (see NOTE 2)
500  *      6 UTRAN w/HSDPA and HSUPA (see NOTE 2)
501  *      7 E-UTRAN
502  *      8 EC-GSM-IoT (A/Gb mode) (see NOTE 3)
503  *      9 E-UTRAN (NB-S1 mode) (see NOTE 4)
504  *      10 E-UTRA connected to a 5GCN (see NOTE 5)
505  *      11 NR connected to a 5GCN (see NOTE 5)
506  *      12 NG-RAN
507  *      13 E-UTRA-NR dual connectivity (see NOTE 6)
508  *
509  *  see RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC or
510  *      RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE or
511  *      RIL_REQUEST_OPERATOR in RIL
512  */
HandleQueryNetworkSelectionMode(const Client & client)513 void NetworkService::HandleQueryNetworkSelectionMode(const Client& client) {
514   std::vector<std::string> responses;
515   std::stringstream ss;
516 
517   if (!IsHasNetwork()) {
518     ss << "+COPS: 0,0,0";
519   } else {
520     auto iter = operator_list_.begin();
521     for (; iter != operator_list_.end(); ++iter) {
522       if (iter->numeric == current_operator_numeric_) {
523         break;
524       }
525     }
526     if (iter != operator_list_.end()) {
527       ss << "+COPS: " << oper_selection_mode_ << ",2," << iter->numeric;
528     } else {
529       ss << "+COPS: " << oper_selection_mode_ << ",0,0";
530     }
531   }
532   responses.push_back(ss.str());
533   responses.push_back("OK");
534   client.SendCommandResponse(responses);
535 }
536 
537 /* AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? */
HandleRequestOperator(const Client & client)538 void NetworkService::HandleRequestOperator(const Client& client) {
539   if (!IsHasNetwork()) {
540     client.SendCommandResponse(kCmeErrorOperationNotAllowed);
541     return;
542   }
543 
544   auto iter = operator_list_.begin();
545   for (; iter != operator_list_.end(); ++iter) {
546     if (iter->numeric == current_operator_numeric_) {
547       break;
548     }
549   }
550   if (iter == operator_list_.end()) {
551     client.SendCommandResponse(kCmeErrorNoNetworkService);
552     return;
553   }
554 
555   std::vector<std::string> responses;
556   std::vector<std::stringstream> ss;
557   ss.resize(3);
558 
559   ss[0] << "+COPS: 0,0," << iter->long_name;
560   ss[1] << "+COPS: 0,1," << iter->short_name;
561   ss[2] << "+COPS: 0,2," << iter->numeric;
562 
563   responses.push_back(ss[0].str());
564   responses.push_back(ss[1].str());
565   responses.push_back(ss[2].str());
566   responses.push_back("OK");
567 
568   client.SendCommandResponse(responses);
569 }
570 
571 /* AT+COPS=? */
HandleQueryAvailableNetwork(const Client & client)572 void NetworkService::HandleQueryAvailableNetwork(const Client& client) {
573   std::vector<std::string> responses;
574   std::stringstream ss;
575 
576   for (auto iter = operator_list_.begin(); iter != operator_list_.end(); ++iter) {
577     ss.clear();
578     ss << "+COPS: (" << iter->operator_state << ","
579                      << iter->long_name << ","
580                      << iter->short_name << ","
581                      << iter->numeric << "),";
582     responses.push_back(ss.str());
583     ss.str("");
584   }
585 
586   responses.push_back("OK");
587   client.SendCommandResponse(responses);
588 }
589 
590 /* AT+COPS=mode,format,operatorNumeric,act */
HandleSetNetworkSelectionMode(const Client & client,std::string & command)591 void NetworkService::HandleSetNetworkSelectionMode(const Client& client, std::string& command) {
592   std::vector<std::string> responses;
593   std::stringstream ss;
594 
595   CommandParser cmd(command);
596   cmd.SkipPrefix();
597 
598   int mode = (OperatorSelectionMode)cmd.GetNextInt();
599   cmd.SkipPrefix();  // Default to be numeric
600 
601   auto& registration_state = voice_registration_status_.registration_state;
602 
603   switch (mode) {
604     // <oper> field is ignored
605     case OperatorSelectionMode::OPER_SELECTION_AUTOMATIC: {
606       oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_AUTOMATIC;
607 
608       // The first operator stored in operator_list_ map default to be
609       // the automatic selected operator
610       auto iter = operator_list_.begin();
611       current_operator_numeric_ = iter->numeric;
612       iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
613 
614       // Change operator state stored in the operator_list_ map
615       ++iter;
616       for (; iter != operator_list_.end(); ++iter) {
617         if (iter->operator_state == NetworkOperator::OPER_STATE_CURRENT) {
618           iter->operator_state = NetworkOperator::OPER_STATE_AVAILABLE;
619           break;
620         }
621       }
622 
623       registration_state = NET_REGISTRATION_HOME;
624       client.SendCommandResponse("OK");
625       break;
626     }
627 
628     // <oper> field shall be present, and <AcT> optionally
629     case OperatorSelectionMode::OPER_SELECTION_MANUAL: {
630       oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_MANUAL;
631       current_operator_numeric_ = cmd.GetNextStr();
632       auto iter = operator_list_.begin();
633       for (; iter != operator_list_.end(); ++iter) {
634         if (iter->numeric == current_operator_numeric_) {
635           break;
636         }
637       }
638       // If the selected operator is not available, no other operator shall be
639       // selected (except <mode>=4).
640       if (iter == operator_list_.end()) {
641         registration_state = NET_REGISTRATION_UNKNOWN;
642         client.SendCommandResponse(kCmeErrorNoNetworkService);
643         break;
644       }
645 
646       // Change operator state stored in the operator_list_ vector
647       iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
648       iter = operator_list_.begin();
649       for (; iter != operator_list_.end(); ++iter) {
650         if (iter->numeric != current_operator_numeric_ &&
651             iter->operator_state == NetworkOperator::OPER_STATE_CURRENT) {
652           iter->operator_state = NetworkOperator::OPER_STATE_AVAILABLE;
653         }
654       }
655 
656       // If the selected access technology is not available, then the same operator
657       // shall be selected in other access technology
658       int act = cmd.GetNextInt();
659       if (act != -1) {
660         auto tech = getTechFromNetworkType((NetworkRegistrationStatus::AccessTechnoloy)act);
661         if (tech & modem_radio_capability_) {
662           current_network_mode_ = tech;
663         }  // else: remain current network mode unchanged
664       }  // else: remain act unchanged
665 
666       if (iter->operator_state == NetworkOperator::OPER_STATE_FORBIDDEN) {
667         registration_state = NET_REGISTRATION_DENIED;
668       } else if (iter->operator_state == NetworkOperator::OPER_STATE_UNKNOWN) {
669         registration_state = NET_REGISTRATION_UNKNOWN;
670       } else {
671         registration_state = NET_REGISTRATION_HOME;
672       }
673       client.SendCommandResponse("OK");
674       break;
675     }
676 
677     case OperatorSelectionMode::OPER_SELECTION_DEREGISTRATION: {
678       oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_DEREGISTRATION;
679       registration_state = NET_REGISTRATION_UNREGISTERED;
680       client.SendCommandResponse("OK");
681       break;
682     }
683 
684     // <oper> field shall be present
685     case OperatorSelectionMode::OPER_SELECTION_MANUAL_AUTOMATIC: {
686       oper_selection_mode_ = OperatorSelectionMode::OPER_SELECTION_MANUAL_AUTOMATIC;
687       auto operator_numeric = cmd.GetNextStr();
688       // If manual selection fails, automatic mode (<mode>=0) is entered
689       auto iter = operator_list_.begin();
690       for (; iter != operator_list_.end(); ++iter) {
691         if (iter->numeric == operator_numeric) {
692           break;
693         }
694       }
695       // If the selected operator is not available, no other operator shall be
696       // selected (except <mode>=4)
697       if (iter != operator_list_.end() ||
698           iter->operator_state == NetworkOperator::OPER_STATE_AVAILABLE) {
699         current_operator_numeric_ = iter->numeric;
700       }
701 
702       // Change operator state stored in the operator_list_ vector
703       iter = operator_list_.begin();
704       for (; iter != operator_list_.end(); ++iter) {
705         if (iter->numeric == current_operator_numeric_) {
706           iter->operator_state = NetworkOperator::OPER_STATE_CURRENT;
707         } else if (iter->operator_state == NetworkOperator::OPER_STATE_CURRENT) {
708           iter->operator_state = NetworkOperator::OPER_STATE_AVAILABLE;
709         }
710       }
711 
712       registration_state = NET_REGISTRATION_HOME;
713       client.SendCommandResponse("OK");
714       break;
715     }
716 
717     default:
718       client.SendCommandResponse(kCmeErrorInCorrectParameters);
719       return;
720   }
721 
722   // Save the value anyway, no matter the value changes or not
723   auto nvram_config = NvramConfig::Get();
724   auto instance = nvram_config->ForInstance(service_id_);
725   instance.set_network_selection_mode(oper_selection_mode_);
726   instance.set_operator_numeric(current_operator_numeric_);
727 
728   NvramConfig::SaveToFile();
729 
730   thread_looper_->Post(
731       makeSafeCallback(this, &NetworkService::UpdateRegisterState,
732                        registration_state),
733       std::chrono::seconds(1));
734 }
735 
736 NetworkService::NetworkRegistrationStatus::AccessTechnoloy
getNetworkTypeFromTech(ModemTechnology modemTech)737 NetworkService::getNetworkTypeFromTech(ModemTechnology modemTech) {
738   switch (modemTech) {
739    case ModemTechnology::M_MODEM_TECH_GSM:
740      return NetworkRegistrationStatus::ACESS_TECH_EGPRS;
741    case ModemTechnology::M_MODEM_TECH_WCDMA:
742      return NetworkRegistrationStatus::ACESS_TECH_HSPA;
743    case ModemTechnology::M_MODEM_TECH_LTE:
744      return NetworkRegistrationStatus::ACESS_TECH_EUTRAN;
745    case ModemTechnology::M_MODEM_TECH_NR:
746      return NetworkRegistrationStatus::ACESS_TECH_NR;
747    default:
748      return NetworkRegistrationStatus::ACESS_TECH_EGPRS;
749   }
750 }
751 
getTechFromNetworkType(NetworkRegistrationStatus::AccessTechnoloy act)752 NetworkService::ModemTechnology NetworkService::getTechFromNetworkType(
753     NetworkRegistrationStatus::AccessTechnoloy act) {
754   switch (act) {
755     case NetworkRegistrationStatus::ACESS_TECH_GSM:
756     case NetworkRegistrationStatus::ACESS_TECH_GSM_COMPACT:
757     case NetworkRegistrationStatus::ACESS_TECH_EGPRS:
758     case NetworkRegistrationStatus::ACESS_TECH_EC_GSM_IoT:
759       return ModemTechnology::M_MODEM_TECH_GSM;
760 
761     case NetworkRegistrationStatus::ACESS_TECH_UTRAN:
762     case NetworkRegistrationStatus::ACESS_TECH_HSDPA:
763     case NetworkRegistrationStatus::ACESS_TECH_HSUPA:
764     case NetworkRegistrationStatus::ACESS_TECH_HSPA:
765       return ModemTechnology::M_MODEM_TECH_WCDMA;
766 
767     case NetworkRegistrationStatus::ACESS_TECH_EUTRAN:
768     case NetworkRegistrationStatus::ACESS_TECH_E_UTRAN:
769     case NetworkRegistrationStatus::ACESS_TECH_E_UTRA:
770       return ModemTechnology::M_MODEM_TECH_LTE;
771 
772     case NetworkRegistrationStatus::ACESS_TECH_NR:
773     case NetworkRegistrationStatus::ACESS_TECH_NG_RAN:
774     case NetworkRegistrationStatus::ACESS_TECH_E_UTRA_NR:
775       return ModemTechnology::M_MODEM_TECH_NR;
776 
777     default:
778       return ModemTechnology::M_MODEM_TECH_GSM;
779   }
780 }
781 
782 /**
783  * AT+CREG
784  *   Set command controls the presentation of an unsolicited result code
785  * +CREG: <stat> when <n>=1 and there is a change in the MT’s circuit
786  * mode network registration status in GERAN/UTRAN/E-UTRAN, or unsolicited
787  * result code +CREG: <stat>[,[<lac>],[<ci>],[<AcT>]]
788  * when <n>=2 and there is a change of the network cell in GERAN/UTRAN/E-UTRAN. The
789  * parameters <AcT>, <lac> and <ci> are sent only if available.
790  * The value <n>=3 further extends the unsolicited result code with [,<cause_type>,
791  * <reject_cause>], when available, when the value of <stat> changes.
792  *
793  * command             Possible response(s)
794  * +CREG=[<n>]         +CME ERROR: <err>
795  *
796  * +CREG?             +CREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>]
797  *                            [,<cause_type>,<reject_cause>]]
798  *
799  * <n>: integer type
800  *    0 disable network registration unsolicited result code
801  *    1 enable network registration unsolicited result code +CREG: <stat>
802  *    2 enable network registration and location information unsolicited
803  *      result code +CREG: <stat>[,[<lac>],[<ci>],[<AcT>]]
804  *    3 enable network registration, location information and cause value
805  *      information unsolicited result code +CREG: <stat>[,[<lac>],[<ci>],
806  *      [<AcT>][,<cause_type>,<reject_cause>]]
807  *
808  * <stat>: integer type;
809  *      0 not registered, MT is not currently searching a new operator to register to
810  *      1 registered, home network
811  *      2 not registered, but MT is currently searching a new operator to register to
812  *      3 registration denied
813  *      4 unknown (e.g. out of GERAN/UTRAN/E-UTRAN coverage)
814  *      5 registered, roaming
815  *
816  * <lac>: string type; two byte location area code (when <AcT> indicates
817  *        value 0 to 6), or tracking area code (when <AcT> indicates
818  *        value 7). In hexadecimal format
819  * <ci>: string type; four byte GERAN/UTRAN/E-UTRAN cell ID in
820  *       hexadecimal format
821  * <AcT>: refer line 190
822  *
823  * see RIL_REQUEST_VOICE_REGISTRATION_STATE or in RIL
824 */
HandleVoiceNetworkRegistration(const Client & client,std::string & command)825 void NetworkService::HandleVoiceNetworkRegistration(const Client& client,
826                                                     std::string& command) {
827   std::vector<std::string> responses;
828   std::stringstream ss;
829 
830   CommandParser cmd(command);
831   cmd.SkipPrefix();
832   if (*cmd == "AT+CREG?") {
833     ss << "+CREG: " << voice_registration_status_.unsol_mode << ","
834                     << voice_registration_status_.registration_state;
835     if (voice_registration_status_.unsol_mode ==
836             NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL &&
837        (voice_registration_status_.registration_state ==
838             NET_REGISTRATION_HOME ||
839         voice_registration_status_.registration_state ==
840             NET_REGISTRATION_ROAMING ||
841         voice_registration_status_.registration_state ==
842             NET_REGISTRATION_EMERGENCY)) {
843       ss << ",\"" << kAreaCode << "\"" << ",\"" << kCellId << "\","
844                   << voice_registration_status_.network_type;
845     }
846 
847     responses.push_back(ss.str());
848   } else {
849     int n = cmd.GetNextInt();
850     switch (n) {
851       case 0:
852         voice_registration_status_.unsol_mode =
853             NetworkRegistrationStatus::REGISTRATION_UNSOL_DISABLED;
854         break;
855       case 1:
856         voice_registration_status_.unsol_mode =
857             NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED;
858         break;
859       case 2:
860         voice_registration_status_.unsol_mode =
861             NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL;
862         break;
863       default:
864         client.SendCommandResponse(kCmeErrorInCorrectParameters);
865         return;
866     }
867   }
868   responses.push_back("OK");
869   client.SendCommandResponse(responses);
870 }
871 
872 /**
873  * AT+CGREG
874  * The set command controls the presentation of an unsolicited result
875  *  code +CGREG: <stat> when <n>=1 and there is a change in the MT's
876  *  GPRS network registration status, or code +CGREG: <stat>[,<lac>,
877  *  <ci>[,<AcT>]] when <n>=2 and there is a change of the network cell.
878  *
879  * command             Possible response(s)
880  * +CGREG=[<n>]         +CME ERROR: <err>
881  *
882  * +CGREG?             when <n>=0, 1, 2 or 3 and command successful:
883  *                     +CGREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>],
884  *                             [<rac>][,<cause_type>,<reject_cause>]]
885  *                     when <n>=4 or 5 and command successful:
886  *                     +CGREG: <n>,<stat>[,[<lac>],[<ci>],[<AcT>],
887  *                             [<rac>][,[<cause_type>],[<reject_cause>][,
888  *                             [<Active-Time>],[<Periodic-RAU>],
889  *                             [<GPRS-READY-timer>]]]]
890  *                             [,<cause_type>,<reject_cause>]]
891  *
892  * note: see AT+CREG
893  *
894  * see  RIL_REQUEST_DATA_REGISTRATION_STATE in RIL
895  */
HandleDataNetworkRegistration(const Client & client,std::string & command)896 void NetworkService::HandleDataNetworkRegistration(const Client& client,
897                                                    std::string& command) {
898   std::vector<std::string> responses;
899   std::stringstream ss;
900   std::string prefix;
901 
902   CommandParser cmd(command);
903   cmd.SkipPrefix();
904   if (command.find("CGREG") != std::string::npos) {
905     prefix = "+CGREG: ";
906   } else if (command.find("CEREG") != std::string::npos){
907     prefix = "+CEREG: ";
908   }
909 
910   if (*cmd == "AT+CGREG?" || *cmd == "AT+CEREG?") {
911     ss << prefix << data_registration_status_.unsol_mode << ","
912                  << data_registration_status_.registration_state;
913     if (voice_registration_status_.unsol_mode ==
914             NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL &&
915        (voice_registration_status_.registration_state ==
916             NET_REGISTRATION_HOME ||
917         voice_registration_status_.registration_state ==
918             NET_REGISTRATION_ROAMING ||
919         voice_registration_status_.registration_state ==
920             NET_REGISTRATION_EMERGENCY)) {
921       data_registration_status_.network_type =
922           getNetworkTypeFromTech(current_network_mode_);
923       ss << ",\"" << kAreaCode << "\"" << ",\"" << kCellId << "\"" << ","
924                   << data_registration_status_.network_type;
925     }
926     responses.push_back(ss.str());
927   } else {
928     int n = cmd.GetNextInt();
929     switch (n) {
930       case 0:
931         data_registration_status_.unsol_mode =
932             NetworkRegistrationStatus::REGISTRATION_UNSOL_DISABLED;
933         break;
934       case 1:
935         data_registration_status_.unsol_mode =
936             NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED;
937         break;
938       case 2:
939         data_registration_status_.unsol_mode =
940             NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL;
941         break;
942       default:
943         client.SendCommandResponse(kCmeErrorInCorrectParameters);
944         return;
945     }
946   }
947   responses.push_back("OK");
948   client.SendCommandResponse(responses);
949 }
950 
951 /* AT+CTEC? */
HandleGetPreferredNetworkType(const Client & client)952 void NetworkService::HandleGetPreferredNetworkType(const Client& client) {
953   std::vector<std::string> responses;
954   std::stringstream ss;
955 
956   ss << "+CTEC: " << current_network_mode_ << "," << std::hex << preferred_network_mode_;
957 
958   responses.push_back(ss.str());
959   responses.push_back("OK");
960   client.SendCommandResponse(responses);
961 }
962 
963 /* AT+CTEC=? */
HandleQuerySupportedTechs(const Client & client)964 void NetworkService::HandleQuerySupportedTechs(const Client& client) {
965   std::vector<std::string> responses;
966   std::stringstream ss;
967   ss << "+CTEC: 0,1,5,6";  // NR | LTE | WCDMA | GSM
968   responses.push_back(ss.str());
969   responses.push_back("OK");
970   client.SendCommandResponse(responses);
971 }
972 
973 /**
974  * Preferred mode bitmask. This is actually 4 byte-sized bitmasks with different priority values,
975  * in which the byte number from LSB to MSB give the priority.
976  *
977  *          |MSB|   |   |LSB
978  * value:   |00 |00 |00 |00
979  * byte #:  |3  |2  |1  |0
980  *
981  * Higher byte order give higher priority. Thus, a value of 0x0000000f represents
982  * a preferred mode of GSM, WCDMA, CDMA, and EvDo in which all are equally preferable, whereas
983  * 0x00000201 represents a mode with GSM and WCDMA, in which WCDMA is preferred over GSM
984  */
getModemTechFromPrefer(int preferred_mask)985 int NetworkService::getModemTechFromPrefer(int preferred_mask) {
986   int i, j;
987 
988   // Current implementation will only return the highest priority,
989   // lowest numbered technology that is set in the mask.
990   for (i = 3; i >= 0; i--) {
991     for (j = 7; j >= 0; j--) {
992       if (preferred_mask & (1 << (j + 8 * i))) {
993         return 1 << j;
994       }
995     }
996   }
997   // This should never happen. Just to please the compiler.
998   return ModemTechnology::M_MODEM_TECH_GSM;
999 }
1000 
UpdateRegisterState(RegistrationState state)1001 void NetworkService::UpdateRegisterState(RegistrationState state ) {
1002   voice_registration_status_.registration_state = state;
1003   data_registration_status_.registration_state = state;
1004   voice_registration_status_.network_type =
1005       (NetworkRegistrationStatus::AccessTechnoloy)getNetworkTypeFromTech(current_network_mode_);
1006   data_registration_status_.network_type =
1007       (NetworkRegistrationStatus::AccessTechnoloy)getNetworkTypeFromTech(current_network_mode_);
1008 
1009   OnVoiceRegisterStateChanged();
1010   OnDataRegisterStateChanged();
1011   OnSignalStrengthChanged();
1012 
1013   int cellBandwidthDownlink = 5000;
1014   const int UNKNOWN = 0;
1015   const int MMWAVE = 4;
1016   int freq = UNKNOWN;
1017   if (current_network_mode_ == M_MODEM_TECH_NR) {
1018     freq = MMWAVE;
1019     cellBandwidthDownlink = 50000;
1020   }
1021 
1022   data_service_->onUpdatePhysicalChannelconfigs(current_network_mode_, freq,
1023                                                 cellBandwidthDownlink);
1024 }
1025 
1026 /* AT+CTEC=current,preferred */
HandleSetPreferredNetworkType(const Client & client,std::string & command)1027 void NetworkService::HandleSetPreferredNetworkType(const Client& client, std::string& command) {
1028   std::vector<std::string> responses;
1029   std::stringstream ss;
1030   int preferred_mask_new;
1031   CommandParser cmd(command);
1032   cmd.SkipPrefix();
1033 
1034   int current = cmd.GetNextInt();
1035   std::string preferred(cmd.GetNextStr());
1036   preferred_mask_new = std::stoi(preferred, nullptr, 16);
1037   if (preferred_mask_new != preferred_network_mode_) {
1038     current_network_mode_ = (ModemTechnology)getModemTechFromPrefer(preferred_mask_new);
1039     preferred_network_mode_ = preferred_mask_new;
1040   }
1041 
1042   if (current != current_network_mode_) {
1043     UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
1044 
1045     ss << "+CTEC: "<< current_network_mode_;
1046 
1047     thread_looper_->Post(
1048         makeSafeCallback(this, &NetworkService::UpdateRegisterState,
1049                          NET_REGISTRATION_HOME),
1050         std::chrono::milliseconds(200));
1051   } else {
1052     ss << "+CTEC: DONE";
1053   }
1054 
1055   auto nvram_config = NvramConfig::Get();
1056   auto instance = nvram_config->ForInstance(service_id_);
1057   instance.set_modem_technoloy(current_network_mode_);
1058   instance.set_preferred_network_mode(preferred_network_mode_);
1059 
1060   NvramConfig::SaveToFile();
1061 
1062   responses.push_back(ss.str());
1063   responses.push_back("OK");
1064   client.SendCommandResponse(responses);
1065 }
1066 
OnVoiceRegisterStateChanged()1067 void NetworkService::OnVoiceRegisterStateChanged() {
1068   std::stringstream ss;
1069 
1070   switch (voice_registration_status_.unsol_mode) {
1071     case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED:
1072       ss << "+CREG: " << voice_registration_status_.registration_state;
1073       break;
1074     case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL:
1075       ss << "+CREG: " << voice_registration_status_.registration_state;
1076       if (voice_registration_status_.registration_state ==
1077               NET_REGISTRATION_HOME ||
1078           voice_registration_status_.registration_state ==
1079               NET_REGISTRATION_ROAMING) {
1080         ss << ",\""<< kAreaCode << "\",\"" << kCellId << "\","
1081                  << voice_registration_status_.network_type;
1082       }
1083       break;
1084     default :
1085       return;
1086   }
1087   SendUnsolicitedCommand(ss.str());
1088 }
1089 
OnDataRegisterStateChanged()1090 void NetworkService::OnDataRegisterStateChanged() {
1091   std::stringstream ss;
1092 
1093   switch (data_registration_status_.unsol_mode) {
1094     case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED:
1095       ss << "+CGREG: " << data_registration_status_.registration_state;
1096       if (data_registration_status_.network_type ==
1097               NetworkRegistrationStatus::ACESS_TECH_EUTRAN) {
1098         ss << "\r+CEREG: " << data_registration_status_.registration_state;
1099       }
1100       break;
1101     case NetworkRegistrationStatus::REGISTRATION_UNSOL_ENABLED_FULL:
1102       ss << "+CGREG: " << data_registration_status_.registration_state;
1103       if (data_registration_status_.registration_state ==
1104                 NET_REGISTRATION_HOME ||
1105           data_registration_status_.registration_state ==
1106                 NET_REGISTRATION_ROAMING) {
1107         ss << ",\"" << kAreaCode << "\",\"" << kCellId << "\","
1108            << data_registration_status_.network_type;
1109       }
1110       if (data_registration_status_.network_type ==
1111                 NetworkRegistrationStatus::ACESS_TECH_EUTRAN) {
1112           ss << "\r+CEREG: " << data_registration_status_.registration_state;
1113           if (data_registration_status_.registration_state ==
1114                   NET_REGISTRATION_HOME ||
1115               data_registration_status_.registration_state ==
1116                   NET_REGISTRATION_ROAMING) {
1117             ss << ",\"" << kAreaCode << "\",\"" << kCellId << "\","
1118                       << data_registration_status_.network_type;
1119           }
1120       }
1121       break;
1122     default:
1123       return;
1124   }
1125   SendUnsolicitedCommand(ss.str());
1126 }
1127 
GetValueInRange(const std::pair<int,int> & range,int percent)1128 int NetworkService::GetValueInRange(const std::pair<int, int>& range,
1129                                     int percent) {
1130   int range_size = range.second - range.first + 1;
1131   return range.first + (int)((percent / 101.0) * range_size);
1132 }
1133 
BuildCSQCommandResponse(const SignalStrength & signal_strength)1134 std::string NetworkService::BuildCSQCommandResponse(
1135     const SignalStrength& signal_strength) {
1136   std::stringstream ss;
1137   // clang-format off
1138   ss << "+CSQ: "
1139      << signal_strength.gsm_rssi << ","
1140      << signal_strength.gsm_ber << ","
1141      << signal_strength.cdma_dbm << ","
1142      << signal_strength.cdma_ecio << ","
1143      << signal_strength.evdo_dbm << ","
1144      << signal_strength.evdo_ecio << ","
1145      << signal_strength.evdo_snr << ","
1146      << signal_strength.lte_rssi << ","
1147      << signal_strength.lte_rsrp << ","
1148      << signal_strength.lte_rsrq << ","
1149      << signal_strength.lte_rssnr << ","
1150      << signal_strength.lte_cqi << ","
1151      << signal_strength.lte_ta << ","
1152      << signal_strength.tdscdma_rscp << ","
1153      << signal_strength.wcdma_rssi << ","
1154      << signal_strength.wcdma_ber << ","
1155      << signal_strength.nr_ss_rsrp << ","
1156      << signal_strength.nr_ss_rsrq << ","
1157      << signal_strength.nr_ss_sinr << ","
1158      << signal_strength.nr_csi_rsrp << ","
1159      << signal_strength.nr_csi_rsrq << ","
1160      << signal_strength.nr_csi_sinr;
1161   // clang-format on
1162   return ss.str();
1163 }
1164 
GetCurrentSignalStrength()1165 NetworkService::SignalStrength NetworkService::GetCurrentSignalStrength() {
1166   NetworkService::SignalStrength result;
1167   if (!IsHasNetwork()) {
1168     return result;
1169   }
1170   int percent = signal_strength_percent_;
1171   switch (current_network_mode_) {
1172     case M_MODEM_TECH_GSM:
1173       result.gsm_rssi = GetValueInRange(kRssiRange, percent);
1174       break;
1175     case M_MODEM_TECH_CDMA:
1176       result.cdma_dbm = GetValueInRange(kDbmRange, percent) * -1;
1177       break;
1178     case M_MODEM_TECH_EVDO:
1179       result.evdo_dbm = GetValueInRange(kDbmRange, percent) * -1;
1180       break;
1181     case M_MODEM_TECH_LTE:
1182       result.lte_rsrp = GetValueInRange(kRsrpRange, percent) * -1;
1183       break;
1184     case M_MODEM_TECH_WCDMA:
1185       result.wcdma_rssi = GetValueInRange(kRssiRange, percent);
1186       break;
1187     case M_MODEM_TECH_NR:
1188       // special for NR: it uses LTE as primary, so LTE signal strength is
1189       // needed as well
1190       result.lte_rsrp = GetValueInRange(kRsrpRange, percent) * -1;
1191       result.nr_ss_rsrp = GetValueInRange(kRsrpRange, percent) * -1;
1192       break;
1193     default:
1194       break;
1195   }
1196   return result;
1197 }
1198 
1199 /* AT+REMOTEREG: state*/
HandleReceiveRemoteVoiceDataReg(const Client & client,std::string & command)1200 void NetworkService::HandleReceiveRemoteVoiceDataReg(const Client& client,
1201                                                      std::string& command) {
1202   (void)client;
1203   std::stringstream ss;
1204   std::string states = command.substr(std::string("AT+REMOTEREG:").size());
1205   int stated = std::stoi(states, nullptr, 10);
1206 
1207   UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
1208 
1209   thread_looper_->Post(
1210       makeSafeCallback(this, &NetworkService::UpdateRegisterState,
1211                        (cuttlefish::NetworkService::RegistrationState)stated),
1212       std::chrono::seconds(1));
1213 }
1214 
1215 /* AT+REMOTECTEC: ctec */
HandleReceiveRemoteCTEC(const Client & client,std::string & command)1216 void NetworkService::HandleReceiveRemoteCTEC(const Client& client,
1217                                              std::string& command) {
1218   (void)client;
1219   LOG(DEBUG) << "calling ctec from remote";
1220   std::stringstream ss;
1221   std::string types = command.substr(std::string("AT+REMOTECTEC: ").size());
1222   int preferred_mask_new = std::stoi(types, nullptr, 10);
1223 
1224   if (preferred_mask_new != preferred_network_mode_) {
1225     preferred_network_mode_ = preferred_mask_new;
1226   }
1227   auto current_network_mode_new =
1228       (ModemTechnology)getModemTechFromPrefer(preferred_mask_new);
1229   if (current_network_mode_new != current_network_mode_) {
1230     current_network_mode_ = current_network_mode_new;
1231     auto saved_state = voice_registration_status_.registration_state;
1232     UpdateRegisterState(NET_REGISTRATION_UNREGISTERED);
1233 
1234     ss << "+CTEC: " << current_network_mode_;
1235 
1236     thread_looper_->Post(
1237         makeSafeCallback(this, &NetworkService::UpdateRegisterState,
1238                          saved_state),
1239         std::chrono::seconds(1));
1240   }
1241 }
1242 
1243 /* AT+REMOTESIGNAL: percent */
HandleReceiveRemoteSignal(const Client & client,std::string & command)1244 void NetworkService::HandleReceiveRemoteSignal(const Client& client,
1245                                                std::string& command) {
1246   (void)client;
1247   std::stringstream ss;
1248   std::string percents = command.substr(std::string("AT+REMOTESIGNAL:").size());
1249   int percent = std::stoi(percents, nullptr, 10);
1250 
1251   if (percent >= 0 && percent <= 100) {
1252     signal_strength_percent_ = percent;
1253   } else {
1254     LOG(DEBUG) << "out of bound signal strength percent: " << percent;
1255     return;
1256   }
1257 
1258   OnSignalStrengthChanged();
1259 }
1260 
HandleIdentifierDisclosure(const std::string & command)1261 void NetworkService::HandleIdentifierDisclosure(const std::string& command) {
1262   LOG(INFO) << "Handling disclosure event: " << command;
1263   SendUnsolicitedCommand(command.substr(2));
1264 }
1265 
HandleSecurityAlgorithmUpdate(const std::string & command)1266 void NetworkService::HandleSecurityAlgorithmUpdate(const std::string& command) {
1267   LOG(INFO) << "Handling security algorithm update event: " << command;
1268   SendUnsolicitedCommand(command.substr(2));
1269 }
1270 
OnSignalStrengthChanged()1271 void NetworkService::OnSignalStrengthChanged() {
1272   SendUnsolicitedCommand(BuildCSQCommandResponse(GetCurrentSignalStrength()));
1273 }
1274 
GetVoiceRegistrationState() const1275 NetworkService::RegistrationState NetworkService::GetVoiceRegistrationState() const {
1276   return voice_registration_status_.registration_state;
1277 }
1278 
KeepSignalStrengthChangingLoop(NetworkService & network_service)1279 NetworkService::KeepSignalStrengthChangingLoop::KeepSignalStrengthChangingLoop(
1280     NetworkService& network_service)
1281     : network_service_{network_service}, loop_started_ ATOMIC_FLAG_INIT {}
1282 
Start()1283 void NetworkService::KeepSignalStrengthChangingLoop::Start() {
1284   if (loop_started_.test_and_set()) {
1285     LOG(ERROR) << "Signal strength is already changing automatically";
1286   } else {
1287     UpdateSignalStrengthCallback();
1288   }
1289 }
1290 
1291 void NetworkService::KeepSignalStrengthChangingLoop::
UpdateSignalStrengthCallback()1292     UpdateSignalStrengthCallback() {
1293   if (network_service_.IsHasNetwork()) {
1294     network_service_.signal_strength_percent_ -= 5;
1295     // With "close to 0" values, the signal strength bar on the Android UI will
1296     // be shown empty, this also represents that theres's no connectivity which
1297     // is misleading as the connectivity continues, so a lower bound of 10 will
1298     // be used so the signal strength bar is never emptied
1299     if (network_service_.signal_strength_percent_ <= 10) {
1300       network_service_.signal_strength_percent_ = 100;
1301     }
1302     network_service_.OnSignalStrengthChanged();
1303   }
1304   network_service_.thread_looper_->Post(
1305       makeSafeCallback(this, &NetworkService::KeepSignalStrengthChangingLoop::
1306                                  UpdateSignalStrengthCallback),
1307       std::chrono::seconds(10));
1308 }
1309 
1310 }  // namespace cuttlefish
1311