[go: nahoru, domu]

blob: afda6a757f9f05a3f7ff83ec3f24f8595c8fd536 [file] [log] [blame]
Michal Mazura1744b82023-10-15 09:13:021// Copyright 2023 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos/ash/components/carrier_lock/carrier_lock_manager.h"
6#include "chromeos/ash/components/carrier_lock/carrier_lock.pb.h"
7#include "chromeos/ash/components/carrier_lock/fcm_topic_subscriber_impl.h"
Michal Mazur4f45d142023-10-15 10:25:358#include "chromeos/ash/components/carrier_lock/metrics.h"
Michal Mazura1744b82023-10-15 09:13:029#include "chromeos/ash/components/carrier_lock/provisioning_config_fetcher_impl.h"
10#include "chromeos/ash/components/carrier_lock/psm_claim_verifier_impl.h"
11
12#include "ash/constants/ash_features.h"
13#include "base/base64.h"
14#include "base/files/file_util.h"
15#include "base/logging.h"
Michal Mazur4f45d142023-10-15 10:25:3516#include "base/metrics/histogram_functions.h"
Michal Mazur9678a672023-12-16 12:30:4617#include "base/strings/string_util.h"
Michal Mazura1744b82023-10-15 09:13:0218#include "base/task/single_thread_task_runner.h"
19#include "base/task/task_runner.h"
20#include "chromeos/ash/components/network/device_state.h"
21#include "chromeos/ash/components/network/network_3gpp_handler.h"
Ujjwal Pande57afcbc2023-11-09 18:08:0822#include "chromeos/ash/components/network/network_connect.h"
Michal Mazura1744b82023-10-15 09:13:0223#include "chromeos/ash/components/network/network_device_handler.h"
24#include "chromeos/ash/components/network/network_handler.h"
25#include "chromeos/ash/components/network/network_state_handler.h"
26#include "chromeos/ash/components/system/statistics_provider.h"
27#include "components/prefs/pref_registry_simple.h"
28#include "components/prefs/pref_service.h"
29#include "components/session_manager/core/session_manager.h"
30#include "services/network/public/cpp/shared_url_loader_factory.h"
31
32namespace ash::carrier_lock {
33
34namespace {
35
Michal Mazur6d7f50a2023-11-13 20:47:2936CarrierLockManager* g_instance = nullptr;
37
Michal Mazura1744b82023-10-15 09:13:0238// test configuration
39const char kFcmAppId[] = "com.google.chromeos.carrier_lock";
40const char kFcmSenderId[] = "727210445342";
Michal Mazura1744b82023-10-15 09:13:0241
42// const values
43constexpr base::TimeDelta kFcmTimeout = base::Days(30);
Michal Mazur4f45d142023-10-15 10:25:3544const char kCarrierLockType[] = "network-pin";
Michal Mazura1744b82023-10-15 09:13:0245const char kFirmwareVariantPath[] =
46 "/run/chromeos-config/v1/modem/firmware-variant";
Michal Mazur9678a672023-12-16 12:30:4647const char kManufacturerNamePath[] =
48 "/run/chromeos-config/v1/branding/oem-name";
49const char kModelNamePath[] = "/run/chromeos-config/v1/name";
Michal Mazura1744b82023-10-15 09:13:0250
51// values of feature parameter LastConfigDateDelta
52const int kLastConfigDefault = -2;
53const int kLastConfigSetToday = -1;
54const int kLastConfigKeepDate = 0;
55
56constexpr net::BackoffEntry::Policy kRetryBackoffPolicy = {
57 0, // Number of initial errors before using exponential delay.
Michal Mazur938e67b2024-02-16 19:04:5058 60 * 1000, // Initial delay of 60 seconds in ms.
59 1.2, // Factor by which the waiting time will be multiplied.
Michal Mazura1744b82023-10-15 09:13:0260 0, // Fuzzing percentage.
Michal Mazur938e67b2024-02-16 19:04:5061 30 * 60 * 1000, // Maximum delay of 30 minutes in ms.
Michal Mazura1744b82023-10-15 09:13:0262 -1, // Never discard the entry.
63 false, // Always use initial delay.
64};
65
66constexpr std::string_view ConfigurationStateToStringView(
67 ConfigurationState state) {
68 switch (state) {
69 case ConfigurationState::kNone:
70 return "None";
71 case ConfigurationState::kInitialize:
72 return "Initialize";
73 case ConfigurationState::kPsmCheckClaim:
74 return "Check PSM claim";
75 case ConfigurationState::kFcmGetToken:
76 return "Get FCM token";
77 case ConfigurationState::kRequestConfig:
78 return "Request configuration";
79 case ConfigurationState::kSetupModem:
80 return "Setup modem locks";
81 case ConfigurationState::kFcmCheckTopic:
82 return "Check FCM topic";
83 case ConfigurationState::kFcmSubscribe:
84 return "Subscribe FCM topic";
85 case ConfigurationState::kDeviceUnlocked:
86 return "Device unlocked";
87 case ConfigurationState::kDeviceLocked:
88 return "Device locked";
89 case ConfigurationState::kFatalError:
90 return "Fatal error";
91 }
92}
93
94constexpr std::string_view ResultToStringView(Result result) {
95 switch (result) {
96 case Result::kSuccess:
97 return "Success";
98 case Result::kInvalidSignature:
99 return "Invalid signature in configuration";
100 case Result::kInvalidImei:
101 return "Invalid IMEI in configuration";
102 case Result::kInvalidTimestamp:
103 return "Invalid timestamp in configuration";
104 case Result::kNetworkListTooLarge:
105 return "Configuration network list too large";
106 case Result::kAlgorithmNotSupported:
107 return "Configuration algorithm not supported";
108 case Result::kFeatureNotSupported:
109 return "Configuration feature not supported";
110 case Result::kDecodeOrParsingError:
111 return "Configuration decode or parsing error";
112 case Result::kHandlerNotInitialized:
113 return "Modem handler not initialized";
114 case Result::kOperationNotSupported:
115 return "Modem operation not supported";
116 case Result::kModemInternalError:
117 return "Modem internal error";
118 case Result::kInvalidNetworkHandler:
119 return "Network handler not initialized";
120 case Result::kInvalidModemHandler:
121 return "Modem 3gpp handler not initialized";
122 case Result::kInvalidAuxHandlers:
123 return "Auxiliary classes not initialized";
124 case Result::kModemNotFound:
125 return "Modem not found or invalid";
126 case Result::kSerialProviderFailed:
127 return "Failed to get serial number";
128 case Result::kHandlerBusy:
129 return "Handler busy";
130 case Result::kRequestFailed:
131 return "Request failed";
132 case Result::kInitializationFailed:
133 return "Initialization failed";
134 case Result::kConnectionError:
135 return "Connection error";
136 case Result::kInvalidInput:
137 return "Invalid input parameters";
138 case Result::kServerInternalError:
139 return "Server internal error";
140 case Result::kInvalidResponse:
141 return "Invalid response from server";
142 case Result::kCreatePsmClientFailed:
143 return "Failed to create PSM client";
144 case Result::kCreateOprfRequestFailed:
145 return "Failed to create OPRF request";
146 case Result::kInvalidOprfReply:
147 return "Invalid reply to OPRF request";
148 case Result::kCreateQueryRequestFailed:
149 return "Failed to create Query request";
150 case Result::kInvalidQueryReply:
151 return "Invalid reply to Query request";
152 case Result::kNoLockConfiguration:
153 return "Lock configuration not found";
154 case Result::kInvalidConfiguration:
155 return "Lock configuration invalid";
156 case Result::kLockedWithoutTopic:
157 return "Locked configuration without topic";
158 case Result::kEmptySignedConfiguration:
159 return "Signed configuration not provided";
160 }
161}
162
163constexpr Result CarrierLockResultToResult(CarrierLockResult result) {
164 switch (result) {
165 case CarrierLockResult::kSuccess:
166 return Result::kSuccess;
167 case CarrierLockResult::kUnknownError:
168 return Result::kModemInternalError;
169 case CarrierLockResult::kInvalidSignature:
170 return Result::kInvalidSignature;
171 case CarrierLockResult::kInvalidImei:
172 return Result::kInvalidImei;
173 case CarrierLockResult::kInvalidTimeStamp:
174 return Result::kInvalidTimestamp;
175 case CarrierLockResult::kNetworkListTooLarge:
176 return Result::kNetworkListTooLarge;
177 case CarrierLockResult::kAlgorithmNotSupported:
178 return Result::kAlgorithmNotSupported;
179 case CarrierLockResult::kFeatureNotSupported:
180 return Result::kFeatureNotSupported;
181 case CarrierLockResult::kDecodeOrParsingError:
182 return Result::kDecodeOrParsingError;
183 case CarrierLockResult::kNotInitialized:
184 return Result::kHandlerNotInitialized;
185 case CarrierLockResult::kOperationNotSupported:
186 return Result::kOperationNotSupported;
187 }
188}
189
190} // namespace
191
192// static
193std::unique_ptr<CarrierLockManager> CarrierLockManager::Create(
194 PrefService* local_state,
195 gcm::GCMDriver* gcm_driver,
196 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
197 DCHECK(local_state);
198 std::unique_ptr<CarrierLockManager> manager =
199 std::make_unique<CarrierLockManager>(local_state);
200
201 if (NetworkHandler::IsInitialized()) {
202 NetworkHandler* network_handler = NetworkHandler::Get();
203 manager->network_state_handler_ = network_handler->network_state_handler();
204 manager->modem_handler_ = network_handler->network_3gpp_handler();
205 }
206 manager->config_ =
207 std::make_unique<ProvisioningConfigFetcherImpl>(url_loader_factory);
208 manager->psm_ = std::make_unique<PsmClaimVerifierImpl>(url_loader_factory);
209 manager->fcm_ = std::make_unique<FcmTopicSubscriberImpl>(
210 gcm_driver, kFcmAppId, kFcmSenderId, url_loader_factory);
211
212 manager->Initialize();
213
Michal Mazur6d7f50a2023-11-13 20:47:29214 g_instance = manager.get();
Michal Mazura1744b82023-10-15 09:13:02215 return manager;
216}
217
218// static
219std::unique_ptr<CarrierLockManager> CarrierLockManager::CreateForTesting(
220 PrefService* local_state,
221 Network3gppHandler* network_3gpp_handler,
222 std::unique_ptr<FcmTopicSubscriber> fcm_topic_subscriber,
223 std::unique_ptr<PsmClaimVerifier> psm_claim_verifier,
224 std::unique_ptr<ProvisioningConfigFetcher> provisioning_config_fetcher) {
225 DCHECK(local_state);
226 std::unique_ptr<CarrierLockManager> manager =
227 std::make_unique<CarrierLockManager>(local_state);
228
229 manager->network_state_handler_ = nullptr;
230 manager->modem_handler_ = network_3gpp_handler;
231 manager->config_ = std::move(provisioning_config_fetcher);
232 manager->psm_ = std::move(psm_claim_verifier);
233 manager->fcm_ = std::move(fcm_topic_subscriber);
Michal Mazur9678a672023-12-16 12:30:46234 manager->manufacturer_ = "Google";
235 manager->model_ = "Pixel 20";
Michal Mazura1744b82023-10-15 09:13:02236
237 // Start with PSM check.
238 manager->RunStep(ConfigurationState::kPsmCheckClaim);
239
Michal Mazur6d7f50a2023-11-13 20:47:29240 g_instance = manager.get();
Michal Mazura1744b82023-10-15 09:13:02241 return manager;
242}
243
244// static
245void CarrierLockManager::RegisterLocalPrefs(PrefRegistrySimple* registry) {
246 registry->RegisterBooleanPref(kDisableManagerPref, false);
247 registry->RegisterIntegerPref(kErrorCounterPref, 0);
248 registry->RegisterStringPref(kFcmTopicPref, std::string());
249 registry->RegisterTimePref(kLastConfigTimePref, base::Time());
250 registry->RegisterStringPref(kLastImeiPref, std::string());
251 registry->RegisterStringPref(kSignedConfigPref, std::string());
252}
253
Michal Mazur6d7f50a2023-11-13 20:47:29254// static
Michal Mazura1744b82023-10-15 09:13:02255ModemLockStatus CarrierLockManager::GetModemLockStatus() {
256 if (!ash::features::IsCellularCarrierLockEnabled()) {
257 return ModemLockStatus::kNotLocked;
258 }
Michal Mazur6d7f50a2023-11-13 20:47:29259 if (!g_instance || !g_instance->local_state_) {
Michal Mazura1744b82023-10-15 09:13:02260 return ModemLockStatus::kUnknown;
261 }
Michal Mazur6d7f50a2023-11-13 20:47:29262 if (g_instance->local_state_->GetBoolean(kDisableManagerPref)) {
Michal Mazura1744b82023-10-15 09:13:02263 return ModemLockStatus::kNotLocked;
264 }
Michal Mazur6d7f50a2023-11-13 20:47:29265 if (!g_instance->local_state_->GetString(kFcmTopicPref).empty()) {
Michal Mazura1744b82023-10-15 09:13:02266 return ModemLockStatus::kCarrierLocked;
267 }
268 return ModemLockStatus::kUnknown;
269}
270
271CarrierLockManager::CarrierLockManager(PrefService* local_state)
272 : local_state_(local_state), retry_backoff_(&kRetryBackoffPolicy) {}
273
274CarrierLockManager::~CarrierLockManager() {
Michal Mazur6d7f50a2023-11-13 20:47:29275 g_instance = nullptr;
Michal Mazura1744b82023-10-15 09:13:02276 if (session_manager_) {
277 session_manager_->RemoveObserver(this);
278 }
279 if (network_state_handler_ && network_state_handler_->HasObserver(this)) {
280 network_state_handler_->RemoveObserver(this, FROM_HERE);
281 }
282 if (local_state_) {
283 local_state_->SetInteger(kErrorCounterPref, error_counter_);
284 }
285}
286
287void CarrierLockManager::OnSessionStateChanged() {
288 if (!session_manager_) {
289 return;
290 }
291
292 session_manager::SessionState session_state =
293 session_manager_->session_state();
294 if (session_state <= session_manager::SessionState::OOBE) {
295 // Wait for end of the OOBE.
296 return;
297 }
298
299 // Once the OOBE is over, disable observer and wait for network connectivity.
300 session_manager_->RemoveObserver(this);
301 session_manager_ = nullptr;
Michal Mazure90c1aea2024-01-25 20:41:26302 network_state_handler_->AddObserver(this, FROM_HERE);
Michal Mazura1744b82023-10-15 09:13:02303 DefaultNetworkChanged(nullptr);
304}
305
306void CarrierLockManager::Initialize() {
307 const int last_config = features::kCellularCarrierLockLastConfig.Get();
308
309 if (last_config > kLastConfigDefault) {
310 VLOG(2) << "Last config option is set to " << last_config;
311 if (last_config == kLastConfigSetToday) {
312 local_state_->SetTime(kLastConfigTimePref, base::Time());
313 }
314 if (last_config > kLastConfigKeepDate) {
315 local_state_->SetTime(kLastConfigTimePref,
316 base::Time::Now() - base::Days(last_config));
317 }
318 local_state_->SetBoolean(kDisableManagerPref, false);
319 }
320
321 configuration_state_ = ConfigurationState::kNone;
322 error_counter_ = local_state_->GetInteger(kErrorCounterPref);
Michal Mazura1744b82023-10-15 09:13:02323
324 // Check Disable flag.
325 if (local_state_->GetBoolean(kDisableManagerPref)) {
326 VLOG(2) << "Manager is Disabled by local flag!";
327 return;
328 }
329
330 // Check for cellular modem and disable Manager if not needed.
331 const base::FilePath modem_path = base::FilePath(kFirmwareVariantPath);
332 if (!base::PathExists(modem_path)) {
333 local_state_->SetBoolean(kDisableManagerPref, true);
334 VLOG(2) << "No modem found. Manager will be disabled.";
335 return;
336 }
337
338 // Check handlers.
339 if (!network_state_handler_) {
340 LOG(ERROR) << "NetworkStateHandler is not initialized.";
341 LogError(Result::kInvalidNetworkHandler);
342 RunStep(ConfigurationState::kFatalError);
343 return;
344 }
345
346 if (!modem_handler_) {
347 LOG(ERROR) << "Network3gppHandler is not initialized.";
348 LogError(Result::kInvalidModemHandler);
349 RunStep(ConfigurationState::kFatalError);
350 return;
351 }
352
353 if (!fcm_ || !psm_ || !config_) {
354 LOG(ERROR) << "Failed to create auxiliary classes.";
355 LogError(Result::kInvalidAuxHandlers);
356 RunStep(ConfigurationState::kFatalError);
357 return;
358 }
359
Michal Mazur9678a672023-12-16 12:30:46360 // Load manufacturer and model.
361 const base::FilePath oem_path(kManufacturerNamePath);
362 if (base::PathExists(oem_path)) {
363 base::File file(oem_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
364 int64_t length = file.GetLength();
365 std::unique_ptr<char[]> buffer(new char[length + 1]);
366 file.Read(0, buffer.get(), length);
367 buffer[length] = '\0';
368 manufacturer_ = buffer.get();
369 } else {
370 LOG(ERROR) << "Manufacturer name file doesn't exist!";
371 }
372
373 const base::FilePath model_path(kModelNamePath);
374 if (base::PathExists(model_path)) {
375 base::File file(model_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
376 int64_t length = file.GetLength();
377 std::unique_ptr<char[]> buffer(new char[length + 1]);
378 file.Read(0, buffer.get(), length);
379 buffer[length] = '\0';
380 model_ = buffer.get();
381 } else {
382 LOG(ERROR) << "Model name file doesn't exist!";
383 }
384
Michal Mazura1744b82023-10-15 09:13:02385 DCHECK(base::SingleThreadTaskRunner::HasCurrentDefault());
386 retry_backoff_.Reset();
387
388 if (!session_manager_) {
389 session_manager_ = session_manager::SessionManager::Get();
390 session_manager_->AddObserver(this);
391 }
392 OnSessionStateChanged();
393}
394
395void CarrierLockManager::DefaultNetworkChanged(const NetworkState* network) {
Michal Mazura1744b82023-10-15 09:13:02396 if (retry_backoff_.ShouldRejectRequest()) {
397 // Ignore this event.
398 VLOG(2) << "Change of default network skipped because of backoff timer.";
399 return;
400 }
Michal Mazura1744b82023-10-15 09:13:02401 if (configuration_state_ >= ConfigurationState::kDeviceLocked) {
402 // Modem configuration is complete.
Michal Mazura1744b82023-10-15 09:13:02403 return;
404 }
405
406 if (!network) {
407 network = network_state_handler_->DefaultNetwork();
408 }
Michal Mazur938e67b2024-02-16 19:04:50409 if (!network || !network->IsConnectedState()) {
410 VLOG(2) << "No network connectivity.";
411 return;
412 }
Michal Mazura1744b82023-10-15 09:13:02413
Michal Mazur938e67b2024-02-16 19:04:50414 if (configuration_state_ == ConfigurationState::kNone) {
Michal Mazura1744b82023-10-15 09:13:02415 // Ready to start configuration process.
Michal Mazure90c1aea2024-01-25 20:41:26416 configuration_state_ = ConfigurationState::kInitialize;
Michal Mazura1744b82023-10-15 09:13:02417 RunStep(configuration_state_);
418 return;
419 }
420
421 retry_backoff_.InformOfRequest(/*succeeded=*/false);
Michal Mazur938e67b2024-02-16 19:04:50422 VLOG(2) << "Network connection was interrupted. Restart setup in "
423 << retry_backoff_.GetTimeUntilRelease().InSeconds() << " seconds.";
Michal Mazura1744b82023-10-15 09:13:02424
Michal Mazur938e67b2024-02-16 19:04:50425 // Call this function after delay to check if configuration process
426 // failed and restart it from initial step.
Michal Mazura1744b82023-10-15 09:13:02427 base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
428 FROM_HERE,
429 base::BindOnce(&CarrierLockManager::DefaultNetworkChanged,
430 weak_ptr_factory_.GetWeakPtr(), nullptr),
431 retry_backoff_.GetTimeUntilRelease());
432}
433
Michal Mazur4f45d142023-10-15 10:25:35434void CarrierLockManager::DevicePropertiesUpdated(const DeviceState* device) {
435 if (device->type() != shill::kTypeCellular) {
436 return;
437 }
438 const std::string lock_type = device->sim_lock_type();
439 if (!lock_type.empty() && lock_type != kCarrierLockType) {
440 // SIM card locked, state of carrier lock is unknown.
441 return;
442 }
443
444 bool is_manager_enabled = (ash::features::IsCellularCarrierLockEnabled() &&
445 !local_state_->GetBoolean(kDisableManagerPref));
446 bool is_modem_configured =
Michal Mazur938e67b2024-02-16 19:04:50447 !local_state_->GetTime(kLastConfigTimePref).is_null();
Michal Mazur4f45d142023-10-15 10:25:35448
449 if (is_manager_enabled) {
450 if (!is_modem_configured) {
451 // Configuration is in progress.
452 base::UmaHistogramEnumeration(kLockState, LockState::kNotConfigured);
453 } else if (lock_type.empty()) {
454 // Modem is carrier-locked and SIM is allowed.
455 base::UmaHistogramEnumeration(kLockState, LockState::kCompatibleSim);
456 } else {
457 // Modem is carrier-locked and SIM is blocked.
458 base::UmaHistogramEnumeration(kLockState, LockState::kIncompatibleSim);
459 }
460 } else if (lock_type.empty()) {
461 if (is_modem_configured) {
462 // Modem was locked and unlocked properly.
463 base::UmaHistogramEnumeration(kLockState, LockState::kProperlyUnlocked);
464 }
465 } else {
466 // Modem is locked but manager is already disabled (invalid state).
467 base::UmaHistogramEnumeration(kLockState, LockState::kIncorrectlyLocked);
468 }
469}
470
Michal Mazura1744b82023-10-15 09:13:02471void CarrierLockManager::RunStep(ConfigurationState state) {
472 VLOG(2) << "Run step " << ConfigurationStateToStringView(state);
473
474 switch (state) {
475 case ConfigurationState::kInitialize:
476 function_ = &CarrierLockManager::CheckState;
477 break;
478 case ConfigurationState::kPsmCheckClaim:
479 function_ = &CarrierLockManager::CheckPsmClaim;
480 break;
481 case ConfigurationState::kFcmGetToken:
482 function_ = &CarrierLockManager::GetFcmToken;
483 break;
484 case ConfigurationState::kRequestConfig:
485 function_ = &CarrierLockManager::RequestConfig;
486 break;
487 case ConfigurationState::kSetupModem:
488 function_ = &CarrierLockManager::SetupModem;
489 break;
490 case ConfigurationState::kFcmCheckTopic:
491 function_ = &CarrierLockManager::CheckFcmTopic;
492 break;
493 case ConfigurationState::kFcmSubscribe:
494 function_ = &CarrierLockManager::SubscribeFcmTopic;
495 break;
496 case ConfigurationState::kDeviceUnlocked:
497 local_state_->SetBoolean(kDisableManagerPref, true);
498 // DevMode will be unlocked during next OOBE based on PSM status.
499 [[fallthrough]];
500 case ConfigurationState::kDeviceLocked:
501 error_counter_ = 0;
502 // Nothing to do, wait for FCM notification.
503 [[fallthrough]];
504 case ConfigurationState::kFatalError:
505 function_ = nullptr;
506 break;
507 case ConfigurationState::kNone:
508 return;
509 }
510 configuration_state_ = state;
511 remaining_retries_ = kMaxRetries;
512
513 if (function_) {
514 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
515 FROM_HERE, base::BindOnce(function_, weak_ptr_factory_.GetWeakPtr()));
516 }
517}
518
519bool CarrierLockManager::RetryStep() {
520 if (!function_) {
521 return false;
522 }
523
524 if (remaining_retries_ <= 0) {
525 LOG(ERROR) << "Step "
526 << ConfigurationStateToStringView(configuration_state_)
527 << " failed " << (kMaxRetries + 1) << " times. Exiting...";
528 // Wait for new connection and retry...
Michal Mazure90c1aea2024-01-25 20:41:26529 configuration_state_ = ConfigurationState::kNone;
Michal Mazura1744b82023-10-15 09:13:02530 return false;
531 }
532 remaining_retries_--;
533
534 VLOG(2) << "Step " << ConfigurationStateToStringView(configuration_state_)
535 << " failed, trying again...";
536
537 // Retry current configuration step after delay.
538 base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
539 FROM_HERE, base::BindOnce(function_, weak_ptr_factory_.GetWeakPtr()),
540 kRetryDelay);
541 return true;
542}
543
544void CarrierLockManager::LogError(Result result) {
545 VLOG(2) << "Step " << ConfigurationStateToStringView(configuration_state_)
546 << " returned error " << ResultToStringView(result);
547
Michal Mazur4f45d142023-10-15 10:25:35548 switch (configuration_state_) {
549 case ConfigurationState::kNone:
550 case ConfigurationState::kInitialize:
551 base::UmaHistogramEnumeration(kErrorManagerInitialization, result);
552 break;
553 case ConfigurationState::kPsmCheckClaim:
554 base::UmaHistogramEnumeration(kErrorPsmClaim, result);
555 break;
556 case ConfigurationState::kFcmGetToken:
557 case ConfigurationState::kFcmSubscribe:
558 base::UmaHistogramEnumeration(kErrorFcmTopic, result);
559 break;
560 case ConfigurationState::kRequestConfig:
561 base::UmaHistogramEnumeration(kErrorProvisioning, result);
562 break;
563 case ConfigurationState::kSetupModem:
564 base::UmaHistogramEnumeration(kErrorModemSetup, result);
565 break;
566 default:
567 break;
568 }
569
Michal Mazura1744b82023-10-15 09:13:02570 local_state_->SetInteger(kErrorCounterPref, ++error_counter_);
Michal Mazur4f45d142023-10-15 10:25:35571 if (error_counter_ && !(error_counter_ % 10)) {
Michal Mazur938e67b2024-02-16 19:04:50572 base::UmaHistogramCounts1M(kNumConsecutiveConfigurationFailures,
573 error_counter_);
Michal Mazur4f45d142023-10-15 10:25:35574 }
Michal Mazura1744b82023-10-15 09:13:02575}
576
577void CarrierLockManager::CheckState() {
578 system::StatisticsProvider* statistics;
579 const DeviceState* cellular_device =
580 network_state_handler_->GetDeviceStateByType(
581 ash::NetworkTypePattern::Cellular());
582 if (cellular_device) {
583 imei_ = cellular_device->imei();
584 }
585 if (!cellular_device || imei_.empty()) {
586 LOG(ERROR) << "Cellular device not found or invalid.";
587 LogError(Result::kModemNotFound);
588 RetryStep();
589 return;
590 }
591
592 if (serial_.empty()) {
593 statistics = system::StatisticsProvider::GetInstance();
594 if (!statistics) {
595 LOG(ERROR) << "StatisticsProvider is not initialized.";
596 LogError(Result::kSerialProviderFailed);
597 RetryStep();
598 return;
599 }
600
601 serial_ = statistics->GetMachineID().value_or(std::string());
602 if (serial_.empty()) {
603 LOG(ERROR) << "Failed to read Serial number";
604 LogError(Result::kSerialProviderFailed);
605 RetryStep();
606 return;
607 }
608 }
609
Michal Mazur938e67b2024-02-16 19:04:50610 // First configuration, check PSM claim.
Michal Mazura1744b82023-10-15 09:13:02611 base::Time last_config = local_state_->GetTime(kLastConfigTimePref);
612 if (last_config.is_null()) {
Michal Mazur4f45d142023-10-15 10:25:35613 base::UmaHistogramEnumeration(kConfigurationStateAfterInitialization,
614 InitialState::kFirstConfiguration);
Michal Mazura1744b82023-10-15 09:13:02615 is_first_setup_ = true;
616 RunStep(ConfigurationState::kPsmCheckClaim);
617 return;
618 }
619
Michal Mazur938e67b2024-02-16 19:04:50620 // Configuration older than 30 days, get FCM token and new configuration.
Michal Mazura1744b82023-10-15 09:13:02621 if (base::Time::Now() - last_config >= kFcmTimeout) {
Michal Mazur4f45d142023-10-15 10:25:35622 base::UmaHistogramEnumeration(kConfigurationStateAfterInitialization,
623 InitialState::kObsoleteConfiguration);
Michal Mazura1744b82023-10-15 09:13:02624 is_first_setup_ = false;
625 RunStep(ConfigurationState::kFcmGetToken);
626 return;
627 }
628
Michal Mazur938e67b2024-02-16 19:04:50629 // Apply stored configuration if possible or request new token and config.
Michal Mazura1744b82023-10-15 09:13:02630 std::string last_imei = local_state_->GetString(kLastImeiPref);
631 std::string signed_config = local_state_->GetString(kSignedConfigPref);
632 std::string fcm_topic = local_state_->GetString(kFcmTopicPref);
633 if ((imei_ == last_imei) && !signed_config.empty() && !fcm_topic.empty()) {
Michal Mazur4f45d142023-10-15 10:25:35634 base::UmaHistogramEnumeration(kConfigurationStateAfterInitialization,
635 InitialState::kAlreadyConfigured);
Michal Mazura1744b82023-10-15 09:13:02636 is_first_setup_ = false;
637 RunStep(ConfigurationState::kSetupModem);
638 } else {
639 is_first_setup_ = (imei_ != last_imei);
Michal Mazur4f45d142023-10-15 10:25:35640 base::UmaHistogramEnumeration(
641 kConfigurationStateAfterInitialization,
642 (is_first_setup_ ? InitialState::kModemImeiChanged
643 : InitialState::kEmptySignedConfig));
Michal Mazura1744b82023-10-15 09:13:02644 RunStep(ConfigurationState::kFcmGetToken);
645 }
646}
647
648void CarrierLockManager::CheckPsmClaim() {
Michal Mazur9678a672023-12-16 12:30:46649 psm_->CheckPsmClaim(serial_, base::ToLowerASCII(manufacturer_),
650 base::ToLowerASCII(model_),
Michal Mazura1744b82023-10-15 09:13:02651 base::BindOnce(&CarrierLockManager::PsmCallback,
652 weak_ptr_factory_.GetWeakPtr()));
653}
654
655void CarrierLockManager::PsmCallback(Result result) {
656 if (result != Result::kSuccess) {
657 LogError(result);
Michal Mazur9678a672023-12-16 12:30:46658 if (result != Result::kHandlerBusy) {
Michal Mazura1744b82023-10-15 09:13:02659 RetryStep();
Michal Mazura1744b82023-10-15 09:13:02660 }
Michal Mazur9678a672023-12-16 12:30:46661 return;
Michal Mazura1744b82023-10-15 09:13:02662 }
663
Michal Mazur9678a672023-12-16 12:30:46664 if (psm_->GetMembership()) {
Michal Mazur4f45d142023-10-15 10:25:35665 base::UmaHistogramEnumeration(kPsmClaimResponse, PsmResult::kDeviceLocked);
Michal Mazura1744b82023-10-15 09:13:02666 RunStep(ConfigurationState::kFcmGetToken);
667 } else {
Michal Mazur9678a672023-12-16 12:30:46668 VLOG(2) << "Not a member in PSM group, manager will be disabled.";
Michal Mazur4f45d142023-10-15 10:25:35669 base::UmaHistogramEnumeration(kPsmClaimResponse,
670 PsmResult::kDeviceUnlocked);
Michal Mazura1744b82023-10-15 09:13:02671 RunStep(ConfigurationState::kDeviceUnlocked);
672 }
673}
674
675void CarrierLockManager::RequestConfig() {
Michal Mazur9678a672023-12-16 12:30:46676 config_->RequestConfig(serial_, imei_, manufacturer_, model_, fcm_token_,
Michal Mazura1744b82023-10-15 09:13:02677 base::BindOnce(&CarrierLockManager::ConfigCallback,
678 weak_ptr_factory_.GetWeakPtr()));
679}
680
681void CarrierLockManager::ConfigCallback(Result result) {
682 if (result != Result::kSuccess) {
683 LogError(result);
684 if (result != Result::kHandlerBusy) {
685 RetryStep();
686 }
687 return;
688 }
689
690 RestrictedNetworks networks = config_->GetNumberOfNetworks();
Michal Mazur9678a672023-12-16 12:30:46691 bool is_config_unlocked = !networks.allowed && !networks.disallowed;
Michal Mazur4f45d142023-10-15 10:25:35692 if (config_->GetFcmTopic().empty()) {
693 // Unlocked or Invalid configuration.
694 base::UmaHistogramEnumeration(kProvisioningServerResponse,
695 is_config_unlocked
696 ? ProvisioningResult::kConfigUnlocked
697 : ProvisioningResult::kConfigInvalid);
698 if (!is_config_unlocked) {
699 // Invalid config (locked but without fcm topic).
700 LogError(Result::kLockedWithoutTopic);
701 RetryStep();
702 return;
703 }
704 } else {
705 // Locked or Temporarily unlocked configuration.
706 base::UmaHistogramEnumeration(kProvisioningServerResponse,
707 is_config_unlocked
708 ? ProvisioningResult::kConfigTempUnlocked
709 : ProvisioningResult::kConfigLocked);
Michal Mazura1744b82023-10-15 09:13:02710 }
711
712 // Check signed configuration and store it.
713 if (config_->GetSignedConfig().empty()) {
714 LogError(Result::kEmptySignedConfiguration);
715 RetryStep();
716 return;
717 }
Tom Sepez801251c42024-01-29 21:01:35718 std::string signed_config = base::Base64Encode(config_->GetSignedConfig());
Michal Mazura1744b82023-10-15 09:13:02719 local_state_->SetString(kSignedConfigPref, signed_config);
Michal Mazur938e67b2024-02-16 19:04:50720
721 if (!local_state_->GetString(kFcmTopicPref).empty() &&
722 config_->GetFcmTopic().empty()) {
723 NetworkConnect::Get()->ShowCarrierUnlockNotification();
724 }
725
726 // Save current time, modem imei and fcm topic.
Michal Mazura1744b82023-10-15 09:13:02727 local_state_->SetString(kFcmTopicPref, config_->GetFcmTopic());
Michal Mazur938e67b2024-02-16 19:04:50728 local_state_->SetTime(kLastConfigTimePref, base::Time::Now());
729 local_state_->SetString(kLastImeiPref, imei_);
Michal Mazura1744b82023-10-15 09:13:02730
731 RunStep(ConfigurationState::kSetupModem);
732}
733
734void CarrierLockManager::SetupModem() {
735 std::string signed_config;
736 base::Base64Decode(local_state_->GetString(kSignedConfigPref),
737 &signed_config);
738
Michal Mazur938e67b2024-02-16 19:04:50739 // Make sure the manager is enabled before locking the modem.
740 if (!local_state_->GetString(kFcmTopicPref).empty() &&
741 local_state_->GetBoolean(kDisableManagerPref)) {
742 local_state_->SetBoolean(kDisableManagerPref, false);
743 }
744
Michal Mazura1744b82023-10-15 09:13:02745 modem_handler_->SetCarrierLock(
746 signed_config, base::BindOnce(&CarrierLockManager::SetupModemCallback,
747 weak_ptr_factory_.GetWeakPtr()));
748}
749
750void CarrierLockManager::SetupModemCallback(CarrierLockResult result) {
751 if (result != CarrierLockResult::kSuccess) {
752 LogError(CarrierLockResultToResult(result));
753 RetryStep();
754 return;
755 }
756
Michal Mazur4f45d142023-10-15 10:25:35757 if (local_state_->GetString(kFcmTopicPref).empty()) {
758 // Configuration not locked.
759 base::UmaHistogramEnumeration(kModemConfigurationResult,
760 is_first_setup_
761 ? ConfigurationResult::kModemNotLocked
762 : ConfigurationResult::kModemUnlocked);
763 } else {
764 // Configuration carrier-locked.
765 base::UmaHistogramEnumeration(kModemConfigurationResult,
766 is_first_setup_
767 ? ConfigurationResult::kModemLocked
768 : ConfigurationResult::kModemRelocked);
769 }
Michal Mazura1744b82023-10-15 09:13:02770 is_first_setup_ = false;
771
772 RunStep(ConfigurationState::kFcmCheckTopic);
773}
774
775void CarrierLockManager::GetFcmToken() {
776 fcm_->RequestToken(BindRepeating(&CarrierLockManager::FcmNotification,
777 weak_ptr_factory_.GetWeakPtr()),
778 BindOnce(&CarrierLockManager::FcmTokenCallback,
779 weak_ptr_factory_.GetWeakPtr()));
780}
781
782void CarrierLockManager::FcmTokenCallback(Result result) {
783 if (result != Result::kSuccess) {
784 LogError(result);
785 if (result != Result::kHandlerBusy) {
786 RetryStep();
787 }
788 return;
789 }
790
791 fcm_token_ = fcm_->token();
792
Michal Mazur4f45d142023-10-15 10:25:35793 base::UmaHistogramEnumeration(kFcmCommunicationResult,
794 FcmResult::kRegistered);
795
Michal Mazura1744b82023-10-15 09:13:02796 RunStep(ConfigurationState::kRequestConfig);
797}
798
799void CarrierLockManager::CheckFcmTopic() {
800 if (local_state_->GetString(kFcmTopicPref).empty()) {
801 VLOG(2) << "FCM topic not provided with config, modem was unlocked.";
Michal Mazur938e67b2024-02-16 19:04:50802 base::UmaHistogramCounts1M(kNumConsecutiveFailuresBeforeUnlock,
803 error_counter_);
Michal Mazura1744b82023-10-15 09:13:02804 RunStep(ConfigurationState::kDeviceUnlocked);
805 return;
806 }
807
Michal Mazur938e67b2024-02-16 19:04:50808 base::UmaHistogramCounts1M(kNumConsecutiveFailuresBeforeLock, error_counter_);
Michal Mazura1744b82023-10-15 09:13:02809 RunStep(ConfigurationState::kFcmSubscribe);
810}
811
812void CarrierLockManager::SubscribeFcmTopic() {
813 std::string fcm_topic = local_state_->GetString(kFcmTopicPref);
814
815 fcm_->SubscribeTopic(fcm_topic,
816 BindRepeating(&CarrierLockManager::FcmNotification,
817 weak_ptr_factory_.GetWeakPtr()),
818 BindOnce(&CarrierLockManager::FcmTopicCallback,
819 weak_ptr_factory_.GetWeakPtr()));
820}
821
822void CarrierLockManager::FcmTopicCallback(Result result) {
823 if (result != Result::kSuccess) {
824 LogError(result);
825 if (result != Result::kHandlerBusy) {
826 RetryStep();
827 }
828 return;
829 }
830
Michal Mazur4f45d142023-10-15 10:25:35831 base::UmaHistogramEnumeration(kFcmCommunicationResult,
832 FcmResult::kSubscribed);
Michal Mazura1744b82023-10-15 09:13:02833 RunStep(ConfigurationState::kDeviceLocked);
834}
835
836void CarrierLockManager::FcmNotification(bool is_from_topic) {
837 // Set LastConfigTime to value older than FCM timeout (usually 30 days)
838 // in order to request new configuration in case of failure or reboot.
839 local_state_->SetTime(kLastConfigTimePref, base::Time::Now() - kFcmTimeout);
840
Michal Mazur4f45d142023-10-15 10:25:35841 base::UmaHistogramEnumeration(
842 kFcmNotificationType, (is_from_topic ? FcmNotification::kUpdateProfile
843 : FcmNotification::kUnlockDevice));
844
Michal Mazura1744b82023-10-15 09:13:02845 RunStep(ConfigurationState::kRequestConfig);
846}
847
848} // namespace ash::carrier_lock