Home | History | Annotate | Download | only in cellular
      1 //
      2 // Copyright (C) 2013 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_capability_universal.h"
     18 
     19 #include <base/bind.h>
     20 #include <base/stl_util.h>
     21 #include <base/strings/string_util.h>
     22 #include <base/strings/stringprintf.h>
     23 #if defined(__ANDROID__)
     24 #include <dbus/service_constants.h>
     25 #else
     26 #include <chromeos/dbus/service_constants.h>
     27 #endif  // __ANDROID__
     28 #include <ModemManager/ModemManager.h>
     29 
     30 #include <string>
     31 #include <vector>
     32 
     33 #include "shill/adaptor_interfaces.h"
     34 #include "shill/cellular/cellular_bearer.h"
     35 #include "shill/cellular/cellular_service.h"
     36 #include "shill/cellular/mobile_operator_info.h"
     37 #include "shill/control_interface.h"
     38 #include "shill/dbus_properties_proxy_interface.h"
     39 #include "shill/error.h"
     40 #include "shill/logging.h"
     41 #include "shill/pending_activation_store.h"
     42 #include "shill/property_accessor.h"
     43 
     44 #ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
     45 #error "Do not include mm-modem.h"
     46 #endif
     47 
     48 using base::Bind;
     49 using base::Closure;
     50 using std::string;
     51 using std::vector;
     52 
     53 namespace shill {
     54 
     55 namespace Logging {
     56 static auto kModuleLogScope = ScopeLogger::kCellular;
     57 static string ObjectID(CellularCapabilityUniversal* c) {
     58   return c->cellular()->GetRpcIdentifier();
     59 }
     60 }
     61 
     62 // static
     63 const char CellularCapabilityUniversal::kConnectPin[] = "pin";
     64 const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
     65 const char CellularCapabilityUniversal::kConnectApn[] = "apn";
     66 const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
     67 const char CellularCapabilityUniversal::kConnectUser[] = "user";
     68 const char CellularCapabilityUniversal::kConnectPassword[] = "password";
     69 const char CellularCapabilityUniversal::kConnectNumber[] = "number";
     70 const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
     71     "allow-roaming";
     72 const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
     73 const int64_t CellularCapabilityUniversal::kEnterPinTimeoutMilliseconds = 20000;
     74 const int64_t
     75 CellularCapabilityUniversal::kRegistrationDroppedUpdateTimeoutMilliseconds =
     76     15000;
     77 const char CellularCapabilityUniversal::kRootPath[] = "/";
     78 const char CellularCapabilityUniversal::kStatusProperty[] = "status";
     79 const char CellularCapabilityUniversal::kOperatorLongProperty[] =
     80     "operator-long";
     81 const char CellularCapabilityUniversal::kOperatorShortProperty[] =
     82     "operator-short";
     83 const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
     84     "operator-code";
     85 const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
     86     "access-technology";
     87 const char CellularCapabilityUniversal::kAltairLTEMMPlugin[] = "Altair LTE";
     88 const char CellularCapabilityUniversal::kNovatelLTEMMPlugin[] = "Novatel LTE";
     89 const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
     90     20000;
     91 
     92 namespace {
     93 
     94 const char kPhoneNumber[] = "*99#";
     95 
     96 // This identifier is specified in the serviceproviders.prototxt file.
     97 const char kVzwIdentifier[] = "c83d6597-dc91-4d48-a3a7-d86b80123751";
     98 const size_t kVzwMdnLength = 10;
     99 
    100 string AccessTechnologyToString(uint32_t access_technologies) {
    101   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
    102     return kNetworkTechnologyLte;
    103   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
    104                               MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
    105                               MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
    106     return kNetworkTechnologyEvdo;
    107   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
    108     return kNetworkTechnology1Xrtt;
    109   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
    110     return kNetworkTechnologyHspaPlus;
    111   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
    112                               MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
    113                               MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
    114     return kNetworkTechnologyHspa;
    115   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
    116     return kNetworkTechnologyUmts;
    117   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
    118     return kNetworkTechnologyEdge;
    119   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
    120     return kNetworkTechnologyGprs;
    121   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
    122                               MM_MODEM_ACCESS_TECHNOLOGY_GSM))
    123       return kNetworkTechnologyGsm;
    124   return "";
    125 }
    126 
    127 string AccessTechnologyToTechnologyFamily(uint32_t access_technologies) {
    128   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
    129                              MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
    130                              MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
    131                              MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
    132                              MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
    133                              MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
    134                              MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
    135                              MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
    136                              MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
    137                              MM_MODEM_ACCESS_TECHNOLOGY_GSM))
    138     return kTechnologyFamilyGsm;
    139   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
    140                              MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
    141                              MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
    142                              MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
    143     return kTechnologyFamilyCdma;
    144   return "";
    145 }
    146 
    147 }  // namespace
    148 
    149 CellularCapabilityUniversal::CellularCapabilityUniversal(
    150     Cellular* cellular,
    151     ControlInterface* control_interface,
    152     ModemInfo* modem_info)
    153     : CellularCapability(cellular, control_interface, modem_info),
    154       mobile_operator_info_(new MobileOperatorInfo(cellular->dispatcher(),
    155                                                    "ParseScanResult")),
    156       weak_ptr_factory_(this),
    157       registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
    158       current_capabilities_(MM_MODEM_CAPABILITY_NONE),
    159       access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
    160       resetting_(false),
    161       subscription_state_(kSubscriptionStateUnknown),
    162       reset_done_(false),
    163       registration_dropped_update_timeout_milliseconds_(
    164           kRegistrationDroppedUpdateTimeoutMilliseconds) {
    165   SLOG(this, 2) << "Cellular capability constructed: Universal";
    166   mobile_operator_info_->Init();
    167   HelpRegisterConstDerivedKeyValueStore(
    168       kSIMLockStatusProperty,
    169       &CellularCapabilityUniversal::SimLockStatusToProperty);
    170 }
    171 
    172 CellularCapabilityUniversal::~CellularCapabilityUniversal() {}
    173 
    174 KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
    175     Error* /*error*/) {
    176   KeyValueStore status;
    177   string lock_type;
    178   switch (sim_lock_status_.lock_type) {
    179     case MM_MODEM_LOCK_SIM_PIN:
    180       lock_type = "sim-pin";
    181       break;
    182     case MM_MODEM_LOCK_SIM_PUK:
    183       lock_type = "sim-puk";
    184       break;
    185     default:
    186       lock_type = "";
    187       break;
    188   }
    189   status.SetBool(kSIMLockEnabledProperty, sim_lock_status_.enabled);
    190   status.SetString(kSIMLockTypeProperty, lock_type);
    191   status.SetUint(kSIMLockRetriesLeftProperty, sim_lock_status_.retries_left);
    192   return status;
    193 }
    194 
    195 void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
    196     const string& name,
    197     KeyValueStore(CellularCapabilityUniversal::*get)(Error* error)) {
    198   cellular()->mutable_store()->RegisterDerivedKeyValueStore(
    199       name,
    200       KeyValueStoreAccessor(
    201           new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
    202               this, get, nullptr)));
    203 }
    204 
    205 void CellularCapabilityUniversal::InitProxies() {
    206   modem_3gpp_proxy_.reset(
    207       control_interface()->CreateMM1ModemModem3gppProxy(
    208           cellular()->dbus_path(), cellular()->dbus_service()));
    209   modem_proxy_.reset(
    210       control_interface()->CreateMM1ModemProxy(cellular()->dbus_path(),
    211                                                cellular()->dbus_service()));
    212   modem_simple_proxy_.reset(
    213       control_interface()->CreateMM1ModemSimpleProxy(
    214           cellular()->dbus_path(), cellular()->dbus_service()));
    215 
    216   modem_proxy_->set_state_changed_callback(
    217       Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
    218            weak_ptr_factory_.GetWeakPtr()));
    219   // Do not create a SIM proxy until the device is enabled because we
    220   // do not yet know the object path of the sim object.
    221   // TODO(jglasgow): register callbacks
    222 }
    223 
    224 void CellularCapabilityUniversal::StartModem(Error* error,
    225                                              const ResultCallback& callback) {
    226   SLOG(this, 3) << __func__;
    227   InitProxies();
    228   deferred_enable_modem_callback_.Reset();
    229   EnableModem(true, error, callback);
    230 }
    231 
    232 void CellularCapabilityUniversal::EnableModem(bool deferrable,
    233                                               Error* error,
    234                                               const ResultCallback& callback) {
    235   SLOG(this, 3) << __func__ << "(deferrable=" << deferrable << ")";
    236   CHECK(!callback.is_null());
    237   Error local_error(Error::kOperationInitiated);
    238   modem_info()->metrics()->NotifyDeviceEnableStarted(
    239       cellular()->interface_index());
    240   modem_proxy_->Enable(
    241       true,
    242       &local_error,
    243       Bind(&CellularCapabilityUniversal::EnableModemCompleted,
    244            weak_ptr_factory_.GetWeakPtr(), deferrable, callback),
    245       kTimeoutEnable);
    246   if (local_error.IsFailure()) {
    247     SLOG(this, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
    248   }
    249   if (error) {
    250     error->CopyFrom(local_error);
    251   }
    252 }
    253 
    254 void CellularCapabilityUniversal::EnableModemCompleted(
    255     bool deferrable, const ResultCallback& callback, const Error& error) {
    256   SLOG(this, 3) << __func__ << "(deferrable=" << deferrable
    257                             << ", error=" << error << ")";
    258 
    259   // If the enable operation failed with Error::kWrongState, the modem is not
    260   // in the expected state (i.e. disabled). If |deferrable| indicates that the
    261   // enable operation can be deferred, we defer the operation until the modem
    262   // goes into the expected state (see OnModemStateChangedSignal).
    263   //
    264   // Note that when the SIM is locked, the enable operation also fails with
    265   // Error::kWrongState. The enable operation is deferred until the modem goes
    266   // into the disabled state after the SIM is unlocked. We may choose not to
    267   // defer the enable operation when the SIM is locked, but the UI needs to
    268   // trigger the enable operation after the SIM is unlocked, which is currently
    269   // not the case.
    270   if (error.IsFailure()) {
    271     if (!deferrable || error.type() != Error::kWrongState) {
    272       callback.Run(error);
    273       return;
    274     }
    275 
    276     if (deferred_enable_modem_callback_.is_null()) {
    277       SLOG(this, 2) << "Defer enable operation.";
    278       // The Enable operation to be deferred should not be further deferrable.
    279       deferred_enable_modem_callback_ =
    280           Bind(&CellularCapabilityUniversal::EnableModem,
    281                weak_ptr_factory_.GetWeakPtr(),
    282                false,  // non-deferrable
    283                nullptr,
    284                callback);
    285     }
    286     return;
    287   }
    288 
    289   // After modem is enabled, it should be possible to get properties
    290   // TODO(jglasgow): handle errors from GetProperties
    291   GetProperties();
    292   // We expect the modem to start scanning after it has been enabled.
    293   // Change this if this behavior is no longer the case in the future.
    294   modem_info()->metrics()->NotifyDeviceEnableFinished(
    295       cellular()->interface_index());
    296   modem_info()->metrics()->NotifyDeviceScanStarted(
    297       cellular()->interface_index());
    298   callback.Run(error);
    299 }
    300 
    301 void CellularCapabilityUniversal::StopModem(Error* error,
    302                                             const ResultCallback& callback) {
    303   CHECK(!callback.is_null());
    304   CHECK(error);
    305   // If there is an outstanding registration change, simply ignore it since
    306   // the service will be destroyed anyway.
    307   if (!registration_dropped_update_callback_.IsCancelled()) {
    308     registration_dropped_update_callback_.Cancel();
    309     SLOG(this, 2) << __func__ << " Cancelled delayed deregister.";
    310   }
    311 
    312   // Some modems will implicitly disconnect the bearer when transitioning to
    313   // low power state. For such modems, it's faster to let the modem disconnect
    314   // the bearer. To do that, we just remove the bearer from the list so
    315   // ModemManager doesn't try to disconnect it during disable.
    316   Closure task;
    317   if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
    318     task = Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearer,
    319                 weak_ptr_factory_.GetWeakPtr(),
    320                 callback);
    321   } else {
    322     task = Bind(&CellularCapabilityUniversal::Stop_Disable,
    323                 weak_ptr_factory_.GetWeakPtr(),
    324                 callback);
    325   }
    326   cellular()->dispatcher()->PostTask(task);
    327   deferred_enable_modem_callback_.Reset();
    328 }
    329 
    330 void CellularCapabilityUniversal::Stop_DeleteActiveBearer(
    331     const ResultCallback& callback) {
    332   SLOG(this, 3) << __func__;
    333 
    334   if (!active_bearer_) {
    335     Stop_Disable(callback);
    336     return;
    337   }
    338 
    339   Error error;
    340   modem_proxy_->DeleteBearer(
    341       active_bearer_->dbus_path(), &error,
    342       Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted,
    343            weak_ptr_factory_.GetWeakPtr(), callback),
    344       kTimeoutDefault);
    345   if (error.IsFailure())
    346     callback.Run(error);
    347 }
    348 
    349 void CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted(
    350     const ResultCallback& callback, const Error& error) {
    351   SLOG(this, 3) << __func__;
    352   // Disregard the error from the bearer deletion since the disable will clean
    353   // up any remaining bearers.
    354   Stop_Disable(callback);
    355 }
    356 
    357 void CellularCapabilityUniversal::Stop_Disable(const ResultCallback& callback) {
    358   SLOG(this, 3) << __func__;
    359   Error error;
    360   modem_info()->metrics()->NotifyDeviceDisableStarted(
    361       cellular()->interface_index());
    362   modem_proxy_->Enable(
    363       false, &error,
    364       Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
    365            weak_ptr_factory_.GetWeakPtr(), callback),
    366       kTimeoutEnable);
    367   if (error.IsFailure())
    368     callback.Run(error);
    369 }
    370 
    371 void CellularCapabilityUniversal::Stop_DisableCompleted(
    372     const ResultCallback& callback, const Error& error) {
    373   SLOG(this, 3) << __func__;
    374 
    375   if (error.IsSuccess()) {
    376     // The modem has been successfully disabled, but we still need to power it
    377     // down.
    378     Stop_PowerDown(callback);
    379   } else {
    380     // An error occurred; terminate the disable sequence.
    381     callback.Run(error);
    382   }
    383 }
    384 
    385 void CellularCapabilityUniversal::Stop_PowerDown(
    386     const ResultCallback& callback) {
    387   SLOG(this, 3) << __func__;
    388   Error error;
    389   modem_proxy_->SetPowerState(
    390       MM_MODEM_POWER_STATE_LOW,
    391       &error,
    392       Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
    393            weak_ptr_factory_.GetWeakPtr(), callback),
    394       kSetPowerStateTimeoutMilliseconds);
    395 
    396   if (error.IsFailure())
    397     // This really shouldn't happen, but if it does, report success,
    398     // because a stop initiated power down is only called if the
    399     // modem was successfully disabled, but the failure of this
    400     // operation should still be propagated up as a successful disable.
    401     Stop_PowerDownCompleted(callback, error);
    402 }
    403 
    404 // Note: if we were in the middle of powering down the modem when the
    405 // system suspended, we might not get this event from
    406 // ModemManager. And we might not even get a timeout from dbus-c++,
    407 // because StartModem re-initializes proxies.
    408 void CellularCapabilityUniversal::Stop_PowerDownCompleted(
    409     const ResultCallback& callback,
    410     const Error& error) {
    411   SLOG(this, 3) << __func__;
    412 
    413   if (error.IsFailure())
    414     SLOG(this, 2) << "Ignoring error returned by SetPowerState: " << error;
    415 
    416   // Since the disable succeeded, if power down fails, we currently fail
    417   // silently, i.e. we need to report the disable operation as having
    418   // succeeded.
    419   modem_info()->metrics()->NotifyDeviceDisableFinished(
    420       cellular()->interface_index());
    421   ReleaseProxies();
    422   callback.Run(Error());
    423 }
    424 
    425 void CellularCapabilityUniversal::Connect(const KeyValueStore& properties,
    426                                           Error* error,
    427                                           const ResultCallback& callback) {
    428   SLOG(this, 3) << __func__;
    429   RpcIdentifierCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
    430                                   weak_ptr_factory_.GetWeakPtr(),
    431                                   callback);
    432   modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
    433 }
    434 
    435 void CellularCapabilityUniversal::Disconnect(Error* error,
    436                                              const ResultCallback& callback) {
    437   SLOG(this, 3) << __func__;
    438   if (modem_simple_proxy_.get()) {
    439     SLOG(this, 2) << "Disconnect all bearers.";
    440     // If "/" is passed as the bearer path, ModemManager will disconnect all
    441     // bearers.
    442     modem_simple_proxy_->Disconnect(kRootPath,
    443                                     error,
    444                                     callback,
    445                                     kTimeoutDisconnect);
    446   }
    447 }
    448 
    449 void CellularCapabilityUniversal::CompleteActivation(Error* error) {
    450   SLOG(this, 3) << __func__;
    451 
    452   // Persist the ICCID as "Pending Activation".
    453   // We're assuming that when this function gets called,
    454   // |cellular()->sim_identifier()| will be non-empty. We still check here that
    455   // is non-empty, though something is wrong if it is empty.
    456   const string& sim_identifier = cellular()->sim_identifier();
    457   if (sim_identifier.empty()) {
    458     SLOG(this, 2) << "SIM identifier not available. Nothing to do.";
    459     return;
    460   }
    461 
    462   modem_info()->pending_activation_store()->SetActivationState(
    463       PendingActivationStore::kIdentifierICCID,
    464       sim_identifier,
    465       PendingActivationStore::kStatePending);
    466   UpdatePendingActivationState();
    467 
    468   SLOG(this, 2) << "Resetting modem for activation.";
    469   ResetAfterActivation();
    470 }
    471 
    472 void CellularCapabilityUniversal::ResetAfterActivation() {
    473   SLOG(this, 3) << __func__;
    474 
    475   // Here the initial call to Reset might fail in rare cases. Simply ignore.
    476   Error error;
    477   ResultCallback callback = Bind(
    478       &CellularCapabilityUniversal::OnResetAfterActivationReply,
    479       weak_ptr_factory_.GetWeakPtr());
    480   Reset(&error, callback);
    481   if (error.IsFailure())
    482     SLOG(this, 2) << "Failed to reset after activation.";
    483 }
    484 
    485 void CellularCapabilityUniversal::OnResetAfterActivationReply(
    486     const Error& error) {
    487   SLOG(this, 3) << __func__;
    488   if (error.IsFailure()) {
    489     SLOG(this, 2) << "Failed to reset after activation. Try again later.";
    490     // TODO(armansito): Maybe post a delayed reset task?
    491     return;
    492   }
    493   reset_done_ = true;
    494   UpdatePendingActivationState();
    495 }
    496 
    497 void CellularCapabilityUniversal::UpdatePendingActivationState() {
    498   SLOG(this, 3) << __func__;
    499 
    500   const string& sim_identifier = cellular()->sim_identifier();
    501   bool registered =
    502       registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
    503 
    504   // We know a service is activated if |subscription_state_| is
    505   // kSubscriptionStateProvisioned / kSubscriptionStateOutOfData
    506   // In the case that |subscription_state_| is kSubscriptionStateUnknown, we
    507   // fallback on checking for a valid MDN.
    508   bool activated =
    509     ((subscription_state_ == kSubscriptionStateProvisioned) ||
    510      (subscription_state_ == kSubscriptionStateOutOfData)) ||
    511     ((subscription_state_ == kSubscriptionStateUnknown) && IsMdnValid());
    512 
    513   if (activated && !sim_identifier.empty())
    514       modem_info()->pending_activation_store()->RemoveEntry(
    515           PendingActivationStore::kIdentifierICCID,
    516           sim_identifier);
    517 
    518   CellularServiceRefPtr service = cellular()->service();
    519 
    520   if (!service.get())
    521     return;
    522 
    523   if (service->activation_state() == kActivationStateActivated)
    524       // Either no service or already activated. Nothing to do.
    525       return;
    526 
    527   // If the ICCID is not available, the following logic can be delayed until it
    528   // becomes available.
    529   if (sim_identifier.empty())
    530     return;
    531 
    532   PendingActivationStore::State state =
    533       modem_info()->pending_activation_store()->GetActivationState(
    534           PendingActivationStore::kIdentifierICCID,
    535           sim_identifier);
    536   switch (state) {
    537     case PendingActivationStore::kStatePending:
    538       // Always mark the service as activating here, as the ICCID could have
    539       // been unavailable earlier.
    540       service->SetActivationState(kActivationStateActivating);
    541       if (reset_done_) {
    542         SLOG(this, 2) << "Post-payment activation reset complete.";
    543         modem_info()->pending_activation_store()->SetActivationState(
    544             PendingActivationStore::kIdentifierICCID,
    545             sim_identifier,
    546             PendingActivationStore::kStateActivated);
    547       }
    548       break;
    549     case PendingActivationStore::kStateActivated:
    550       if (registered) {
    551         // Trigger auto connect here.
    552         SLOG(this, 2) << "Modem has been reset at least once, try to "
    553                       << "autoconnect to force MDN to update.";
    554         service->AutoConnect();
    555       }
    556       break;
    557     case PendingActivationStore::kStateUnknown:
    558       // No entry exists for this ICCID. Nothing to do.
    559       break;
    560     default:
    561       NOTREACHED();
    562   }
    563 }
    564 
    565 string CellularCapabilityUniversal::GetMdnForOLP(
    566     const MobileOperatorInfo* operator_info) const {
    567   // TODO(benchan): This is ugly. Remove carrier specific code once we move
    568   // mobile activation logic to carrier-specifc extensions (crbug.com/260073).
    569   const string& mdn = cellular()->mdn();
    570   if (!operator_info->IsMobileNetworkOperatorKnown()) {
    571     // Can't make any carrier specific modifications.
    572     return mdn;
    573   }
    574 
    575   if (operator_info->uuid() == kVzwIdentifier) {
    576     // subscription_state_ is the definitive indicator of whether we need
    577     // activation. The OLP expects an all zero MDN in that case.
    578     if (subscription_state_ == kSubscriptionStateUnprovisioned || mdn.empty()) {
    579       return string(kVzwMdnLength, '0');
    580     }
    581     if (mdn.length() > kVzwMdnLength) {
    582       return mdn.substr(mdn.length() - kVzwMdnLength);
    583     }
    584   }
    585   return mdn;
    586 }
    587 
    588 void CellularCapabilityUniversal::ReleaseProxies() {
    589   SLOG(this, 3) << __func__;
    590   modem_3gpp_proxy_.reset();
    591   modem_proxy_.reset();
    592   modem_simple_proxy_.reset();
    593   sim_proxy_.reset();
    594 }
    595 
    596 bool CellularCapabilityUniversal::AreProxiesInitialized() const {
    597   return (modem_3gpp_proxy_.get() && modem_proxy_.get() &&
    598           modem_simple_proxy_.get() && sim_proxy_.get());
    599 }
    600 
    601 void CellularCapabilityUniversal::UpdateServiceActivationState() {
    602   if (!cellular()->service().get())
    603     return;
    604 
    605   const string& sim_identifier = cellular()->sim_identifier();
    606   string activation_state;
    607   PendingActivationStore::State state =
    608       modem_info()->pending_activation_store()->GetActivationState(
    609           PendingActivationStore::kIdentifierICCID,
    610           sim_identifier);
    611   if ((subscription_state_ == kSubscriptionStateUnknown ||
    612        subscription_state_ == kSubscriptionStateUnprovisioned) &&
    613       !sim_identifier.empty() &&
    614       state == PendingActivationStore::kStatePending) {
    615     activation_state = kActivationStateActivating;
    616   } else if (IsServiceActivationRequired()) {
    617     activation_state = kActivationStateNotActivated;
    618   } else {
    619     activation_state = kActivationStateActivated;
    620 
    621     // Mark an activated service for auto-connect by default. Since data from
    622     // the user profile will be loaded after the call to OnServiceCreated, this
    623     // property will be corrected based on the user data at that time.
    624     // NOTE: This function can be called outside the service initialization
    625     // path so make sure we don't overwrite the auto-connect setting.
    626     if (cellular()->service()->activation_state() != activation_state)
    627       cellular()->service()->SetAutoConnect(true);
    628   }
    629   cellular()->service()->SetActivationState(activation_state);
    630 }
    631 
    632 void CellularCapabilityUniversal::OnServiceCreated() {
    633   cellular()->service()->SetActivationType(CellularService::kActivationTypeOTA);
    634   UpdateServiceActivationState();
    635 
    636   // WORKAROUND:
    637   // E362 modems on Verizon network does not properly redirect when a SIM
    638   // runs out of credits, we need to enforce out-of-credits detection.
    639   //
    640   // The out-of-credits detection is also needed on ALT3100 modems until the PCO
    641   // support is ready (crosbug.com/p/20461).
    642   cellular()->service()->InitOutOfCreditsDetection(
    643       GetOutOfCreditsDetectionType());
    644 
    645   // Make sure that the network technology is set when the service gets
    646   // created, just in case.
    647   cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
    648 }
    649 
    650 // Create the list of APNs to try, in the following order:
    651 // - last APN that resulted in a successful connection attempt on the
    652 //   current network (if any)
    653 // - the APN, if any, that was set by the user
    654 // - the list of APNs found in the mobile broadband provider DB for the
    655 //   home provider associated with the current SIM
    656 // - as a last resort, attempt to connect with no APN
    657 void CellularCapabilityUniversal::SetupApnTryList() {
    658   apn_try_list_.clear();
    659 
    660   DCHECK(cellular()->service().get());
    661   const Stringmap* apn_info = cellular()->service()->GetLastGoodApn();
    662   if (apn_info)
    663     apn_try_list_.push_back(*apn_info);
    664 
    665   apn_info = cellular()->service()->GetUserSpecifiedApn();
    666   if (apn_info)
    667     apn_try_list_.push_back(*apn_info);
    668 
    669   apn_try_list_.insert(apn_try_list_.end(),
    670                        cellular()->apn_list().begin(),
    671                        cellular()->apn_list().end());
    672 }
    673 
    674 void CellularCapabilityUniversal::SetupConnectProperties(
    675     KeyValueStore* properties) {
    676   SetupApnTryList();
    677   FillConnectPropertyMap(properties);
    678 }
    679 
    680 void CellularCapabilityUniversal::FillConnectPropertyMap(
    681     KeyValueStore* properties) {
    682 
    683   // TODO(jglasgow): Is this really needed anymore?
    684   properties->SetString(kConnectNumber, kPhoneNumber);
    685 
    686   properties->SetBool(kConnectAllowRoaming, AllowRoaming());
    687 
    688   if (!apn_try_list_.empty()) {
    689     // Leave the APN at the front of the list, so that it can be recorded
    690     // if the connect attempt succeeds.
    691     Stringmap apn_info = apn_try_list_.front();
    692     SLOG(this, 2) << __func__ << ": Using APN " << apn_info[kApnProperty];
    693     properties->SetString(kConnectApn, apn_info[kApnProperty]);
    694     if (ContainsKey(apn_info, kApnUsernameProperty))
    695       properties->SetString(kConnectUser, apn_info[kApnUsernameProperty]);
    696     if (ContainsKey(apn_info, kApnPasswordProperty))
    697       properties->SetString(kConnectPassword, apn_info[kApnPasswordProperty]);
    698   }
    699 }
    700 
    701 void CellularCapabilityUniversal::OnConnectReply(const ResultCallback& callback,
    702                                                  const string& path,
    703                                                  const Error& error) {
    704   SLOG(this, 3) << __func__ << "(" << error << ")";
    705 
    706   CellularServiceRefPtr service = cellular()->service();
    707   if (!service) {
    708     // The service could have been deleted before our Connect() request
    709     // completes if the modem was enabled and then quickly disabled.
    710     apn_try_list_.clear();
    711   } else if (error.IsFailure()) {
    712     service->ClearLastGoodApn();
    713     // The APN that was just tried (and failed) is still at the
    714     // front of the list, about to be removed. If the list is empty
    715     // after that, try one last time without an APN. This may succeed
    716     // with some modems in some cases.
    717     if (RetriableConnectError(error) && !apn_try_list_.empty()) {
    718       apn_try_list_.pop_front();
    719       SLOG(this, 2) << "Connect failed with invalid APN, "
    720                     << apn_try_list_.size() << " remaining APNs to try";
    721       KeyValueStore props;
    722       FillConnectPropertyMap(&props);
    723       Error error;
    724       Connect(props, &error, callback);
    725       return;
    726     }
    727   } else {
    728     if (!apn_try_list_.empty()) {
    729       service->SetLastGoodApn(apn_try_list_.front());
    730       apn_try_list_.clear();
    731     }
    732     SLOG(this, 2) << "Connected bearer " << path;
    733   }
    734 
    735   if (!callback.is_null())
    736     callback.Run(error);
    737 
    738   UpdatePendingActivationState();
    739 }
    740 
    741 bool CellularCapabilityUniversal::AllowRoaming() {
    742   return cellular()->provider_requires_roaming() || allow_roaming_property();
    743 }
    744 
    745 void CellularCapabilityUniversal::GetProperties() {
    746   SLOG(this, 3) << __func__;
    747 
    748   std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
    749       control_interface()->CreateDBusPropertiesProxy(
    750           cellular()->dbus_path(), cellular()->dbus_service()));
    751 
    752   KeyValueStore properties(
    753       properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
    754   OnModemPropertiesChanged(properties, vector<string>());
    755 
    756   properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
    757   OnModem3GPPPropertiesChanged(properties, vector<string>());
    758 }
    759 
    760 void CellularCapabilityUniversal::UpdateServiceOLP() {
    761   SLOG(this, 3) << __func__;
    762 
    763   // OLP is based off of the Home Provider.
    764   if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown()) {
    765     return;
    766   }
    767 
    768   const vector<MobileOperatorInfo::OnlinePortal>& olp_list =
    769       cellular()->home_provider_info()->olp_list();
    770   if (olp_list.empty()) {
    771     return;
    772   }
    773 
    774   if (olp_list.size() > 1) {
    775     SLOG(this, 1) << "Found multiple online portals. Choosing the first.";
    776   }
    777   string post_data = olp_list[0].post_data;
    778   base::ReplaceSubstringsAfterOffset(
    779       &post_data, 0, "${iccid}", cellular()->sim_identifier());
    780   base::ReplaceSubstringsAfterOffset(
    781       &post_data, 0, "${imei}", cellular()->imei());
    782   base::ReplaceSubstringsAfterOffset(
    783       &post_data, 0, "${imsi}", cellular()->imsi());
    784   base::ReplaceSubstringsAfterOffset(
    785       &post_data, 0, "${mdn}", GetMdnForOLP(cellular()->home_provider_info()));
    786   base::ReplaceSubstringsAfterOffset(
    787       &post_data, 0, "${min}", cellular()->min());
    788   cellular()->service()->SetOLP(olp_list[0].url, olp_list[0].method, post_data);
    789 }
    790 
    791 void CellularCapabilityUniversal::UpdateActiveBearer() {
    792   SLOG(this, 3) << __func__;
    793 
    794   // Look for the first active bearer and use its path as the connected
    795   // one. Right now, we don't allow more than one active bearer.
    796   active_bearer_.reset();
    797   for (const auto& path : bearer_paths_) {
    798     std::unique_ptr<CellularBearer> bearer(
    799         new CellularBearer(control_interface(),
    800                            path,
    801                            cellular()->dbus_service()));
    802     // The bearer object may have vanished before ModemManager updates the
    803     // 'Bearers' property.
    804     if (!bearer->Init())
    805       continue;
    806 
    807     if (!bearer->connected())
    808       continue;
    809 
    810     SLOG(this, 2) << "Found active bearer \"" << path << "\".";
    811     CHECK(!active_bearer_) << "Found more than one active bearer.";
    812     active_bearer_ = std::move(bearer);
    813   }
    814 
    815   if (!active_bearer_)
    816     SLOG(this, 2) << "No active bearer found.";
    817 }
    818 
    819 bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
    820   const string& sim_identifier = cellular()->sim_identifier();
    821   // subscription_state_ is the definitive answer. If that does not work,
    822   // fallback on MDN based logic.
    823   if (subscription_state_ == kSubscriptionStateProvisioned ||
    824       subscription_state_ == kSubscriptionStateOutOfData)
    825     return false;
    826 
    827   // We are in the process of activating, ignore all other clues from the
    828   // network and use our own knowledge about the activation state.
    829   if (!sim_identifier.empty() &&
    830       modem_info()->pending_activation_store()->GetActivationState(
    831           PendingActivationStore::kIdentifierICCID,
    832           sim_identifier) != PendingActivationStore::kStateUnknown)
    833     return false;
    834 
    835   // Network notification that the service needs to be activated.
    836   if (subscription_state_ == kSubscriptionStateUnprovisioned)
    837     return true;
    838 
    839   // If there is no online payment portal information, it's safer to assume
    840   // the service does not require activation.
    841   if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown() ||
    842       cellular()->home_provider_info()->olp_list().empty()) {
    843     return false;
    844   }
    845 
    846   // If the MDN is invalid (i.e. empty or contains only zeros), the service
    847   // requires activation.
    848   return !IsMdnValid();
    849 }
    850 
    851 bool CellularCapabilityUniversal::IsMdnValid() const {
    852   const string& mdn = cellular()->mdn();
    853   // Note that |mdn| is normalized to contain only digits in OnMdnChanged().
    854   for (size_t i = 0; i < mdn.size(); ++i) {
    855     if (mdn[i] != '0')
    856       return true;
    857   }
    858   return false;
    859 }
    860 
    861 // always called from an async context
    862 void CellularCapabilityUniversal::Register(const ResultCallback& callback) {
    863   SLOG(this, 3) << __func__ << " \"" << cellular()->selected_network()
    864                             << "\"";
    865   CHECK(!callback.is_null());
    866   Error error;
    867   ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
    868                                 weak_ptr_factory_.GetWeakPtr(), callback);
    869   modem_3gpp_proxy_->Register(cellular()->selected_network(), &error, cb,
    870                               kTimeoutRegister);
    871   if (error.IsFailure())
    872     callback.Run(error);
    873 }
    874 
    875 void CellularCapabilityUniversal::RegisterOnNetwork(
    876     const string& network_id,
    877     Error* error,
    878     const ResultCallback& callback) {
    879   SLOG(this, 3) << __func__ << "(" << network_id << ")";
    880   CHECK(error);
    881   desired_network_ = network_id;
    882   ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
    883                                 weak_ptr_factory_.GetWeakPtr(), callback);
    884   modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
    885 }
    886 
    887 void CellularCapabilityUniversal::OnRegisterReply(
    888     const ResultCallback& callback,
    889     const Error& error) {
    890   SLOG(this, 3) << __func__ << "(" << error << ")";
    891 
    892   if (error.IsSuccess()) {
    893     cellular()->set_selected_network(desired_network_);
    894     desired_network_.clear();
    895     callback.Run(error);
    896     return;
    897   }
    898   // If registration on the desired network failed,
    899   // try to register on the home network.
    900   if (!desired_network_.empty()) {
    901     desired_network_.clear();
    902     cellular()->set_selected_network("");
    903     LOG(INFO) << "Couldn't register on selected network, trying home network";
    904     Register(callback);
    905     return;
    906   }
    907   callback.Run(error);
    908 }
    909 
    910 bool CellularCapabilityUniversal::IsRegistered() const {
    911   return IsRegisteredState(registration_state_);
    912 }
    913 
    914 bool CellularCapabilityUniversal::IsRegisteredState(
    915     MMModem3gppRegistrationState state) {
    916   return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
    917           state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
    918 }
    919 
    920 void CellularCapabilityUniversal::SetUnregistered(bool searching) {
    921   // If we're already in some non-registered state, don't override that
    922   if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
    923           registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
    924     registration_state_ =
    925         (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
    926                      MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
    927   }
    928 }
    929 
    930 void CellularCapabilityUniversal::RequirePIN(
    931     const string& pin, bool require,
    932     Error* error, const ResultCallback& callback) {
    933   CHECK(error);
    934   sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
    935 }
    936 
    937 void CellularCapabilityUniversal::EnterPIN(const string& pin,
    938                                            Error* error,
    939                                            const ResultCallback& callback) {
    940   CHECK(error);
    941   SLOG(this, 3) << __func__;
    942   sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
    943 }
    944 
    945 void CellularCapabilityUniversal::UnblockPIN(const string& unblock_code,
    946                                              const string& pin,
    947                                              Error* error,
    948                                              const ResultCallback& callback) {
    949   CHECK(error);
    950   sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
    951 }
    952 
    953 void CellularCapabilityUniversal::ChangePIN(
    954     const string& old_pin, const string& new_pin,
    955     Error* error, const ResultCallback& callback) {
    956   CHECK(error);
    957   sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
    958 }
    959 
    960 void CellularCapabilityUniversal::Reset(Error* error,
    961                                         const ResultCallback& callback) {
    962   SLOG(this, 3) << __func__;
    963   CHECK(error);
    964   if (resetting_) {
    965     Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress,
    966                           "Already resetting");
    967     return;
    968   }
    969   ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
    970                            weak_ptr_factory_.GetWeakPtr(), callback);
    971   modem_proxy_->Reset(error, cb, kTimeoutReset);
    972   if (!error->IsFailure()) {
    973     resetting_ = true;
    974   }
    975 }
    976 
    977 void CellularCapabilityUniversal::OnResetReply(const ResultCallback& callback,
    978                                                const Error& error) {
    979   SLOG(this, 3) << __func__;
    980   resetting_ = false;
    981   if (!callback.is_null())
    982     callback.Run(error);
    983 }
    984 
    985 void CellularCapabilityUniversal::Scan(
    986     Error* error,
    987     const ResultStringmapsCallback& callback) {
    988   KeyValueStoresCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
    989                                    weak_ptr_factory_.GetWeakPtr(), callback);
    990   modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
    991 }
    992 
    993 void CellularCapabilityUniversal::OnScanReply(
    994     const ResultStringmapsCallback& callback,
    995     const ScanResults& results,
    996     const Error& error) {
    997   Stringmaps found_networks;
    998   for (const auto& result : results)
    999     found_networks.push_back(ParseScanResult(result));
   1000   callback.Run(found_networks, error);
   1001 }
   1002 
   1003 Stringmap CellularCapabilityUniversal::ParseScanResult(
   1004     const ScanResult& result) {
   1005 
   1006   /* ScanResults contain the following keys:
   1007 
   1008      "status"
   1009      A MMModem3gppNetworkAvailability value representing network
   1010      availability status, given as an unsigned integer (signature "u").
   1011      This key will always be present.
   1012 
   1013      "operator-long"
   1014      Long-format name of operator, given as a string value (signature
   1015      "s"). If the name is unknown, this field should not be present.
   1016 
   1017      "operator-short"
   1018      Short-format name of operator, given as a string value
   1019      (signature "s"). If the name is unknown, this field should not
   1020      be present.
   1021 
   1022      "operator-code"
   1023      Mobile code of the operator, given as a string value (signature
   1024      "s"). Returned in the format "MCCMNC", where MCC is the
   1025      three-digit ITU E.212 Mobile Country Code and MNC is the two- or
   1026      three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
   1027 
   1028      "access-technology"
   1029      A MMModemAccessTechnology value representing the generic access
   1030      technology used by this mobile network, given as an unsigned
   1031      integer (signature "u").
   1032   */
   1033   Stringmap parsed;
   1034 
   1035   if (result.ContainsUint(kStatusProperty)) {
   1036     uint32_t status = result.GetUint(kStatusProperty);
   1037     // numerical values are taken from 3GPP TS 27.007 Section 7.3.
   1038     static const char* const kStatusString[] = {
   1039       "unknown",    // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
   1040       "available",  // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
   1041       "current",    // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
   1042       "forbidden",  // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
   1043     };
   1044     parsed[kStatusProperty] = kStatusString[status];
   1045   }
   1046 
   1047   // MMModemAccessTechnology
   1048   if (result.ContainsUint(kOperatorAccessTechnologyProperty)) {
   1049     parsed[kTechnologyProperty] =
   1050         AccessTechnologyToString(
   1051             result.GetUint(kOperatorAccessTechnologyProperty));
   1052   }
   1053 
   1054   string operator_long, operator_short, operator_code;
   1055   if (result.ContainsString(kOperatorLongProperty))
   1056     parsed[kLongNameProperty] = result.GetString(kOperatorLongProperty);
   1057   if (result.ContainsString(kOperatorShortProperty))
   1058     parsed[kShortNameProperty] = result.GetString(kOperatorShortProperty);
   1059   if (result.ContainsString(kOperatorCodeProperty))
   1060     parsed[kNetworkIdProperty] = result.GetString(kOperatorCodeProperty);
   1061 
   1062   // If the long name is not available but the network ID is, look up the long
   1063   // name in the mobile provider database.
   1064   if ((!ContainsKey(parsed, kLongNameProperty) ||
   1065        parsed[kLongNameProperty].empty()) &&
   1066       ContainsKey(parsed, kNetworkIdProperty)) {
   1067     mobile_operator_info_->Reset();
   1068     mobile_operator_info_->UpdateMCCMNC(parsed[kNetworkIdProperty]);
   1069     if (mobile_operator_info_->IsMobileNetworkOperatorKnown() &&
   1070         !mobile_operator_info_->operator_name().empty()) {
   1071       parsed[kLongNameProperty] = mobile_operator_info_->operator_name();
   1072     }
   1073   }
   1074   return parsed;
   1075 }
   1076 
   1077 CellularBearer* CellularCapabilityUniversal::GetActiveBearer() const {
   1078   return active_bearer_.get();
   1079 }
   1080 
   1081 string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
   1082   // If we know that the modem is an E362 modem supported by the Novatel LTE
   1083   // plugin, return LTE here to make sure that Chrome sees LTE as the network
   1084   // technology even if the actual technology is unknown.
   1085   //
   1086   // This hack will cause the UI to display LTE even if the modem doesn't
   1087   // support it at a given time. This might be problematic if we ever want to
   1088   // support switching between access technologies (e.g. falling back to 3G
   1089   // when LTE is not available).
   1090   if (cellular()->mm_plugin() == kNovatelLTEMMPlugin)
   1091     return kNetworkTechnologyLte;
   1092 
   1093   // Order is important.  Return the highest speed technology
   1094   // TODO(jglasgow): change shill interfaces to a capability model
   1095   return AccessTechnologyToString(access_technologies_);
   1096 }
   1097 
   1098 string CellularCapabilityUniversal::GetRoamingStateString() const {
   1099   switch (registration_state_) {
   1100     case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
   1101       return kRoamingStateHome;
   1102     case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
   1103       return kRoamingStateRoaming;
   1104     default:
   1105       break;
   1106   }
   1107   return kRoamingStateUnknown;
   1108 }
   1109 
   1110 // TODO(armansito): Remove this method once cromo is deprecated.
   1111 void CellularCapabilityUniversal::GetSignalQuality() {
   1112   // ModemManager always returns the cached value, so there is no need to
   1113   // trigger an update here. The true value is updated through a property
   1114   // change signal.
   1115 }
   1116 
   1117 string CellularCapabilityUniversal::GetTypeString() const {
   1118   return AccessTechnologyToTechnologyFamily(access_technologies_);
   1119 }
   1120 
   1121 void CellularCapabilityUniversal::OnModemPropertiesChanged(
   1122     const KeyValueStore& properties,
   1123     const vector<string>& /* invalidated_properties */) {
   1124 
   1125   // Update the bearers property before the modem state property as
   1126   // OnModemStateChanged may call UpdateActiveBearer, which reads the bearers
   1127   // property.
   1128   if (properties.ContainsRpcIdentifiers(MM_MODEM_PROPERTY_BEARERS)) {
   1129     RpcIdentifiers bearers =
   1130         properties.GetRpcIdentifiers(MM_MODEM_PROPERTY_BEARERS);
   1131     OnBearersChanged(bearers);
   1132   }
   1133 
   1134   // This solves a bootstrapping problem: If the modem is not yet
   1135   // enabled, there are no proxy objects associated with the capability
   1136   // object, so modem signals like StateChanged aren't seen. By monitoring
   1137   // changes to the State property via the ModemManager, we're able to
   1138   // get the initialization process started, which will result in the
   1139   // creation of the proxy objects.
   1140   //
   1141   // The first time we see the change to State (when the modem state
   1142   // is Unknown), we simply update the state, and rely on the Manager to
   1143   // enable the device when it is registered with the Manager. On subsequent
   1144   // changes to State, we need to explicitly enable the device ourselves.
   1145   if (properties.ContainsInt(MM_MODEM_PROPERTY_STATE)) {
   1146     int32_t istate = properties.GetInt(MM_MODEM_PROPERTY_STATE);
   1147     Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
   1148     OnModemStateChanged(state);
   1149   }
   1150   if (properties.ContainsRpcIdentifier(MM_MODEM_PROPERTY_SIM))
   1151     OnSimPathChanged(properties.GetRpcIdentifier(MM_MODEM_PROPERTY_SIM));
   1152 
   1153   if (properties.ContainsUint32s(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES)) {
   1154     OnSupportedCapabilitesChanged(
   1155         properties.GetUint32s(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES));
   1156   }
   1157 
   1158   if (properties.ContainsUint(MM_MODEM_PROPERTY_CURRENTCAPABILITIES)) {
   1159     OnModemCurrentCapabilitiesChanged(
   1160         properties.GetUint(MM_MODEM_PROPERTY_CURRENTCAPABILITIES));
   1161   }
   1162   // not needed: MM_MODEM_PROPERTY_MAXBEARERS
   1163   // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
   1164   if (properties.ContainsString(MM_MODEM_PROPERTY_MANUFACTURER)) {
   1165     cellular()->set_manufacturer(
   1166         properties.GetString(MM_MODEM_PROPERTY_MANUFACTURER));
   1167   }
   1168   if (properties.ContainsString(MM_MODEM_PROPERTY_MODEL)) {
   1169     cellular()->set_model_id(properties.GetString(MM_MODEM_PROPERTY_MODEL));
   1170   }
   1171   if (properties.ContainsString(MM_MODEM_PROPERTY_PLUGIN)) {
   1172     cellular()->set_mm_plugin(properties.GetString(MM_MODEM_PROPERTY_PLUGIN));
   1173   }
   1174   if (properties.ContainsString(MM_MODEM_PROPERTY_REVISION)) {
   1175     OnModemRevisionChanged(properties.GetString(MM_MODEM_PROPERTY_REVISION));
   1176   }
   1177   // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
   1178   // not needed: MM_MODEM_PROPERTY_DEVICE
   1179   // not needed: MM_MODEM_PROPERTY_DRIVER
   1180   // not needed: MM_MODEM_PROPERTY_PLUGIN
   1181   // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
   1182 
   1183   // Unlock required and SimLock
   1184   bool lock_status_changed = false;
   1185   if (properties.ContainsUint(MM_MODEM_PROPERTY_UNLOCKREQUIRED)) {
   1186     uint32_t unlock_required =
   1187         properties.GetUint(MM_MODEM_PROPERTY_UNLOCKREQUIRED);
   1188     OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
   1189     lock_status_changed = true;
   1190   }
   1191 
   1192   // Unlock retries
   1193   if (properties.Contains(MM_MODEM_PROPERTY_UNLOCKRETRIES)) {
   1194     OnLockRetriesChanged(
   1195         properties.Get(MM_MODEM_PROPERTY_UNLOCKRETRIES).Get<LockRetryData>());
   1196     lock_status_changed = true;
   1197   }
   1198 
   1199   if (lock_status_changed)
   1200     OnSimLockStatusChanged();
   1201 
   1202   if (properties.ContainsUint(MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES)) {
   1203     OnAccessTechnologiesChanged(
   1204         properties.GetUint(MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES));
   1205   }
   1206 
   1207   if (properties.Contains(MM_MODEM_PROPERTY_SIGNALQUALITY)) {
   1208     SignalQuality quality =
   1209         properties.Get(MM_MODEM_PROPERTY_SIGNALQUALITY).Get<SignalQuality>();
   1210     OnSignalQualityChanged(std::get<0>(quality));
   1211   }
   1212 
   1213   if (properties.ContainsStrings(MM_MODEM_PROPERTY_OWNNUMBERS)) {
   1214     vector<string> numbers =
   1215         properties.GetStrings(MM_MODEM_PROPERTY_OWNNUMBERS);
   1216     string mdn;
   1217     if (numbers.size() > 0)
   1218       mdn = numbers[0];
   1219     OnMdnChanged(mdn);
   1220   }
   1221 
   1222   if (properties.Contains(MM_MODEM_PROPERTY_SUPPORTEDMODES)) {
   1223     SupportedModes mm_supported_modes =
   1224         properties.Get(MM_MODEM_PROPERTY_SUPPORTEDMODES).Get<SupportedModes>();
   1225     vector<ModemModes> supported_modes;
   1226     for (const auto& modes : mm_supported_modes) {
   1227       supported_modes.push_back(
   1228           ModemModes(std::get<0>(modes),
   1229                      static_cast<MMModemMode>(std::get<1>(modes))));
   1230     }
   1231     OnSupportedModesChanged(supported_modes);
   1232   }
   1233 
   1234   if (properties.Contains(MM_MODEM_PROPERTY_CURRENTMODES)) {
   1235     ModesData current_modes =
   1236         properties.Get(MM_MODEM_PROPERTY_CURRENTMODES).Get<ModesData>();
   1237     OnCurrentModesChanged(
   1238         ModemModes(std::get<0>(current_modes),
   1239                    static_cast<MMModemMode>(std::get<1>(current_modes))));
   1240   }
   1241 
   1242   // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
   1243   // au: MM_MODEM_PROPERTY_BANDS
   1244 }
   1245 
   1246 void CellularCapabilityUniversal::OnPropertiesChanged(
   1247     const string& interface,
   1248     const KeyValueStore& changed_properties,
   1249     const vector<string>& invalidated_properties) {
   1250   SLOG(this, 3) << __func__ << "(" << interface << ")";
   1251   if (interface == MM_DBUS_INTERFACE_MODEM) {
   1252     OnModemPropertiesChanged(changed_properties, invalidated_properties);
   1253   }
   1254   if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
   1255     OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
   1256   }
   1257   if (interface == MM_DBUS_INTERFACE_SIM) {
   1258     OnSimPropertiesChanged(changed_properties, invalidated_properties);
   1259   }
   1260 }
   1261 
   1262 bool CellularCapabilityUniversal::RetriableConnectError(
   1263     const Error& error) const {
   1264   if (error.type() == Error::kInvalidApn)
   1265     return true;
   1266 
   1267   // ModemManager does not ever return kInvalidApn for an E362 modem (with
   1268   // firmware version 1.41) supported by the Novatel LTE plugin.
   1269   if ((cellular()->mm_plugin() == kNovatelLTEMMPlugin) &&
   1270       (error.type() == Error::kOperationFailed)) {
   1271     return true;
   1272   }
   1273   return false;
   1274 }
   1275 
   1276 void CellularCapabilityUniversal::OnNetworkModeSignal(uint32_t /*mode*/) {
   1277   // TODO(petkov): Implement this.
   1278   NOTIMPLEMENTED();
   1279 }
   1280 
   1281 bool CellularCapabilityUniversal::IsValidSimPath(const string& sim_path) const {
   1282   return !sim_path.empty() && sim_path != kRootPath;
   1283 }
   1284 
   1285 string CellularCapabilityUniversal::NormalizeMdn(const string& mdn) const {
   1286   string normalized_mdn;
   1287   for (size_t i = 0; i < mdn.size(); ++i) {
   1288     if (base::IsAsciiDigit(mdn[i]))
   1289       normalized_mdn += mdn[i];
   1290   }
   1291   return normalized_mdn;
   1292 }
   1293 
   1294 void CellularCapabilityUniversal::OnSimPathChanged(
   1295     const string& sim_path) {
   1296   if (sim_path == sim_path_)
   1297     return;
   1298 
   1299   mm1::SimProxyInterface* proxy = nullptr;
   1300   if (IsValidSimPath(sim_path))
   1301     proxy = control_interface()->CreateSimProxy(sim_path,
   1302                                                 cellular()->dbus_service());
   1303   sim_path_ = sim_path;
   1304   sim_proxy_.reset(proxy);
   1305 
   1306   if (!IsValidSimPath(sim_path)) {
   1307     // Clear all data about the sim
   1308     cellular()->set_imsi("");
   1309     spn_ = "";
   1310     cellular()->set_sim_present(false);
   1311     OnSimIdentifierChanged("");
   1312     OnOperatorIdChanged("");
   1313     cellular()->home_provider_info()->Reset();
   1314   } else {
   1315     cellular()->set_sim_present(true);
   1316     std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
   1317         control_interface()->CreateDBusPropertiesProxy(
   1318             sim_path, cellular()->dbus_service()));
   1319     // TODO(jglasgow): convert to async interface
   1320     KeyValueStore properties(properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
   1321     OnSimPropertiesChanged(properties, vector<string>());
   1322   }
   1323 }
   1324 
   1325 void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
   1326     const vector<uint32_t>& supported_capabilities) {
   1327   supported_capabilities_ = supported_capabilities;
   1328 }
   1329 
   1330 void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
   1331     uint32_t current_capabilities) {
   1332   current_capabilities_ = current_capabilities;
   1333 
   1334   // Only allow network scan when the modem's current capabilities support
   1335   // GSM/UMTS.
   1336   //
   1337   // TODO(benchan): We should consider having the modem plugins in ModemManager
   1338   // reporting whether network scan is supported.
   1339   cellular()->set_scanning_supported(
   1340       (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0);
   1341 }
   1342 
   1343 void CellularCapabilityUniversal::OnMdnChanged(
   1344     const string& mdn) {
   1345   cellular()->set_mdn(NormalizeMdn(mdn));
   1346   UpdatePendingActivationState();
   1347 }
   1348 
   1349 void CellularCapabilityUniversal::OnModemRevisionChanged(
   1350     const string& revision) {
   1351   cellular()->set_firmware_revision(revision);
   1352 }
   1353 
   1354 void CellularCapabilityUniversal::OnModemStateChanged(
   1355     Cellular::ModemState state) {
   1356   SLOG(this, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
   1357 
   1358   if (state == Cellular::kModemStateConnected) {
   1359     // This assumes that ModemManager updates the Bearers list and the Bearer
   1360     // properties before changing Modem state to Connected.
   1361     SLOG(this, 2) << "Update active bearer.";
   1362     UpdateActiveBearer();
   1363   }
   1364 
   1365   cellular()->OnModemStateChanged(state);
   1366   // TODO(armansito): Move the deferred enable logic to Cellular
   1367   // (See crbug.com/279499).
   1368   if (!deferred_enable_modem_callback_.is_null() &&
   1369       state == Cellular::kModemStateDisabled) {
   1370     SLOG(this, 2) << "Enabling modem after deferring.";
   1371     deferred_enable_modem_callback_.Run();
   1372     deferred_enable_modem_callback_.Reset();
   1373   }
   1374 }
   1375 
   1376 void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
   1377     uint32_t access_technologies) {
   1378   if (access_technologies_ != access_technologies) {
   1379     const string old_type_string(GetTypeString());
   1380     access_technologies_ = access_technologies;
   1381     const string new_type_string(GetTypeString());
   1382     if (new_type_string != old_type_string) {
   1383       // TODO(jglasgow): address layering violation of emitting change
   1384       // signal here for a property owned by Cellular.
   1385       cellular()->adaptor()->EmitStringChanged(
   1386           kTechnologyFamilyProperty, new_type_string);
   1387     }
   1388     if (cellular()->service().get()) {
   1389       cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
   1390     }
   1391   }
   1392 }
   1393 
   1394 void CellularCapabilityUniversal::OnSupportedModesChanged(
   1395     const vector<ModemModes>& supported_modes) {
   1396   supported_modes_ = supported_modes;
   1397 }
   1398 
   1399 void CellularCapabilityUniversal::OnCurrentModesChanged(
   1400     const ModemModes& current_modes) {
   1401   current_modes_ = current_modes;
   1402 }
   1403 
   1404 void CellularCapabilityUniversal::OnBearersChanged(
   1405     const RpcIdentifiers& bearers) {
   1406   bearer_paths_ = bearers;
   1407 }
   1408 
   1409 void CellularCapabilityUniversal::OnLockRetriesChanged(
   1410     const LockRetryData& lock_retries) {
   1411   SLOG(this, 3) << __func__;
   1412 
   1413   // Look for the retries left for the current lock. Try the obtain the count
   1414   // that matches the current count. If no count for the current lock is
   1415   // available, report the first one in the dictionary.
   1416   LockRetryData::const_iterator it =
   1417       lock_retries.find(sim_lock_status_.lock_type);
   1418   if (it == lock_retries.end())
   1419       it = lock_retries.begin();
   1420   if (it != lock_retries.end())
   1421     sim_lock_status_.retries_left = it->second;
   1422   else
   1423     // Unknown, use 999
   1424     sim_lock_status_.retries_left = 999;
   1425 }
   1426 
   1427 void CellularCapabilityUniversal::OnLockTypeChanged(
   1428     MMModemLock lock_type) {
   1429   SLOG(this, 3) << __func__ << ": " << lock_type;
   1430   sim_lock_status_.lock_type = lock_type;
   1431 
   1432   // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
   1433   // This is because the corresponding property 'EnabledFacilityLocks' is on
   1434   // the 3GPP interface and the 3GPP interface is not available while the Modem
   1435   // is in the 'LOCKED' state.
   1436   if (lock_type != MM_MODEM_LOCK_NONE &&
   1437       lock_type != MM_MODEM_LOCK_UNKNOWN &&
   1438       !sim_lock_status_.enabled)
   1439     sim_lock_status_.enabled = true;
   1440 }
   1441 
   1442 void CellularCapabilityUniversal::OnSimLockStatusChanged() {
   1443   SLOG(this, 3) << __func__;
   1444   cellular()->adaptor()->EmitKeyValueStoreChanged(
   1445       kSIMLockStatusProperty, SimLockStatusToProperty(nullptr));
   1446 
   1447   // If the SIM is currently unlocked, assume that we need to refresh
   1448   // carrier information, since a locked SIM prevents shill from obtaining
   1449   // the necessary data to establish a connection later (e.g. IMSI).
   1450   if (IsValidSimPath(sim_path_) &&
   1451       (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
   1452        sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
   1453     std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
   1454         control_interface()->CreateDBusPropertiesProxy(
   1455             sim_path_, cellular()->dbus_service()));
   1456     KeyValueStore properties(
   1457         properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
   1458     OnSimPropertiesChanged(properties, vector<string>());
   1459   }
   1460 }
   1461 
   1462 void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
   1463     const KeyValueStore& properties,
   1464     const vector<string>& /* invalidated_properties */) {
   1465   SLOG(this, 3) << __func__;
   1466   if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_IMEI))
   1467     cellular()->set_imei(
   1468         properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_IMEI));
   1469 
   1470   // Handle registration state changes as a single change
   1471   Stringmap::const_iterator it;
   1472   string operator_code;
   1473   string operator_name;
   1474   it = serving_operator_.find(kOperatorCodeKey);
   1475   if (it != serving_operator_.end())
   1476     operator_code = it->second;
   1477   it = serving_operator_.find(kOperatorNameKey);
   1478   if (it != serving_operator_.end())
   1479     operator_name = it->second;
   1480 
   1481   MMModem3gppRegistrationState state = registration_state_;
   1482   bool registration_changed = false;
   1483   if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE)) {
   1484     state = static_cast<MMModem3gppRegistrationState>(
   1485         properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE));
   1486     registration_changed = true;
   1487   }
   1488   if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE)) {
   1489     operator_code =
   1490         properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE);
   1491     registration_changed = true;
   1492   }
   1493   if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME)) {
   1494     operator_name =
   1495         properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME);
   1496     registration_changed = true;
   1497   }
   1498   if (registration_changed)
   1499     On3GPPRegistrationChanged(state, operator_code, operator_name);
   1500   if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE))
   1501     On3GPPSubscriptionStateChanged(
   1502         static_cast<MMModem3gppSubscriptionState>(
   1503             properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE)));
   1504 
   1505   CellularServiceRefPtr service = cellular()->service();
   1506   if (service.get() &&
   1507       properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE)) {
   1508     uint32_t subscription_state =
   1509         properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE);
   1510     SLOG(this, 3) << __func__ << ": Subscription state = "
   1511                               << subscription_state;
   1512     service->out_of_credits_detector()->NotifySubscriptionStateChanged(
   1513         subscription_state);
   1514   }
   1515 
   1516   if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS))
   1517     OnFacilityLocksChanged(
   1518         properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS));
   1519 }
   1520 
   1521 void CellularCapabilityUniversal::On3GPPRegistrationChanged(
   1522     MMModem3gppRegistrationState state,
   1523     const string& operator_code,
   1524     const string& operator_name) {
   1525   SLOG(this, 3) << __func__ << ": regstate=" << state
   1526                             << ", opercode=" << operator_code
   1527                             << ", opername=" << operator_name;
   1528 
   1529   // While the modem is connected, if the state changed from a registered state
   1530   // to a non registered state, defer the state change by 15 seconds.
   1531   if (cellular()->modem_state() == Cellular::kModemStateConnected &&
   1532       IsRegistered() && !IsRegisteredState(state)) {
   1533     if (!registration_dropped_update_callback_.IsCancelled()) {
   1534       LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
   1535                    << "Ignoring earlier notifications.";
   1536       registration_dropped_update_callback_.Cancel();
   1537     } else {
   1538       // This is not a repeated post. So, count this instance of delayed drop
   1539       // posted.
   1540       modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
   1541     }
   1542     SLOG(this, 2) << "Posted deferred registration state update";
   1543     registration_dropped_update_callback_.Reset(
   1544         Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
   1545              weak_ptr_factory_.GetWeakPtr(),
   1546              state,
   1547              operator_code,
   1548              operator_name));
   1549     cellular()->dispatcher()->PostDelayedTask(
   1550         registration_dropped_update_callback_.callback(),
   1551         registration_dropped_update_timeout_milliseconds_);
   1552   } else {
   1553     if (!registration_dropped_update_callback_.IsCancelled()) {
   1554       SLOG(this, 2) << "Cancelled a deferred registration state update";
   1555       registration_dropped_update_callback_.Cancel();
   1556       // If we cancelled the callback here, it means we had flaky network for a
   1557       // small duration.
   1558       modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
   1559     }
   1560     Handle3GPPRegistrationChange(state, operator_code, operator_name);
   1561   }
   1562 }
   1563 
   1564 void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
   1565     MMModem3gppRegistrationState updated_state,
   1566     string updated_operator_code,
   1567     string updated_operator_name) {
   1568   // A finished callback does not qualify as a canceled callback.
   1569   // We test for a canceled callback to check for outstanding callbacks.
   1570   // So, explicitly cancel the callback here.
   1571   registration_dropped_update_callback_.Cancel();
   1572 
   1573   SLOG(this, 3) << __func__ << ": regstate=" << updated_state
   1574                             << ", opercode=" << updated_operator_code
   1575                             << ", opername=" << updated_operator_name;
   1576 
   1577   registration_state_ = updated_state;
   1578   serving_operator_[kOperatorCodeKey] = updated_operator_code;
   1579   serving_operator_[kOperatorNameKey] = updated_operator_name;
   1580   cellular()->serving_operator_info()->UpdateMCCMNC(updated_operator_code);
   1581   cellular()->serving_operator_info()->UpdateOperatorName(
   1582       updated_operator_name);
   1583 
   1584   cellular()->HandleNewRegistrationState();
   1585 
   1586   // If the modem registered with the network and the current ICCID is pending
   1587   // activation, then reset the modem.
   1588   UpdatePendingActivationState();
   1589 }
   1590 
   1591 void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged(
   1592     MMModem3gppSubscriptionState updated_state) {
   1593   SLOG(this, 3) << __func__ << ": Updated subscription state = "
   1594                             << updated_state;
   1595 
   1596   // A one-to-one enum mapping.
   1597   SubscriptionState new_subscription_state;
   1598   switch (updated_state) {
   1599     case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN:
   1600       new_subscription_state = kSubscriptionStateUnknown;
   1601       break;
   1602     case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED:
   1603       new_subscription_state = kSubscriptionStateProvisioned;
   1604       break;
   1605     case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED:
   1606       new_subscription_state = kSubscriptionStateUnprovisioned;
   1607       break;
   1608     case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA:
   1609       new_subscription_state = kSubscriptionStateOutOfData;
   1610       break;
   1611     default:
   1612       LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: "
   1613                  << updated_state;
   1614       new_subscription_state = kSubscriptionStateUnknown;
   1615       return;
   1616   }
   1617   if (new_subscription_state == subscription_state_)
   1618     return;
   1619 
   1620   subscription_state_ = new_subscription_state;
   1621 
   1622   UpdateServiceActivationState();
   1623   UpdatePendingActivationState();
   1624 }
   1625 
   1626 void CellularCapabilityUniversal::OnModemStateChangedSignal(
   1627     int32_t old_state, int32_t new_state, uint32_t reason) {
   1628   Cellular::ModemState old_modem_state =
   1629       static_cast<Cellular::ModemState>(old_state);
   1630   Cellular::ModemState new_modem_state =
   1631       static_cast<Cellular::ModemState>(new_state);
   1632   SLOG(this, 3) << __func__ << "("
   1633                             << Cellular::GetModemStateString(old_modem_state)
   1634                             << ", "
   1635                             << Cellular::GetModemStateString(new_modem_state)
   1636                             << ", "
   1637                             << reason << ")";
   1638 }
   1639 
   1640 void CellularCapabilityUniversal::OnSignalQualityChanged(uint32_t quality) {
   1641   cellular()->HandleNewSignalQuality(quality);
   1642 }
   1643 
   1644 void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32_t locks) {
   1645   bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
   1646   if (sim_lock_status_.enabled != sim_enabled) {
   1647     sim_lock_status_.enabled = sim_enabled;
   1648     OnSimLockStatusChanged();
   1649   }
   1650 }
   1651 
   1652 void CellularCapabilityUniversal::OnSimPropertiesChanged(
   1653     const KeyValueStore& props,
   1654     const vector<string>& /* invalidated_properties */) {
   1655   SLOG(this, 3) << __func__;
   1656   if (props.ContainsString(MM_SIM_PROPERTY_SIMIDENTIFIER))
   1657     OnSimIdentifierChanged(props.GetString(MM_SIM_PROPERTY_SIMIDENTIFIER));
   1658   if (props.ContainsString(MM_SIM_PROPERTY_OPERATORIDENTIFIER))
   1659     OnOperatorIdChanged(props.GetString(MM_SIM_PROPERTY_OPERATORIDENTIFIER));
   1660   if (props.ContainsString(MM_SIM_PROPERTY_OPERATORNAME))
   1661     OnSpnChanged(props.GetString(MM_SIM_PROPERTY_OPERATORNAME));
   1662   if (props.ContainsString(MM_SIM_PROPERTY_IMSI)) {
   1663     string imsi = props.GetString(MM_SIM_PROPERTY_IMSI);
   1664     cellular()->set_imsi(imsi);
   1665     cellular()->home_provider_info()->UpdateIMSI(imsi);
   1666     // We do not obtain IMSI OTA right now. Provide the value from the SIM to
   1667     // serving operator as well, to aid in MVNO identification.
   1668     cellular()->serving_operator_info()->UpdateIMSI(imsi);
   1669   }
   1670 }
   1671 
   1672 void CellularCapabilityUniversal::OnSpnChanged(const std::string& spn) {
   1673   spn_ = spn;
   1674   cellular()->home_provider_info()->UpdateOperatorName(spn);
   1675 }
   1676 
   1677 void CellularCapabilityUniversal::OnSimIdentifierChanged(const string& id) {
   1678   cellular()->set_sim_identifier(id);
   1679   cellular()->home_provider_info()->UpdateICCID(id);
   1680   // Provide ICCID to serving operator as well to aid in MVNO identification.
   1681   cellular()->serving_operator_info()->UpdateICCID(id);
   1682   UpdatePendingActivationState();
   1683 }
   1684 
   1685 void CellularCapabilityUniversal::OnOperatorIdChanged(
   1686     const string& operator_id) {
   1687   SLOG(this, 2) << "Operator ID = '" << operator_id << "'";
   1688   cellular()->home_provider_info()->UpdateMCCMNC(operator_id);
   1689 }
   1690 
   1691 OutOfCreditsDetector::OOCType
   1692 CellularCapabilityUniversal::GetOutOfCreditsDetectionType() const {
   1693   if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
   1694     return OutOfCreditsDetector::OOCTypeSubscriptionState;
   1695   } else {
   1696     return OutOfCreditsDetector::OOCTypeNone;
   1697   }
   1698 }
   1699 
   1700 }  // namespace shill
   1701