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