Home | History | Annotate | Download | only in cellular
      1 //
      2 // Copyright (C) 2012 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 
     17 #include "shill/cellular/cellular.h"
     18 
     19 #include <netinet/in.h>
     20 #include <linux/if.h>  // NOLINT - Needs definitions from netinet/in.h
     21 
     22 #include <string>
     23 #include <utility>
     24 #include <vector>
     25 
     26 #include <base/bind.h>
     27 #include <base/callback.h>
     28 #include <base/files/file_path.h>
     29 #include <base/strings/string_util.h>
     30 #include <base/strings/stringprintf.h>
     31 #if defined(__ANDROID__)
     32 #include <dbus/service_constants.h>
     33 #else
     34 #include <chromeos/dbus/service_constants.h>
     35 #endif  // __ANDROID__
     36 
     37 #include "shill/adaptor_interfaces.h"
     38 #include "shill/cellular/cellular_bearer.h"
     39 #include "shill/cellular/cellular_capability_cdma.h"
     40 #include "shill/cellular/cellular_capability_gsm.h"
     41 #include "shill/cellular/cellular_capability_universal.h"
     42 #include "shill/cellular/cellular_capability_universal_cdma.h"
     43 #include "shill/cellular/cellular_service.h"
     44 #include "shill/cellular/mobile_operator_info.h"
     45 #include "shill/control_interface.h"
     46 #include "shill/device.h"
     47 #include "shill/device_info.h"
     48 #include "shill/error.h"
     49 #include "shill/event_dispatcher.h"
     50 #include "shill/external_task.h"
     51 #include "shill/logging.h"
     52 #include "shill/manager.h"
     53 #include "shill/net/rtnl_handler.h"
     54 #include "shill/ppp_daemon.h"
     55 #include "shill/ppp_device.h"
     56 #include "shill/ppp_device_factory.h"
     57 #include "shill/process_manager.h"
     58 #include "shill/profile.h"
     59 #include "shill/property_accessor.h"
     60 #include "shill/store_interface.h"
     61 #include "shill/technology.h"
     62 
     63 using base::Bind;
     64 using base::Closure;
     65 using base::FilePath;
     66 using base::StringPrintf;
     67 using std::map;
     68 using std::string;
     69 using std::vector;
     70 
     71 namespace shill {
     72 
     73 namespace Logging {
     74 static auto kModuleLogScope = ScopeLogger::kCellular;
     75 static string ObjectID(Cellular* c) { return c->GetRpcIdentifier(); }
     76 }
     77 
     78 // static
     79 const char Cellular::kAllowRoaming[] = "AllowRoaming";
     80 const int64_t Cellular::kDefaultScanningTimeoutMilliseconds = 60000;
     81 const char Cellular::kGenericServiceNamePrefix[] = "MobileNetwork";
     82 unsigned int Cellular::friendly_service_name_id_ = 1;
     83 
     84 Cellular::Cellular(ModemInfo* modem_info,
     85                    const string& link_name,
     86                    const string& address,
     87                    int interface_index,
     88                    Type type,
     89                    const string& service,
     90                    const string& path)
     91     : Device(modem_info->control_interface(),
     92              modem_info->dispatcher(),
     93              modem_info->metrics(),
     94              modem_info->manager(),
     95              link_name,
     96              address,
     97              interface_index,
     98              Technology::kCellular),
     99       weak_ptr_factory_(this),
    100       state_(kStateDisabled),
    101       modem_state_(kModemStateUnknown),
    102       home_provider_info_(
    103           new MobileOperatorInfo(modem_info->dispatcher(), "HomeProvider")),
    104       serving_operator_info_(
    105           new MobileOperatorInfo(modem_info->dispatcher(), "ServingOperator")),
    106       mobile_operator_info_observer_(
    107           new Cellular::MobileOperatorInfoObserver(this)),
    108       dbus_service_(service),
    109       dbus_path_(path),
    110       scanning_supported_(false),
    111       scanning_(false),
    112       provider_requires_roaming_(false),
    113       scan_interval_(0),
    114       sim_present_(false),
    115       prl_version_(0),
    116       modem_info_(modem_info),
    117       type_(type),
    118       ppp_device_factory_(PPPDeviceFactory::GetInstance()),
    119       process_manager_(ProcessManager::GetInstance()),
    120       allow_roaming_(false),
    121       proposed_scan_in_progress_(false),
    122       explicit_disconnect_(false),
    123       is_ppp_authenticating_(false),
    124       scanning_timeout_milliseconds_(kDefaultScanningTimeoutMilliseconds) {
    125   RegisterProperties();
    126   InitCapability(type);
    127 
    128   // TODO(pprabhu) Split MobileOperatorInfo into a context that stores the
    129   // costly database, and lighter objects that |Cellular| can own.
    130   // crbug.com/363874
    131   home_provider_info_->Init();
    132   serving_operator_info_->Init();
    133   home_provider_info()->AddObserver(mobile_operator_info_observer_.get());
    134   serving_operator_info()->AddObserver(mobile_operator_info_observer_.get());
    135 
    136   SLOG(this, 2) << "Cellular device " << this->link_name()
    137                 << " initialized.";
    138 }
    139 
    140 Cellular::~Cellular() {
    141   // Under certain conditions, Cellular::StopModem may not be
    142   // called before the Cellular device is destroyed. This happens if the dbus
    143   // modem exported by the modem-manager daemon disappears soon after the modem
    144   // is disabled, not giving shill enough time to complete the disable
    145   // operation.
    146   // In that case, the termination action associated with this cellular object
    147   // may not have been removed.
    148   manager()->RemoveTerminationAction(FriendlyName());
    149 
    150   home_provider_info()->RemoveObserver(mobile_operator_info_observer_.get());
    151   serving_operator_info()->RemoveObserver(
    152       mobile_operator_info_observer_.get());
    153   // Explicitly delete the observer to ensure that it is destroyed before the
    154   // handle to |capability_| that it holds.
    155   mobile_operator_info_observer_.reset();
    156 }
    157 
    158 bool Cellular::Load(StoreInterface* storage) {
    159   const string id = GetStorageIdentifier();
    160   if (!storage->ContainsGroup(id)) {
    161     LOG(WARNING) << "Device is not available in the persistent store: " << id;
    162     return false;
    163   }
    164   storage->GetBool(id, kAllowRoaming, &allow_roaming_);
    165   return Device::Load(storage);
    166 }
    167 
    168 bool Cellular::Save(StoreInterface* storage) {
    169   const string id = GetStorageIdentifier();
    170   storage->SetBool(id, kAllowRoaming, allow_roaming_);
    171   return Device::Save(storage);
    172 }
    173 
    174 // static
    175 string Cellular::GetStateString(State state) {
    176   switch (state) {
    177     case kStateDisabled:
    178       return "CellularStateDisabled";
    179     case kStateEnabled:
    180       return "CellularStateEnabled";
    181     case kStateRegistered:
    182       return "CellularStateRegistered";
    183     case kStateConnected:
    184       return "CellularStateConnected";
    185     case kStateLinked:
    186       return "CellularStateLinked";
    187     default:
    188       NOTREACHED();
    189   }
    190   return StringPrintf("CellularStateUnknown-%d", state);
    191 }
    192 
    193 // static
    194 string Cellular::GetModemStateString(ModemState modem_state) {
    195   switch (modem_state) {
    196     case kModemStateFailed:
    197       return "CellularModemStateFailed";
    198     case kModemStateUnknown:
    199       return "CellularModemStateUnknown";
    200     case kModemStateInitializing:
    201       return "CellularModemStateInitializing";
    202     case kModemStateLocked:
    203       return "CellularModemStateLocked";
    204     case kModemStateDisabled:
    205       return "CellularModemStateDisabled";
    206     case kModemStateDisabling:
    207       return "CellularModemStateDisabling";
    208     case kModemStateEnabling:
    209       return "CellularModemStateEnabling";
    210     case kModemStateEnabled:
    211       return "CellularModemStateEnabled";
    212     case kModemStateSearching:
    213       return "CellularModemStateSearching";
    214     case kModemStateRegistered:
    215       return "CellularModemStateRegistered";
    216     case kModemStateDisconnecting:
    217       return "CellularModemStateDisconnecting";
    218     case kModemStateConnecting:
    219       return "CellularModemStateConnecting";
    220     case kModemStateConnected:
    221       return "CellularModemStateConnected";
    222     default:
    223       NOTREACHED();
    224   }
    225   return StringPrintf("CellularModemStateUnknown-%d", modem_state);
    226 }
    227 
    228 string Cellular::GetTechnologyFamily(Error* error) {
    229   return capability_->GetTypeString();
    230 }
    231 
    232 void Cellular::SetState(State state) {
    233   SLOG(this, 2) << GetStateString(state_) << " -> "
    234                 << GetStateString(state);
    235   state_ = state;
    236 }
    237 
    238 void Cellular::HelpRegisterDerivedBool(
    239     const string& name,
    240     bool(Cellular::*get)(Error* error),
    241     bool(Cellular::*set)(const bool& value, Error* error)) {
    242   mutable_store()->RegisterDerivedBool(
    243       name,
    244       BoolAccessor(
    245           new CustomAccessor<Cellular, bool>(this, get, set)));
    246 }
    247 
    248 void Cellular::HelpRegisterConstDerivedString(
    249     const string& name,
    250     string(Cellular::*get)(Error*)) {
    251   mutable_store()->RegisterDerivedString(
    252       name,
    253       StringAccessor(new CustomAccessor<Cellular, string>(this, get, nullptr)));
    254 }
    255 
    256 void Cellular::Start(Error* error,
    257                      const EnabledStateChangedCallback& callback) {
    258   DCHECK(error);
    259   SLOG(this, 2) << __func__ << ": " << GetStateString(state_);
    260   // We can only short circuit the start operation if both the cellular state
    261   // is not disabled AND the proxies have been initialized.  We have seen
    262   // crashes due to NULL proxies and the state being not disabled.
    263   if (state_ != kStateDisabled && capability_->AreProxiesInitialized()) {
    264     return;
    265   }
    266 
    267   ResultCallback cb = Bind(&Cellular::StartModemCallback,
    268                            weak_ptr_factory_.GetWeakPtr(),
    269                            callback);
    270   capability_->StartModem(error, cb);
    271 }
    272 
    273 void Cellular::Stop(Error* error,
    274                     const EnabledStateChangedCallback& callback) {
    275   SLOG(this, 2) << __func__ << ": " << GetStateString(state_);
    276   explicit_disconnect_ = true;
    277   ResultCallback cb = Bind(&Cellular::StopModemCallback,
    278                            weak_ptr_factory_.GetWeakPtr(),
    279                            callback);
    280   capability_->StopModem(error, cb);
    281 }
    282 
    283 bool Cellular::IsUnderlyingDeviceEnabled() const {
    284   return IsEnabledModemState(modem_state_);
    285 }
    286 
    287 bool Cellular::IsModemRegistered() const {
    288   return (modem_state_ == Cellular::kModemStateRegistered ||
    289           modem_state_ == Cellular::kModemStateConnecting ||
    290           modem_state_ == Cellular::kModemStateConnected);
    291 }
    292 
    293 // static
    294 bool Cellular::IsEnabledModemState(ModemState state) {
    295   switch (state) {
    296     case kModemStateFailed:
    297     case kModemStateUnknown:
    298     case kModemStateDisabled:
    299     case kModemStateInitializing:
    300     case kModemStateLocked:
    301     case kModemStateDisabling:
    302     case kModemStateEnabling:
    303       return false;
    304     case kModemStateEnabled:
    305     case kModemStateSearching:
    306     case kModemStateRegistered:
    307     case kModemStateDisconnecting:
    308     case kModemStateConnecting:
    309     case kModemStateConnected:
    310       return true;
    311   }
    312   return false;
    313 }
    314 
    315 void Cellular::StartModemCallback(const EnabledStateChangedCallback& callback,
    316                                   const Error& error) {
    317   SLOG(this, 2) << __func__ << ": " << GetStateString(state_);
    318   if (error.IsSuccess() && (state_ == kStateDisabled)) {
    319     SetState(kStateEnabled);
    320     // Registration state updates may have been ignored while the
    321     // modem was not yet marked enabled.
    322     HandleNewRegistrationState();
    323   }
    324   callback.Run(error);
    325 }
    326 
    327 void Cellular::StopModemCallback(const EnabledStateChangedCallback& callback,
    328                                  const Error& error) {
    329   SLOG(this, 2) << __func__ << ": " << GetStateString(state_);
    330   explicit_disconnect_ = false;
    331   // Destroy the cellular service regardless of any errors that occur during
    332   // the stop process since we do not know the state of the modem at this
    333   // point.
    334   DestroyService();
    335   if (state_ != kStateDisabled)
    336     SetState(kStateDisabled);
    337   callback.Run(error);
    338   // In case no termination action was executed (and TerminationActionComplete
    339   // was not invoked) in response to a suspend request, any registered
    340   // termination action needs to be removed explicitly.
    341   manager()->RemoveTerminationAction(FriendlyName());
    342 }
    343 
    344 void Cellular::InitCapability(Type type) {
    345   // TODO(petkov): Consider moving capability construction into a factory that's
    346   // external to the Cellular class.
    347   SLOG(this, 2) << __func__ << "(" << type << ")";
    348   switch (type) {
    349     case kTypeGSM:
    350       capability_.reset(new CellularCapabilityGSM(this,
    351                                                   control_interface(),
    352                                                   modem_info_));
    353       break;
    354     case kTypeCDMA:
    355       capability_.reset(new CellularCapabilityCDMA(this,
    356                                                    control_interface(),
    357                                                    modem_info_));
    358       break;
    359     case kTypeUniversal:
    360       capability_.reset(new CellularCapabilityUniversal(
    361           this,
    362           control_interface(),
    363           modem_info_));
    364       break;
    365     case kTypeUniversalCDMA:
    366       capability_.reset(new CellularCapabilityUniversalCDMA(
    367           this,
    368           control_interface(),
    369           modem_info_));
    370       break;
    371     default: NOTREACHED();
    372   }
    373   mobile_operator_info_observer_->set_capability(capability_.get());
    374 }
    375 
    376 void Cellular::Activate(const string& carrier,
    377                         Error* error, const ResultCallback& callback) {
    378   capability_->Activate(carrier, error, callback);
    379 }
    380 
    381 void Cellular::CompleteActivation(Error* error) {
    382   capability_->CompleteActivation(error);
    383 }
    384 
    385 void Cellular::RegisterOnNetwork(const string& network_id,
    386                                  Error* error,
    387                                  const ResultCallback& callback) {
    388   capability_->RegisterOnNetwork(network_id, error, callback);
    389 }
    390 
    391 void Cellular::RequirePIN(const string& pin, bool require,
    392                           Error* error, const ResultCallback& callback) {
    393   SLOG(this, 2) << __func__ << "(" << require << ")";
    394   capability_->RequirePIN(pin, require, error, callback);
    395 }
    396 
    397 void Cellular::EnterPIN(const string& pin,
    398                         Error* error, const ResultCallback& callback) {
    399   SLOG(this, 2) << __func__;
    400   capability_->EnterPIN(pin, error, callback);
    401 }
    402 
    403 void Cellular::UnblockPIN(const string& unblock_code,
    404                           const string& pin,
    405                           Error* error, const ResultCallback& callback) {
    406   SLOG(this, 2) << __func__;
    407   capability_->UnblockPIN(unblock_code, pin, error, callback);
    408 }
    409 
    410 void Cellular::ChangePIN(const string& old_pin, const string& new_pin,
    411                          Error* error, const ResultCallback& callback) {
    412   SLOG(this, 2) << __func__;
    413   capability_->ChangePIN(old_pin, new_pin, error, callback);
    414 }
    415 
    416 void Cellular::Reset(Error* error, const ResultCallback& callback) {
    417   SLOG(this, 2) << __func__;
    418   capability_->Reset(error, callback);
    419 }
    420 
    421 void Cellular::SetCarrier(const string& carrier,
    422                           Error* error, const ResultCallback& callback) {
    423   SLOG(this, 2) << __func__ << "(" << carrier << ")";
    424   capability_->SetCarrier(carrier, error, callback);
    425 }
    426 
    427 bool Cellular::IsIPv6Allowed() const {
    428   // A cellular device is disabled before the system goes into suspend mode.
    429   // However, outstanding TCP sockets may not be nuked when the associated
    430   // network interface goes down. When the system resumes from suspend, the
    431   // cellular device is re-enabled and may reconnect to the network, which
    432   // acquire a new IPv6 address on the network interface. However, those
    433   // outstanding TCP sockets may initiate traffic with the old IPv6 address.
    434   // Some network may not like the fact that two IPv6 addresses originated from
    435   // the same modem within a connection session and may drop the connection.
    436   // Here we disable IPv6 support on cellular devices to work around the issue.
    437   //
    438   // TODO(benchan): Resolve the IPv6 issue in a different way and then
    439   // re-enable IPv6 support on cellular devices.
    440   return false;
    441 }
    442 
    443 void Cellular::DropConnection() {
    444   if (ppp_device_) {
    445     // For PPP dongles, IP configuration is handled on the |ppp_device_|,
    446     // rather than the netdev plumbed into |this|.
    447     ppp_device_->DropConnection();
    448   } else {
    449     Device::DropConnection();
    450   }
    451 }
    452 
    453 void Cellular::SetServiceState(Service::ConnectState state) {
    454   if (ppp_device_) {
    455     ppp_device_->SetServiceState(state);
    456   } else if (selected_service()) {
    457     Device::SetServiceState(state);
    458   } else if (service_) {
    459     service_->SetState(state);
    460   } else {
    461     LOG(WARNING) << "State change with no Service.";
    462   }
    463 }
    464 
    465 void Cellular::SetServiceFailure(Service::ConnectFailure failure_state) {
    466   if (ppp_device_) {
    467     ppp_device_->SetServiceFailure(failure_state);
    468   } else if (selected_service()) {
    469     Device::SetServiceFailure(failure_state);
    470   } else if (service_) {
    471     service_->SetFailure(failure_state);
    472   } else {
    473     LOG(WARNING) << "State change with no Service.";
    474   }
    475 }
    476 
    477 void Cellular::SetServiceFailureSilent(Service::ConnectFailure failure_state) {
    478   if (ppp_device_) {
    479     ppp_device_->SetServiceFailureSilent(failure_state);
    480   } else if (selected_service()) {
    481     Device::SetServiceFailureSilent(failure_state);
    482   } else if (service_) {
    483     service_->SetFailureSilent(failure_state);
    484   } else {
    485     LOG(WARNING) << "State change with no Service.";
    486   }
    487 }
    488 
    489 void Cellular::OnBeforeSuspend(const ResultCallback& callback) {
    490   LOG(INFO) << __func__;
    491   Error error;
    492   StopPPP();
    493   SetEnabledNonPersistent(false, &error, callback);
    494   if (error.IsFailure() && error.type() != Error::kInProgress) {
    495     // If we fail to disable the modem right away, proceed instead of wasting
    496     // the time to wait for the suspend/termination delay to expire.
    497     LOG(WARNING) << "Proceed with suspend/termination even though the modem "
    498                  << "is not yet disabled: " << error;
    499     callback.Run(error);
    500   }
    501 }
    502 
    503 void Cellular::OnAfterResume() {
    504   SLOG(this, 2) << __func__;
    505   if (enabled_persistent()) {
    506     LOG(INFO) << "Restarting modem after resume.";
    507 
    508     // If we started disabling the modem before suspend, but that
    509     // suspend is still in progress, then we are not yet in
    510     // kStateDisabled. That's a problem, because Cellular::Start
    511     // returns immediately in that case. Hack around that by forcing
    512     // |state_| here.
    513     //
    514     // TODO(quiche): Remove this hack. Maybe
    515     // CellularCapabilityUniversal should generate separate
    516     // notifications for Stop_Disable, and Stop_PowerDown. Then we'd
    517     // update our state to kStateDisabled when Stop_Disable completes.
    518     state_ = kStateDisabled;
    519 
    520     Error error;
    521     SetEnabledUnchecked(true, &error, Bind(LogRestartModemResult));
    522     if (error.IsSuccess()) {
    523       LOG(INFO) << "Modem restart completed immediately.";
    524     } else if (error.IsOngoing()) {
    525       LOG(INFO) << "Modem restart in progress.";
    526     } else {
    527       LOG(WARNING) << "Modem restart failed: " << error;
    528     }
    529   }
    530   // TODO(quiche): Consider if this should be conditional. If, e.g.,
    531   // the device was still disabling when we suspended, will trying to
    532   // renew DHCP here cause problems?
    533   Device::OnAfterResume();
    534 }
    535 
    536 void Cellular::Scan(ScanType /*scan_type*/, Error* error,
    537                     const string& /*reason*/) {
    538   SLOG(this, 2) << __func__;
    539   CHECK(error);
    540   if (proposed_scan_in_progress_) {
    541     Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress,
    542                           "Already scanning");
    543     return;
    544   }
    545 
    546   // |scan_type| is ignored because Cellular only does a full scan.
    547   ResultStringmapsCallback cb = Bind(&Cellular::OnScanReply,
    548                                      weak_ptr_factory_.GetWeakPtr());
    549   capability_->Scan(error, cb);
    550   // An immediate failure in |cabapility_->Scan(...)| is indicated through the
    551   // |error| argument.
    552   if (error->IsFailure())
    553     return;
    554 
    555   proposed_scan_in_progress_ = true;
    556   UpdateScanning();
    557 }
    558 
    559 void Cellular::OnScanReply(const Stringmaps& found_networks,
    560                            const Error& error) {
    561   proposed_scan_in_progress_ = false;
    562   UpdateScanning();
    563 
    564   // TODO(jglasgow): fix error handling.
    565   // At present, there is no way of notifying user of this asynchronous error.
    566   if (error.IsFailure()) {
    567     clear_found_networks();
    568     return;
    569   }
    570 
    571   set_found_networks(found_networks);
    572 }
    573 
    574 void Cellular::HandleNewRegistrationState() {
    575   SLOG(this, 2) << __func__
    576                 << ": (new state " << GetStateString(state_) << ")";
    577   if (!capability_->IsRegistered()) {
    578     if (!explicit_disconnect_ &&
    579         (state_ == kStateLinked || state_ == kStateConnected) &&
    580         service_.get())
    581       metrics()->NotifyCellularDeviceDrop(
    582           capability_->GetNetworkTechnologyString(), service_->strength());
    583     DestroyService();
    584     if (state_ == kStateLinked ||
    585         state_ == kStateConnected ||
    586         state_ == kStateRegistered) {
    587       SetState(kStateEnabled);
    588     }
    589     return;
    590   }
    591   // In Disabled state, defer creating a service until fully
    592   // enabled. UI will ignore the appearance of a new service
    593   // on a disabled device.
    594   if (state_ == kStateDisabled) {
    595     return;
    596   }
    597   if (state_ == kStateEnabled) {
    598     SetState(kStateRegistered);
    599   }
    600   if (!service_.get()) {
    601     metrics()->NotifyDeviceScanFinished(interface_index());
    602     CreateService();
    603   }
    604   capability_->GetSignalQuality();
    605   if (state_ == kStateRegistered && modem_state_ == kModemStateConnected)
    606     OnConnected();
    607   service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString());
    608   service_->SetRoamingState(capability_->GetRoamingStateString());
    609   manager()->UpdateService(service_);
    610 }
    611 
    612 void Cellular::HandleNewSignalQuality(uint32_t strength) {
    613   SLOG(this, 2) << "Signal strength: " << strength;
    614   if (service_) {
    615     service_->SetStrength(strength);
    616   }
    617 }
    618 
    619 void Cellular::CreateService() {
    620   SLOG(this, 2) << __func__;
    621   CHECK(!service_.get());
    622   service_ = new CellularService(modem_info_, this);
    623   capability_->OnServiceCreated();
    624 
    625   // Storage identifier must be set only once, and before registering the
    626   // service with the manager, since we key off of this identifier to
    627   // determine the profile to load.
    628   // TODO(pprabhu) Make profile matching more robust (crbug.com/369755)
    629   string service_id;
    630   if (home_provider_info_->IsMobileNetworkOperatorKnown() &&
    631       !home_provider_info_->uuid().empty()) {
    632     service_id = home_provider_info_->uuid();
    633   } else if (serving_operator_info_->IsMobileNetworkOperatorKnown() &&
    634              !serving_operator_info_->uuid().empty()) {
    635     service_id = serving_operator_info_->uuid();
    636   } else {
    637     switch (type_) {
    638       case kTypeGSM:
    639       case kTypeUniversal:
    640         if (!sim_identifier().empty()) {
    641           service_id = sim_identifier();
    642         }
    643         break;
    644 
    645       case kTypeCDMA:
    646       case kTypeUniversalCDMA:
    647         if (!meid().empty()) {
    648           service_id = meid();
    649         }
    650         break;
    651 
    652       default:
    653         NOTREACHED();
    654     }
    655   }
    656 
    657   if (!service_id.empty()) {
    658     string storage_id = base::StringPrintf(
    659         "%s_%s_%s",
    660         kTypeCellular, address().c_str(), service_id.c_str());
    661     service()->SetStorageIdentifier(storage_id);
    662   }
    663 
    664   manager()->RegisterService(service_);
    665 
    666   // We might have missed a property update because the service wasn't created
    667   // ealier.
    668   UpdateScanning();
    669   mobile_operator_info_observer_->OnOperatorChanged();
    670 }
    671 
    672 void Cellular::DestroyService() {
    673   SLOG(this, 2) << __func__;
    674   DropConnection();
    675   if (service_) {
    676     LOG(INFO) << "Deregistering cellular service " << service_->unique_name()
    677               << " for device " << link_name();
    678     manager()->DeregisterService(service_);
    679     service_ = nullptr;
    680   }
    681 }
    682 
    683 void Cellular::Connect(Error* error) {
    684   SLOG(this, 2) << __func__;
    685   if (state_ == kStateConnected || state_ == kStateLinked) {
    686     Error::PopulateAndLog(FROM_HERE, error, Error::kAlreadyConnected,
    687                           "Already connected; connection request ignored.");
    688     return;
    689   } else if (state_ != kStateRegistered) {
    690     Error::PopulateAndLog(FROM_HERE, error, Error::kNotRegistered,
    691                           "Modem not registered; connection request ignored.");
    692     return;
    693   }
    694 
    695   if (!capability_->AllowRoaming() &&
    696       service_->roaming_state() == kRoamingStateRoaming) {
    697     Error::PopulateAndLog(FROM_HERE, error, Error::kNotOnHomeNetwork,
    698                           "Roaming disallowed; connection request ignored.");
    699     return;
    700   }
    701 
    702   KeyValueStore properties;
    703   capability_->SetupConnectProperties(&properties);
    704   ResultCallback cb = Bind(&Cellular::OnConnectReply,
    705                            weak_ptr_factory_.GetWeakPtr());
    706   OnConnecting();
    707   capability_->Connect(properties, error, cb);
    708   if (!error->IsSuccess())
    709     return;
    710 
    711   bool is_auto_connecting = service_.get() && service_->is_auto_connecting();
    712   metrics()->NotifyDeviceConnectStarted(interface_index(), is_auto_connecting);
    713 }
    714 
    715 // Note that there's no ResultCallback argument to this,
    716 // since Connect() isn't yet passed one.
    717 void Cellular::OnConnectReply(const Error& error) {
    718   SLOG(this, 2) << __func__ << "(" << error << ")";
    719   if (error.IsSuccess()) {
    720     metrics()->NotifyDeviceConnectFinished(interface_index());
    721     OnConnected();
    722   } else {
    723     metrics()->NotifyCellularDeviceConnectionFailure();
    724     OnConnectFailed(error);
    725   }
    726 }
    727 
    728 void Cellular::OnDisabled() {
    729   SetEnabled(false);
    730 }
    731 
    732 void Cellular::OnEnabled() {
    733   manager()->AddTerminationAction(FriendlyName(),
    734                                   Bind(&Cellular::StartTermination,
    735                                        weak_ptr_factory_.GetWeakPtr()));
    736   SetEnabled(true);
    737 }
    738 
    739 void Cellular::OnConnecting() {
    740   if (service_)
    741     service_->SetState(Service::kStateAssociating);
    742 }
    743 
    744 void Cellular::OnConnected() {
    745   SLOG(this, 2) << __func__;
    746   if (state_ == kStateConnected || state_ == kStateLinked) {
    747     SLOG(this, 2) << "Already connected";
    748     return;
    749   }
    750   SetState(kStateConnected);
    751   if (!service_) {
    752     LOG(INFO) << "Disconnecting due to no cellular service.";
    753     Disconnect(nullptr, "no celluar service");
    754   } else if (!capability_->AllowRoaming() &&
    755       service_->roaming_state() == kRoamingStateRoaming) {
    756     LOG(INFO) << "Disconnecting due to roaming.";
    757     Disconnect(nullptr, "roaming");
    758   } else {
    759     EstablishLink();
    760   }
    761 }
    762 
    763 void Cellular::OnConnectFailed(const Error& error) {
    764   if (service_)
    765     service_->SetFailure(Service::kFailureUnknown);
    766 }
    767 
    768 void Cellular::Disconnect(Error* error, const char* reason) {
    769   SLOG(this, 2) << __func__ << ": " << reason;
    770   if (state_ != kStateConnected && state_ != kStateLinked) {
    771     Error::PopulateAndLog(
    772         FROM_HERE, error, Error::kNotConnected,
    773         "Not connected; request ignored.");
    774     return;
    775   }
    776   StopPPP();
    777   explicit_disconnect_ = true;
    778   ResultCallback cb = Bind(&Cellular::OnDisconnectReply,
    779                            weak_ptr_factory_.GetWeakPtr());
    780   capability_->Disconnect(error, cb);
    781 }
    782 
    783 void Cellular::OnDisconnectReply(const Error& error) {
    784   SLOG(this, 2) << __func__ << "(" << error << ")";
    785   explicit_disconnect_ = false;
    786   if (error.IsSuccess()) {
    787     OnDisconnected();
    788   } else {
    789     metrics()->NotifyCellularDeviceDisconnectionFailure();
    790     OnDisconnectFailed();
    791   }
    792 }
    793 
    794 void Cellular::OnDisconnected() {
    795   SLOG(this, 2) << __func__;
    796   if (!DisconnectCleanup()) {
    797     LOG(WARNING) << "Disconnect occurred while in state "
    798                  << GetStateString(state_);
    799   }
    800 }
    801 
    802 void Cellular::OnDisconnectFailed() {
    803   SLOG(this, 2) << __func__;
    804   // If the modem is in the disconnecting state, then
    805   // the disconnect should eventually succeed, so do
    806   // nothing.
    807   if (modem_state_ == kModemStateDisconnecting) {
    808     LOG(WARNING) << "Ignoring failed disconnect while modem is disconnecting.";
    809     return;
    810   }
    811 
    812   // OnDisconnectFailed got called because no bearers
    813   // to disconnect were found. Which means that we shouldn't
    814   // really remain in the connected/linked state if we
    815   // are in one of those.
    816   if (!DisconnectCleanup()) {
    817     // otherwise, no-op
    818     LOG(WARNING) << "Ignoring failed disconnect while in state "
    819                  << GetStateString(state_);
    820   }
    821 
    822   // TODO(armansito): In either case, shill ends up thinking
    823   // that it's disconnected, while for some reason the underlying
    824   // modem might still actually be connected. In that case the UI
    825   // would be reflecting an incorrect state and a further connection
    826   // request would fail. We should perhaps tear down the modem and
    827   // restart it here.
    828 }
    829 
    830 void Cellular::EstablishLink() {
    831   SLOG(this, 2) << __func__;
    832   CHECK_EQ(kStateConnected, state_);
    833 
    834   CellularBearer* bearer = capability_->GetActiveBearer();
    835   if (bearer && bearer->ipv4_config_method() == IPConfig::kMethodPPP) {
    836     LOG(INFO) << "Start PPP connection on " << bearer->data_interface();
    837     StartPPP(bearer->data_interface());
    838     return;
    839   }
    840 
    841   unsigned int flags = 0;
    842   if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
    843       (flags & IFF_UP) != 0) {
    844     LinkEvent(flags, IFF_UP);
    845     return;
    846   }
    847   // TODO(petkov): Provide a timeout for a failed link-up request.
    848   rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
    849 
    850   // Set state to associating.
    851   OnConnecting();
    852 }
    853 
    854 void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
    855   Device::LinkEvent(flags, change);
    856   if (ppp_task_) {
    857     LOG(INFO) << "Ignoring LinkEvent on device with PPP interface.";
    858     return;
    859   }
    860 
    861   if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
    862     LOG(INFO) << link_name() << " is up.";
    863     SetState(kStateLinked);
    864 
    865     // TODO(benchan): IPv6 support is currently disabled for cellular devices.
    866     // Check and obtain IPv6 configuration from the bearer when we later enable
    867     // IPv6 support on cellular devices.
    868     CellularBearer* bearer = capability_->GetActiveBearer();
    869     if (bearer && bearer->ipv4_config_method() == IPConfig::kMethodStatic) {
    870       SLOG(this, 2) << "Assign static IP configuration from bearer.";
    871       SelectService(service_);
    872       SetServiceState(Service::kStateConfiguring);
    873       AssignIPConfig(*bearer->ipv4_config_properties());
    874       return;
    875     }
    876 
    877     if (AcquireIPConfig()) {
    878       SLOG(this, 2) << "Start DHCP to acquire IP configuration.";
    879       SelectService(service_);
    880       SetServiceState(Service::kStateConfiguring);
    881       return;
    882     }
    883 
    884     LOG(ERROR) << "Unable to acquire IP configuration over DHCP.";
    885     return;
    886   }
    887 
    888   if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
    889     LOG(INFO) << link_name() << " is down.";
    890     SetState(kStateConnected);
    891     DropConnection();
    892   }
    893 }
    894 
    895 void Cellular::OnPropertiesChanged(
    896     const string& interface,
    897     const KeyValueStore& changed_properties,
    898     const vector<string>& invalidated_properties) {
    899   capability_->OnPropertiesChanged(interface,
    900                                    changed_properties,
    901                                    invalidated_properties);
    902 }
    903 
    904 string Cellular::CreateDefaultFriendlyServiceName() {
    905   SLOG(this, 2) << __func__;
    906   return base::StringPrintf("%s_%u",
    907                             kGenericServiceNamePrefix,
    908                             friendly_service_name_id_++);
    909 }
    910 
    911 bool Cellular::IsDefaultFriendlyServiceName(const string& service_name) const {
    912   return base::StartsWith(service_name, kGenericServiceNamePrefix,
    913                           base::CompareCase::SENSITIVE);
    914 }
    915 
    916 void Cellular::OnModemStateChanged(ModemState new_state) {
    917   ModemState old_state = modem_state_;
    918   SLOG(this, 2) << __func__ << ": " << GetModemStateString(old_state)
    919                 << " -> " << GetModemStateString(new_state);
    920   if (old_state == new_state) {
    921     SLOG(this, 2) << "The new state matches the old state. Nothing to do.";
    922     return;
    923   }
    924   set_modem_state(new_state);
    925   if (old_state >= kModemStateRegistered &&
    926       new_state < kModemStateRegistered) {
    927     capability_->SetUnregistered(new_state == kModemStateSearching);
    928     HandleNewRegistrationState();
    929   }
    930   if (new_state == kModemStateDisabled) {
    931     OnDisabled();
    932   } else if (new_state >= kModemStateEnabled) {
    933     if (old_state < kModemStateEnabled) {
    934       // Just became enabled, update enabled state.
    935       OnEnabled();
    936     }
    937     if ((new_state == kModemStateEnabled ||
    938          new_state == kModemStateSearching ||
    939          new_state == kModemStateRegistered) &&
    940         (old_state == kModemStateConnected ||
    941          old_state == kModemStateConnecting ||
    942          old_state == kModemStateDisconnecting))
    943       OnDisconnected();
    944     else if (new_state == kModemStateConnecting)
    945       OnConnecting();
    946     else if (new_state == kModemStateConnected &&
    947              old_state == kModemStateConnecting)
    948       OnConnected();
    949   }
    950 
    951   // Update the kScanningProperty property after we've handled the current state
    952   // update completely.
    953   UpdateScanning();
    954 }
    955 
    956 bool Cellular::IsActivating() const {
    957   return capability_->IsActivating();
    958 }
    959 
    960 bool Cellular::SetAllowRoaming(const bool& value, Error* /*error*/) {
    961   SLOG(this, 2) << __func__
    962                 << "(" << allow_roaming_ << "->" << value << ")";
    963   if (allow_roaming_ == value) {
    964     return false;
    965   }
    966   allow_roaming_ = value;
    967   manager()->UpdateDevice(this);
    968 
    969   // Use AllowRoaming() instead of allow_roaming_ in order to
    970   // incorporate provider preferences when evaluating if a disconnect
    971   // is required.
    972   if (!capability_->AllowRoaming() &&
    973       capability_->GetRoamingStateString() == kRoamingStateRoaming) {
    974     Error error;
    975     Disconnect(&error, __func__);
    976   }
    977   adaptor()->EmitBoolChanged(kCellularAllowRoamingProperty, value);
    978   return true;
    979 }
    980 
    981 void Cellular::StartTermination() {
    982   SLOG(this, 2) << __func__;
    983   OnBeforeSuspend(Bind(&Cellular::OnTerminationCompleted,
    984                        weak_ptr_factory_.GetWeakPtr()));
    985 }
    986 
    987 void Cellular::OnTerminationCompleted(const Error& error) {
    988   LOG(INFO) << __func__ << ": " << error;
    989   manager()->TerminationActionComplete(FriendlyName());
    990   manager()->RemoveTerminationAction(FriendlyName());
    991 }
    992 
    993 bool Cellular::DisconnectCleanup() {
    994   bool succeeded = false;
    995   if (state_ == kStateConnected || state_ == kStateLinked) {
    996     SetState(kStateRegistered);
    997     SetServiceFailureSilent(Service::kFailureUnknown);
    998     DestroyIPConfig();
    999     succeeded = true;
   1000   }
   1001   capability_->DisconnectCleanup();
   1002   return succeeded;
   1003 }
   1004 
   1005 // static
   1006 void Cellular::LogRestartModemResult(const Error& error) {
   1007   if (error.IsSuccess()) {
   1008     LOG(INFO) << "Modem restart completed.";
   1009   } else {
   1010     LOG(WARNING) << "Attempt to restart modem failed: " << error;
   1011   }
   1012 }
   1013 
   1014 void Cellular::StartPPP(const string& serial_device) {
   1015   SLOG(PPP, this, 2) << __func__ << " on " << serial_device;
   1016   // Detach any SelectedService from this device. It will be grafted onto
   1017   // the PPPDevice after PPP is up (in Cellular::Notify).
   1018   //
   1019   // This has two important effects: 1) kills dhcpcd if it is running.
   1020   // 2) stops Cellular::LinkEvent from driving changes to the
   1021   // SelectedService.
   1022   if (selected_service()) {
   1023     CHECK_EQ(service_.get(), selected_service().get());
   1024     // Save and restore |service_| state, as DropConnection calls
   1025     // SelectService, and SelectService will move selected_service()
   1026     // to kStateIdle.
   1027     Service::ConnectState original_state(service_->state());
   1028     Device::DropConnection();  // Don't redirect to PPPDevice.
   1029     service_->SetState(original_state);
   1030   } else {
   1031     CHECK(!ipconfig());  // Shouldn't have ipconfig without selected_service().
   1032   }
   1033 
   1034   PPPDaemon::DeathCallback death_callback(Bind(&Cellular::OnPPPDied,
   1035                                                weak_ptr_factory_.GetWeakPtr()));
   1036 
   1037   PPPDaemon::Options options;
   1038   options.no_detach = true;
   1039   options.no_default_route = true;
   1040   options.use_peer_dns = true;
   1041 
   1042   is_ppp_authenticating_ = false;
   1043 
   1044   Error error;
   1045   std::unique_ptr<ExternalTask> new_ppp_task(
   1046       PPPDaemon::Start(modem_info_->control_interface(),
   1047                        process_manager_,
   1048                        weak_ptr_factory_.GetWeakPtr(),
   1049                        options,
   1050                        serial_device,
   1051                        death_callback,
   1052                        &error));
   1053   if (new_ppp_task) {
   1054     LOG(INFO) << "Forked pppd process.";
   1055     ppp_task_ = std::move(new_ppp_task);
   1056   }
   1057 }
   1058 
   1059 void Cellular::StopPPP() {
   1060   SLOG(PPP, this, 2) << __func__;
   1061   DropConnection();
   1062   ppp_task_.reset();
   1063   ppp_device_ = nullptr;
   1064 }
   1065 
   1066 // called by |ppp_task_|
   1067 void Cellular::GetLogin(string* user, string* password) {
   1068   SLOG(PPP, this, 2) << __func__;
   1069   if (!service()) {
   1070     LOG(ERROR) << __func__ << " with no service ";
   1071     return;
   1072   }
   1073   CHECK(user);
   1074   CHECK(password);
   1075   *user = service()->ppp_username();
   1076   *password = service()->ppp_password();
   1077 }
   1078 
   1079 // Called by |ppp_task_|.
   1080 void Cellular::Notify(const string& reason,
   1081                       const map<string, string>& dict) {
   1082   SLOG(PPP, this, 2) << __func__ << " " << reason << " on " << link_name();
   1083 
   1084   if (reason == kPPPReasonAuthenticating) {
   1085     OnPPPAuthenticating();
   1086   } else if (reason == kPPPReasonAuthenticated) {
   1087     OnPPPAuthenticated();
   1088   } else if (reason == kPPPReasonConnect) {
   1089     OnPPPConnected(dict);
   1090   } else if (reason == kPPPReasonDisconnect) {
   1091     OnPPPDisconnected();
   1092   } else {
   1093     NOTREACHED();
   1094   }
   1095 }
   1096 
   1097 void Cellular::OnPPPAuthenticated() {
   1098   SLOG(PPP, this, 2) << __func__;
   1099   is_ppp_authenticating_ = false;
   1100 }
   1101 
   1102 void Cellular::OnPPPAuthenticating() {
   1103   SLOG(PPP, this, 2) << __func__;
   1104   is_ppp_authenticating_ = true;
   1105 }
   1106 
   1107 void Cellular::OnPPPConnected(const map<string, string>& params) {
   1108   SLOG(PPP, this, 2) << __func__;
   1109   string interface_name = PPPDevice::GetInterfaceName(params);
   1110   DeviceInfo* device_info = modem_info_->manager()->device_info();
   1111   int interface_index = device_info->GetIndex(interface_name);
   1112   if (interface_index < 0) {
   1113     // TODO(quiche): Consider handling the race when the RTNL notification about
   1114     // the new PPP device has not been received yet. crbug.com/246832.
   1115     NOTIMPLEMENTED() << ": No device info for " << interface_name << ".";
   1116     return;
   1117   }
   1118 
   1119   if (!ppp_device_ || ppp_device_->interface_index() != interface_index) {
   1120     if (ppp_device_) {
   1121       ppp_device_->SelectService(nullptr);  // No longer drives |service_|.
   1122     }
   1123     ppp_device_ = ppp_device_factory_->CreatePPPDevice(
   1124         modem_info_->control_interface(),
   1125         modem_info_->dispatcher(),
   1126         modem_info_->metrics(),
   1127         modem_info_->manager(),
   1128         interface_name,
   1129         interface_index);
   1130     device_info->RegisterDevice(ppp_device_);
   1131   }
   1132 
   1133   CHECK(service_);
   1134   // For PPP, we only SelectService on the |ppp_device_|.
   1135   CHECK(!selected_service());
   1136   const bool kBlackholeIPv6 = false;
   1137   ppp_device_->SetEnabled(true);
   1138   ppp_device_->SelectService(service_);
   1139   ppp_device_->UpdateIPConfigFromPPP(params, kBlackholeIPv6);
   1140 }
   1141 
   1142 void Cellular::OnPPPDisconnected() {
   1143   SLOG(PPP, this, 2) << __func__;
   1144   // DestroyLater, rather than while on stack.
   1145   ppp_task_.release()->DestroyLater(modem_info_->dispatcher());
   1146   if (is_ppp_authenticating_) {
   1147     SetServiceFailure(Service::kFailurePPPAuth);
   1148   } else {
   1149     // TODO(quiche): Don't set failure if we disconnected intentionally.
   1150     SetServiceFailure(Service::kFailureUnknown);
   1151   }
   1152   Error error;
   1153   Disconnect(&error, __func__);
   1154 }
   1155 
   1156 void Cellular::OnPPPDied(pid_t pid, int exit) {
   1157   LOG(INFO) << __func__ << " on " << link_name();
   1158   OnPPPDisconnected();
   1159 }
   1160 
   1161 void Cellular::UpdateScanning() {
   1162   if (proposed_scan_in_progress_) {
   1163     set_scanning(true);
   1164     return;
   1165   }
   1166 
   1167   if (modem_state_ == kModemStateEnabling) {
   1168     set_scanning(true);
   1169     return;
   1170   }
   1171 
   1172   if (service_ && service_->activation_state() != kActivationStateActivated) {
   1173     set_scanning(false);
   1174     return;
   1175   }
   1176 
   1177   if (modem_state_ == kModemStateEnabled ||
   1178       modem_state_ == kModemStateSearching) {
   1179     set_scanning(true);
   1180     return;
   1181   }
   1182 
   1183   set_scanning(false);
   1184 }
   1185 
   1186 void Cellular::RegisterProperties() {
   1187   PropertyStore* store = this->mutable_store();
   1188 
   1189   // These properties do not have setters, and events are not generated when
   1190   // they are changed.
   1191   store->RegisterConstString(kDBusServiceProperty, &dbus_service_);
   1192   store->RegisterConstString(kDBusObjectProperty, &dbus_path_);
   1193 
   1194   store->RegisterUint16(kScanIntervalProperty, &scan_interval_);
   1195 
   1196   // These properties have setters that should be used to change their values.
   1197   // Events are generated whenever the values change.
   1198   store->RegisterConstStringmap(kHomeProviderProperty, &home_provider_);
   1199   store->RegisterConstString(kCarrierProperty, &carrier_);
   1200   store->RegisterConstBool(kSupportNetworkScanProperty, &scanning_supported_);
   1201   store->RegisterConstString(kEsnProperty, &esn_);
   1202   store->RegisterConstString(kFirmwareRevisionProperty, &firmware_revision_);
   1203   store->RegisterConstString(kHardwareRevisionProperty, &hardware_revision_);
   1204   store->RegisterConstString(kImeiProperty, &imei_);
   1205   store->RegisterConstString(kImsiProperty, &imsi_);
   1206   store->RegisterConstString(kMdnProperty, &mdn_);
   1207   store->RegisterConstString(kMeidProperty, &meid_);
   1208   store->RegisterConstString(kMinProperty, &min_);
   1209   store->RegisterConstString(kManufacturerProperty, &manufacturer_);
   1210   store->RegisterConstString(kModelIDProperty, &model_id_);
   1211   store->RegisterConstBool(kScanningProperty, &scanning_);
   1212 
   1213   store->RegisterConstString(kSelectedNetworkProperty, &selected_network_);
   1214   store->RegisterConstStringmaps(kFoundNetworksProperty, &found_networks_);
   1215   store->RegisterConstBool(kProviderRequiresRoamingProperty,
   1216                            &provider_requires_roaming_);
   1217   store->RegisterConstBool(kSIMPresentProperty, &sim_present_);
   1218   store->RegisterConstStringmaps(kCellularApnListProperty, &apn_list_);
   1219   store->RegisterConstString(kIccidProperty, &sim_identifier_);
   1220 
   1221   store->RegisterConstStrings(kSupportedCarriersProperty, &supported_carriers_);
   1222   store->RegisterConstUint16(kPRLVersionProperty, &prl_version_);
   1223 
   1224   // TODO(pprabhu): Decide whether these need their own custom setters.
   1225   HelpRegisterConstDerivedString(kTechnologyFamilyProperty,
   1226                                  &Cellular::GetTechnologyFamily);
   1227   HelpRegisterDerivedBool(kCellularAllowRoamingProperty,
   1228                           &Cellular::GetAllowRoaming,
   1229                           &Cellular::SetAllowRoaming);
   1230 }
   1231 
   1232 void Cellular::set_home_provider(const Stringmap& home_provider) {
   1233   if (home_provider_ == home_provider)
   1234     return;
   1235 
   1236   home_provider_ = home_provider;
   1237   adaptor()->EmitStringmapChanged(kHomeProviderProperty, home_provider_);
   1238 }
   1239 
   1240 void Cellular::set_carrier(const string& carrier) {
   1241   if (carrier_ == carrier)
   1242     return;
   1243 
   1244   carrier_ = carrier;
   1245   adaptor()->EmitStringChanged(kCarrierProperty, carrier_);
   1246 }
   1247 
   1248 void Cellular::set_scanning_supported(bool scanning_supported) {
   1249   if (scanning_supported_ == scanning_supported)
   1250     return;
   1251 
   1252   scanning_supported_ = scanning_supported;
   1253   if (adaptor())
   1254     adaptor()->EmitBoolChanged(kSupportNetworkScanProperty,
   1255                                scanning_supported_);
   1256   else
   1257     SLOG(this, 2) << "Could not emit signal for property |"
   1258                   << kSupportNetworkScanProperty
   1259                   << "| change. DBus adaptor is NULL!";
   1260 }
   1261 
   1262 void Cellular::set_esn(const string& esn) {
   1263   if (esn_ == esn)
   1264     return;
   1265 
   1266   esn_ = esn;
   1267   adaptor()->EmitStringChanged(kEsnProperty, esn_);
   1268 }
   1269 
   1270 void Cellular::set_firmware_revision(const string& firmware_revision) {
   1271   if (firmware_revision_ == firmware_revision)
   1272     return;
   1273 
   1274   firmware_revision_ = firmware_revision;
   1275   adaptor()->EmitStringChanged(kFirmwareRevisionProperty, firmware_revision_);
   1276 }
   1277 
   1278 void Cellular::set_hardware_revision(const string& hardware_revision) {
   1279   if (hardware_revision_ == hardware_revision)
   1280     return;
   1281 
   1282   hardware_revision_ = hardware_revision;
   1283   adaptor()->EmitStringChanged(kHardwareRevisionProperty, hardware_revision_);
   1284 }
   1285 
   1286 // TODO(armansito): The following methods should probably log their argument
   1287 // values. Need to learn if any of them need to be scrubbed.
   1288 void Cellular::set_imei(const string& imei) {
   1289   if (imei_ == imei)
   1290     return;
   1291 
   1292   imei_ = imei;
   1293   adaptor()->EmitStringChanged(kImeiProperty, imei_);
   1294 }
   1295 
   1296 void Cellular::set_imsi(const string& imsi) {
   1297   if (imsi_ == imsi)
   1298     return;
   1299 
   1300   imsi_ = imsi;
   1301   adaptor()->EmitStringChanged(kImsiProperty, imsi_);
   1302 }
   1303 
   1304 void Cellular::set_mdn(const string& mdn) {
   1305   if (mdn_ == mdn)
   1306     return;
   1307 
   1308   mdn_ = mdn;
   1309   adaptor()->EmitStringChanged(kMdnProperty, mdn_);
   1310 }
   1311 
   1312 void Cellular::set_meid(const string& meid) {
   1313   if (meid_ == meid)
   1314     return;
   1315 
   1316   meid_ = meid;
   1317   adaptor()->EmitStringChanged(kMeidProperty, meid_);
   1318 }
   1319 
   1320 void Cellular::set_min(const string& min) {
   1321   if (min_ == min)
   1322     return;
   1323 
   1324   min_ = min;
   1325   adaptor()->EmitStringChanged(kMinProperty, min_);
   1326 }
   1327 
   1328 void Cellular::set_manufacturer(const string& manufacturer) {
   1329   if (manufacturer_ == manufacturer)
   1330     return;
   1331 
   1332   manufacturer_ = manufacturer;
   1333   adaptor()->EmitStringChanged(kManufacturerProperty, manufacturer_);
   1334 }
   1335 
   1336 void Cellular::set_model_id(const string& model_id) {
   1337   if (model_id_ == model_id)
   1338     return;
   1339 
   1340   model_id_ = model_id;
   1341   adaptor()->EmitStringChanged(kModelIDProperty, model_id_);
   1342 }
   1343 
   1344 void Cellular::set_mm_plugin(const string& mm_plugin) {
   1345   mm_plugin_ = mm_plugin;
   1346 }
   1347 
   1348 void Cellular::set_scanning(bool scanning) {
   1349   if (scanning_ == scanning)
   1350     return;
   1351 
   1352   scanning_ = scanning;
   1353   adaptor()->EmitBoolChanged(kScanningProperty, scanning_);
   1354 
   1355   // kScanningProperty is a sticky-false property.
   1356   // Every time it is set to |true|, it will remain |true| up to a maximum of
   1357   // |kScanningTimeout| time, after which it will be reset to |false|.
   1358   if (!scanning_ && !scanning_timeout_callback_.IsCancelled()) {
   1359      SLOG(this, 2) << "Scanning set to false. "
   1360                    << "Cancelling outstanding timeout.";
   1361      scanning_timeout_callback_.Cancel();
   1362   } else {
   1363     CHECK(scanning_timeout_callback_.IsCancelled());
   1364     SLOG(this, 2) << "Scanning set to true. "
   1365                   << "Starting timeout to reset to false.";
   1366     scanning_timeout_callback_.Reset(Bind(&Cellular::set_scanning,
   1367                                           weak_ptr_factory_.GetWeakPtr(),
   1368                                           false));
   1369     dispatcher()->PostDelayedTask(
   1370         scanning_timeout_callback_.callback(),
   1371         scanning_timeout_milliseconds_);
   1372   }
   1373 }
   1374 
   1375 void Cellular::set_selected_network(const string& selected_network) {
   1376   if (selected_network_ == selected_network)
   1377     return;
   1378 
   1379   selected_network_ = selected_network;
   1380   adaptor()->EmitStringChanged(kSelectedNetworkProperty, selected_network_);
   1381 }
   1382 
   1383 void Cellular::set_found_networks(const Stringmaps& found_networks) {
   1384   // There is no canonical form of a Stringmaps value.
   1385   // So don't check for redundant updates.
   1386   found_networks_ = found_networks;
   1387   adaptor()->EmitStringmapsChanged(kFoundNetworksProperty, found_networks_);
   1388 }
   1389 
   1390 void Cellular::clear_found_networks() {
   1391   if (found_networks_.empty())
   1392     return;
   1393 
   1394   found_networks_.clear();
   1395   adaptor()->EmitStringmapsChanged(kFoundNetworksProperty, found_networks_);
   1396 }
   1397 
   1398 void Cellular::set_provider_requires_roaming(bool provider_requires_roaming) {
   1399   if (provider_requires_roaming_ == provider_requires_roaming)
   1400     return;
   1401 
   1402   provider_requires_roaming_ = provider_requires_roaming;
   1403   adaptor()->EmitBoolChanged(kProviderRequiresRoamingProperty,
   1404                              provider_requires_roaming_);
   1405 }
   1406 
   1407 void Cellular::set_sim_present(bool sim_present) {
   1408   if (sim_present_ == sim_present)
   1409     return;
   1410 
   1411   sim_present_ = sim_present;
   1412   adaptor()->EmitBoolChanged(kSIMPresentProperty, sim_present_);
   1413 }
   1414 
   1415 void Cellular::set_apn_list(const Stringmaps& apn_list) {
   1416   // There is no canonical form of a Stringmaps value.
   1417   // So don't check for redundant updates.
   1418   apn_list_ = apn_list;
   1419   // See crbug.com/215581: Sometimes adaptor may be nullptr when |set_apn_list|
   1420   // is called.
   1421   if (adaptor())
   1422     adaptor()->EmitStringmapsChanged(kCellularApnListProperty, apn_list_);
   1423   else
   1424     SLOG(this, 2) << "Could not emit signal for property |"
   1425                   << kCellularApnListProperty
   1426                   << "| change. DBus adaptor is NULL!";
   1427 }
   1428 
   1429 void Cellular::set_sim_identifier(const string& sim_identifier) {
   1430   if (sim_identifier_ == sim_identifier)
   1431     return;
   1432 
   1433   sim_identifier_ = sim_identifier;
   1434   adaptor()->EmitStringChanged(kIccidProperty, sim_identifier_);
   1435 }
   1436 
   1437 void Cellular::set_supported_carriers(const Strings& supported_carriers) {
   1438   // There is no canonical form of a Strings value.
   1439   // So don't check for redundant updates.
   1440   supported_carriers_ = supported_carriers;
   1441   adaptor()->EmitStringsChanged(kSupportedCarriersProperty,
   1442                                 supported_carriers_);
   1443 }
   1444 
   1445 void Cellular::set_prl_version(uint16_t prl_version) {
   1446   if (prl_version_ == prl_version)
   1447     return;
   1448 
   1449   prl_version_ = prl_version;
   1450   adaptor()->EmitUint16Changed(kPRLVersionProperty, prl_version_);
   1451 }
   1452 
   1453 void Cellular::set_home_provider_info(MobileOperatorInfo* home_provider_info) {
   1454   home_provider_info_.reset(home_provider_info);
   1455 }
   1456 
   1457 void Cellular::set_serving_operator_info(
   1458     MobileOperatorInfo* serving_operator_info) {
   1459   serving_operator_info_.reset(serving_operator_info);
   1460 }
   1461 
   1462 void Cellular::UpdateHomeProvider(const MobileOperatorInfo* operator_info) {
   1463   SLOG(this, 3) << __func__;
   1464 
   1465   Stringmap home_provider;
   1466   if (!operator_info->sid().empty()) {
   1467     home_provider[kOperatorCodeKey] = operator_info->sid();
   1468   }
   1469   if (!operator_info->nid().empty()) {
   1470     home_provider[kOperatorCodeKey] = operator_info->nid();
   1471   }
   1472   if (!operator_info->mccmnc().empty()) {
   1473     home_provider[kOperatorCodeKey] = operator_info->mccmnc();
   1474   }
   1475   if (!operator_info->operator_name().empty()) {
   1476     home_provider[kOperatorNameKey] = operator_info->operator_name();
   1477   }
   1478   if (!operator_info->country().empty()) {
   1479     home_provider[kOperatorCountryKey] = operator_info->country();
   1480   }
   1481   set_home_provider(home_provider);
   1482 
   1483   const ScopedVector<MobileOperatorInfo::MobileAPN>& apn_list =
   1484       operator_info->apn_list();
   1485   Stringmaps apn_list_dict;
   1486 
   1487   for (const auto& mobile_apn : apn_list) {
   1488     Stringmap props;
   1489     if (!mobile_apn->apn.empty()) {
   1490       props[kApnProperty] = mobile_apn->apn;
   1491     }
   1492     if (!mobile_apn->username.empty()) {
   1493       props[kApnUsernameProperty] = mobile_apn->username;
   1494     }
   1495     if (!mobile_apn->password.empty()) {
   1496       props[kApnPasswordProperty] = mobile_apn->password;
   1497     }
   1498 
   1499     // Find the first localized and non-localized name, if any.
   1500     if (!mobile_apn->operator_name_list.empty()) {
   1501       props[kApnNameProperty] = mobile_apn->operator_name_list[0].name;
   1502     }
   1503     for (const auto& lname : mobile_apn->operator_name_list) {
   1504       if (!lname.language.empty()) {
   1505         props[kApnLocalizedNameProperty] = lname.name;
   1506       }
   1507     }
   1508 
   1509     apn_list_dict.push_back(props);
   1510   }
   1511   set_apn_list(apn_list_dict);
   1512 
   1513   set_provider_requires_roaming(operator_info->requires_roaming());
   1514 }
   1515 
   1516 void Cellular::UpdateServingOperator(
   1517     const MobileOperatorInfo* operator_info,
   1518     const MobileOperatorInfo* home_provider_info) {
   1519   SLOG(this, 3) << __func__;
   1520   if (!service()) {
   1521     return;
   1522   }
   1523 
   1524   Stringmap serving_operator;
   1525   if (!operator_info->sid().empty()) {
   1526     serving_operator[kOperatorCodeKey] = operator_info->sid();
   1527   }
   1528   if (!operator_info->nid().empty()) {
   1529     serving_operator[kOperatorCodeKey] = operator_info->nid();
   1530   }
   1531   if (!operator_info->mccmnc().empty()) {
   1532     serving_operator[kOperatorCodeKey] = operator_info->mccmnc();
   1533   }
   1534   if (!operator_info->operator_name().empty()) {
   1535     serving_operator[kOperatorNameKey] = operator_info->operator_name();
   1536   }
   1537   if (!operator_info->country().empty()) {
   1538     serving_operator[kOperatorCountryKey] = operator_info->country();
   1539   }
   1540   service()->set_serving_operator(serving_operator);
   1541 
   1542   // Set friendly name of service.
   1543   string service_name;
   1544   if (!operator_info->operator_name().empty()) {
   1545     // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
   1546     // rules (TS 31.102 and annex A of 122.101).
   1547     if (service()->roaming_state() == kRoamingStateRoaming &&
   1548         home_provider_info &&
   1549         !home_provider_info->operator_name().empty()) {
   1550       service_name += home_provider_info->operator_name() + " | ";
   1551     }
   1552     service_name += operator_info->operator_name();
   1553   } else if (!operator_info->mccmnc().empty()) {
   1554     // We could not get a name for the operator, just use the code.
   1555     service_name = "cellular_" + operator_info->mccmnc();
   1556   } else {
   1557     // We do not have any information, so must fallback to default service name.
   1558     // Only assign a new default name if the service doesn't already have one,
   1559     // because we we generate a new name each time.
   1560     service_name = service()->friendly_name();
   1561     if (!IsDefaultFriendlyServiceName(service_name)) {
   1562       service_name = CreateDefaultFriendlyServiceName();
   1563     }
   1564   }
   1565   service()->SetFriendlyName(service_name);
   1566 }
   1567 
   1568 // /////////////////////////////////////////////////////////////////////////////
   1569 // MobileOperatorInfoObserver implementation.
   1570 Cellular::MobileOperatorInfoObserver::MobileOperatorInfoObserver(
   1571     Cellular* cellular)
   1572   : cellular_(cellular),
   1573     capability_(nullptr) {}
   1574 
   1575 Cellular::MobileOperatorInfoObserver::~MobileOperatorInfoObserver() {}
   1576 
   1577 void Cellular::MobileOperatorInfoObserver::OnOperatorChanged() {
   1578   SLOG(cellular_, 3) << __func__;
   1579 
   1580   // Give the capabilities a chance to hook in and update their state.
   1581   // Some tests set |capability_| to nullptr avoid having to expect the full
   1582   // behaviour caused by this call.
   1583   if (capability_) {
   1584     capability_->OnOperatorChanged();
   1585   }
   1586 
   1587   const MobileOperatorInfo* home_provider_info =
   1588       cellular_->home_provider_info();
   1589   const MobileOperatorInfo* serving_operator_info =
   1590       cellular_->serving_operator_info();
   1591 
   1592   const bool home_provider_known =
   1593       home_provider_info->IsMobileNetworkOperatorKnown();
   1594   const bool serving_operator_known =
   1595       serving_operator_info->IsMobileNetworkOperatorKnown();
   1596 
   1597   if (home_provider_known) {
   1598     cellular_->UpdateHomeProvider(home_provider_info);
   1599   } else if (serving_operator_known) {
   1600     SLOG(cellular_, 2) << "Serving provider proxying in for home provider.";
   1601     cellular_->UpdateHomeProvider(serving_operator_info);
   1602   }
   1603 
   1604   if (serving_operator_known) {
   1605     if (home_provider_known) {
   1606       cellular_->UpdateServingOperator(serving_operator_info,
   1607                                        home_provider_info);
   1608     } else {
   1609       cellular_->UpdateServingOperator(serving_operator_info, nullptr);
   1610     }
   1611   } else if (home_provider_known) {
   1612     cellular_->UpdateServingOperator(home_provider_info, home_provider_info);
   1613   }
   1614 }
   1615 
   1616 }  // namespace shill
   1617