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_capability_classic.h"
     18 
     19 #include <base/bind.h>
     20 #if defined(__ANDROID__)
     21 #include <dbus/service_constants.h>
     22 #else
     23 #include <chromeos/dbus/service_constants.h>
     24 #endif  // __ANDROID__
     25 
     26 #include "shill/cellular/cellular.h"
     27 #include "shill/cellular/modem_gobi_proxy_interface.h"
     28 #include "shill/control_interface.h"
     29 #include "shill/error.h"
     30 #include "shill/logging.h"
     31 #include "shill/property_accessor.h"
     32 
     33 using base::Bind;
     34 using base::Callback;
     35 using base::Closure;
     36 using std::string;
     37 
     38 namespace shill {
     39 
     40 namespace Logging {
     41 static auto kModuleLogScope = ScopeLogger::kCellular;
     42 static string ObjectID(CellularCapabilityClassic* c) {
     43   return c->cellular()->GetRpcIdentifier();
     44 }
     45 }
     46 
     47 const char CellularCapabilityClassic::kConnectPropertyApn[] = "apn";
     48 const char CellularCapabilityClassic::kConnectPropertyApnUsername[] =
     49     "username";
     50 const char CellularCapabilityClassic::kConnectPropertyApnPassword[] =
     51     "password";
     52 const char CellularCapabilityClassic::kConnectPropertyHomeOnly[] = "home_only";
     53 const char CellularCapabilityClassic::kConnectPropertyPhoneNumber[] = "number";
     54 const char CellularCapabilityClassic::kModemPropertyEnabled[] = "Enabled";
     55 const int CellularCapabilityClassic::kTimeoutSetCarrierMilliseconds = 120000;
     56 
     57 static Cellular::ModemState ConvertClassicToModemState(uint32_t classic_state) {
     58   ModemClassicState cstate = static_cast<ModemClassicState>(classic_state);
     59   switch (cstate) {
     60     case kModemClassicStateUnknown:
     61       return Cellular::kModemStateUnknown;
     62     case kModemClassicStateDisabled:
     63       return Cellular::kModemStateDisabled;
     64     case kModemClassicStateDisabling:
     65       return Cellular::kModemStateDisabling;
     66     case kModemClassicStateEnabling:
     67       return Cellular::kModemStateEnabling;
     68     case kModemClassicStateEnabled:
     69       return Cellular::kModemStateEnabled;
     70     case kModemClassicStateSearching:
     71       return Cellular::kModemStateSearching;
     72     case kModemClassicStateRegistered:
     73       return Cellular::kModemStateRegistered;
     74     case kModemClassicStateDisconnecting:
     75       return Cellular::kModemStateDisconnecting;
     76     case kModemClassicStateConnecting:
     77       return Cellular::kModemStateConnecting;
     78     case kModemClassicStateConnected:
     79       return Cellular::kModemStateConnected;
     80     default:
     81       return Cellular::kModemStateUnknown;
     82   }
     83 }
     84 
     85 CellularCapabilityClassic::CellularCapabilityClassic(
     86     Cellular* cellular,
     87     ControlInterface* control_interface,
     88     ModemInfo* modem_info)
     89     : CellularCapability(cellular, control_interface, modem_info),
     90       weak_ptr_factory_(this) {
     91   // This class is currently instantiated only for Gobi modems so setup the
     92   // supported carriers list appropriately and expose it over RPC.
     93   cellular->set_supported_carriers({kCarrierGenericUMTS,
     94                                     kCarrierSprint,
     95                                     kCarrierVerizon});
     96 }
     97 
     98 CellularCapabilityClassic::~CellularCapabilityClassic() {}
     99 
    100 void CellularCapabilityClassic::InitProxies() {
    101   SLOG(this, 2) << __func__;
    102   proxy_.reset(control_interface()->CreateModemProxy(
    103       cellular()->dbus_path(), cellular()->dbus_service()));
    104   simple_proxy_.reset(control_interface()->CreateModemSimpleProxy(
    105       cellular()->dbus_path(), cellular()->dbus_service()));
    106   proxy_->set_state_changed_callback(
    107       Bind(&CellularCapabilityClassic::OnModemStateChangedSignal,
    108            weak_ptr_factory_.GetWeakPtr()));
    109 }
    110 
    111 void CellularCapabilityClassic::ReleaseProxies() {
    112   SLOG(this, 2) << __func__;
    113   proxy_.reset();
    114   simple_proxy_.reset();
    115   gobi_proxy_.reset();
    116 }
    117 
    118 bool CellularCapabilityClassic::AreProxiesInitialized() const {
    119   return (proxy_.get() && simple_proxy_.get() && gobi_proxy_.get());
    120 }
    121 
    122 void CellularCapabilityClassic::FinishEnable(const ResultCallback& callback) {
    123   // Normally, running the callback is the last thing done in a method.
    124   // In this case, we do it first, because we want to make sure that
    125   // the device is marked as Enabled before the registration state is
    126   // handled. See comment in Cellular::HandleNewRegistrationState.
    127   callback.Run(Error());
    128   GetRegistrationState();
    129   GetSignalQuality();
    130   // We expect the modem to start scanning after it has been enabled.
    131   // Change this if this behavior is no longer the case in the future.
    132   modem_info()->metrics()->NotifyDeviceEnableFinished(
    133       cellular()->interface_index());
    134   modem_info()->metrics()->NotifyDeviceScanStarted(
    135       cellular()->interface_index());
    136 }
    137 
    138 void CellularCapabilityClassic::FinishDisable(const ResultCallback& callback) {
    139   modem_info()->metrics()->NotifyDeviceDisableFinished(
    140       cellular()->interface_index());
    141   ReleaseProxies();
    142   callback.Run(Error());
    143 }
    144 
    145 void CellularCapabilityClassic::RunNextStep(CellularTaskList* tasks) {
    146   CHECK(!tasks->empty());
    147   SLOG(this, 2) << __func__ << ": " << tasks->size() << " remaining tasks";
    148   Closure task = (*tasks)[0];
    149   tasks->erase(tasks->begin());
    150   cellular()->dispatcher()->PostTask(task);
    151 }
    152 
    153 void CellularCapabilityClassic::StepCompletedCallback(
    154     const ResultCallback& callback,
    155     bool ignore_error,
    156     CellularTaskList* tasks,
    157     const Error& error) {
    158   if ((ignore_error || error.IsSuccess()) && !tasks->empty()) {
    159     RunNextStep(tasks);
    160     return;
    161   }
    162   delete tasks;
    163   if (!callback.is_null())
    164     callback.Run(error);
    165 }
    166 
    167 // always called from an async context
    168 void CellularCapabilityClassic::EnableModem(const ResultCallback& callback) {
    169   SLOG(this, 2) << __func__;
    170   CHECK(!callback.is_null());
    171   Error error;
    172   modem_info()->metrics()->NotifyDeviceEnableStarted(
    173       cellular()->interface_index());
    174   proxy_->Enable(true, &error, callback, kTimeoutEnable);
    175   if (error.IsFailure())
    176     callback.Run(error);
    177 }
    178 
    179 // always called from an async context
    180 void CellularCapabilityClassic::DisableModem(const ResultCallback& callback) {
    181   SLOG(this, 2) << __func__;
    182   CHECK(!callback.is_null());
    183   Error error;
    184   modem_info()->metrics()->NotifyDeviceDisableStarted(
    185       cellular()->interface_index());
    186   proxy_->Enable(false, &error, callback, kTimeoutEnable);
    187   if (error.IsFailure())
    188       callback.Run(error);
    189 }
    190 
    191 // always called from an async context
    192 void CellularCapabilityClassic::GetModemStatus(const ResultCallback& callback) {
    193   SLOG(this, 2) << __func__;
    194   CHECK(!callback.is_null());
    195   KeyValueStoreCallback cb = Bind(
    196       &CellularCapabilityClassic::OnGetModemStatusReply,
    197       weak_ptr_factory_.GetWeakPtr(), callback);
    198   Error error;
    199   simple_proxy_->GetModemStatus(&error, cb, kTimeoutDefault);
    200   if (error.IsFailure())
    201       callback.Run(error);
    202 }
    203 
    204 // always called from an async context
    205 void CellularCapabilityClassic::GetModemInfo(const ResultCallback& callback) {
    206   SLOG(this, 2) << __func__;
    207   CHECK(!callback.is_null());
    208   ModemInfoCallback cb = Bind(&CellularCapabilityClassic::OnGetModemInfoReply,
    209                               weak_ptr_factory_.GetWeakPtr(), callback);
    210   Error error;
    211   proxy_->GetModemInfo(&error, cb, kTimeoutDefault);
    212   if (error.IsFailure())
    213       callback.Run(error);
    214 }
    215 
    216 void CellularCapabilityClassic::StopModem(Error* error,
    217                                           const ResultCallback& callback) {
    218   SLOG(this, 2) << __func__;
    219 
    220   CellularTaskList* tasks = new CellularTaskList();
    221   ResultCallback cb =
    222       Bind(&CellularCapabilityClassic::StepCompletedCallback,
    223            weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
    224   ResultCallback cb_ignore_error =
    225       Bind(&CellularCapabilityClassic::StepCompletedCallback,
    226            weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
    227   // TODO(ers): We can skip the call to Disconnect if the modem has
    228   // told us that the modem state is Disabled or Registered.
    229   tasks->push_back(Bind(&CellularCapabilityClassic::Disconnect,
    230                         weak_ptr_factory_.GetWeakPtr(), nullptr,
    231                         cb_ignore_error));
    232   // TODO(ers): We can skip the call to Disable if the modem has
    233   // told us that the modem state is Disabled.
    234   tasks->push_back(Bind(&CellularCapabilityClassic::DisableModem,
    235                         weak_ptr_factory_.GetWeakPtr(), cb));
    236   tasks->push_back(Bind(&CellularCapabilityClassic::FinishDisable,
    237                         weak_ptr_factory_.GetWeakPtr(), cb));
    238 
    239   RunNextStep(tasks);
    240 }
    241 
    242 void CellularCapabilityClassic::Connect(const KeyValueStore& properties,
    243                                         Error* error,
    244                                         const ResultCallback& callback) {
    245   SLOG(this, 2) << __func__;
    246   simple_proxy_->Connect(properties, error, callback, kTimeoutConnect);
    247 }
    248 
    249 void CellularCapabilityClassic::Disconnect(Error* error,
    250                                            const ResultCallback& callback) {
    251   SLOG(this, 2) << __func__;
    252   if (proxy_.get())
    253     proxy_->Disconnect(error, callback, kTimeoutDisconnect);
    254   else
    255     LOG(ERROR) << "No proxy found in disconnect.";
    256 }
    257 
    258 void CellularCapabilityClassic::SetCarrier(const string& carrier,
    259                                            Error* error,
    260                                            const ResultCallback& callback) {
    261   LOG(INFO) << __func__ << "(" << carrier << ")";
    262   if (!gobi_proxy_.get()) {
    263     gobi_proxy_.reset(control_interface()->CreateModemGobiProxy(
    264         cellular()->dbus_path(), cellular()->dbus_service()));
    265   }
    266   CHECK(error);
    267   gobi_proxy_->SetCarrier(carrier, error, callback,
    268                           kTimeoutSetCarrierMilliseconds);
    269 }
    270 
    271 void CellularCapabilityClassic::OnPropertiesChanged(
    272     const std::string& interface,
    273     const KeyValueStore& changed_properties,
    274     const std::vector<std::string>& invalidated_properties) {
    275   SLOG(this, 2) << __func__;
    276   // This solves a bootstrapping problem: If the modem is not yet
    277   // enabled, there are no proxy objects associated with the capability
    278   // object, so modem signals like StateChanged aren't seen. By monitoring
    279   // changes to the Enabled property via the ModemManager, we're able to
    280   // get the initialization process started, which will result in the
    281   // creation of the proxy objects.
    282   //
    283   // We handle all state changes to ENABLED from a disabled state (including,
    284   // UNKNOWN) through Cellular::OnModemStateChanged. This will try to enable
    285   // the device regardless of whether it has been registered with the Manager.
    286   //
    287   // All other state changes are handled from OnModemStateChangedSignal.
    288   if (changed_properties.ContainsBool(kModemPropertyEnabled)) {
    289     bool enabled = changed_properties.GetBool(kModemPropertyEnabled);
    290     SLOG(this, 2) << "Property \"Enabled\" changed: " << enabled;
    291     Cellular::ModemState prev_modem_state = cellular()->modem_state();
    292     if (!Cellular::IsEnabledModemState(prev_modem_state)) {
    293       cellular()->OnModemStateChanged(
    294           enabled ? Cellular::kModemStateEnabled :
    295                     Cellular::kModemStateDisabled);
    296     }
    297   }
    298 }
    299 
    300 void CellularCapabilityClassic::OnGetModemStatusReply(
    301     const ResultCallback& callback,
    302     const KeyValueStore& props,
    303     const Error& error) {
    304   SLOG(this, 2) << __func__ << " error " << error;
    305   if (error.IsSuccess()) {
    306     if (props.ContainsString("carrier")) {
    307       string carrier = props.GetString("carrier");
    308       cellular()->set_carrier(carrier);
    309       cellular()->home_provider_info()->UpdateOperatorName(carrier);
    310     }
    311     if (props.ContainsString("meid")) {
    312       cellular()->set_meid(props.GetString("meid"));
    313     }
    314     if (props.ContainsString("imei")) {
    315      cellular()->set_imei(props.GetString("imei"));
    316     }
    317     if (props.ContainsString(kModemPropertyIMSI)) {
    318       string imsi = props.GetString(kModemPropertyIMSI);
    319       cellular()->set_imsi(imsi);
    320       cellular()->home_provider_info()->UpdateIMSI(imsi);
    321       // We do not currently obtain the IMSI OTA at all. Provide the IMSI from
    322       // the SIM to the serving operator as well to aid in MVNO identification.
    323       cellular()->serving_operator_info()->UpdateIMSI(imsi);
    324     }
    325     if (props.ContainsString("esn")) {
    326       cellular()->set_esn(props.GetString("esn"));
    327     }
    328     if (props.ContainsString("mdn")) {
    329       cellular()->set_mdn(props.GetString("mdn"));
    330     }
    331     if (props.ContainsString("min")) {
    332       cellular()->set_min(props.GetString("min"));
    333     }
    334     if (props.ContainsString("firmware_revision")) {
    335       cellular()->set_firmware_revision(props.GetString("firmware_revision"));
    336     }
    337     UpdateStatus(props);
    338   }
    339   callback.Run(error);
    340 }
    341 
    342 void CellularCapabilityClassic::UpdateStatus(
    343     const KeyValueStore& properties) {
    344   SLOG(this, 3) << __func__;
    345 }
    346 
    347 void CellularCapabilityClassic::OnGetModemInfoReply(
    348     const ResultCallback& callback,
    349     const std::string& manufacturer,
    350     const std::string& modem,
    351     const std::string& version,
    352     const Error& error) {
    353   SLOG(this, 2) << __func__ << "(" << error << ")";
    354   if (error.IsSuccess()) {
    355     cellular()->set_manufacturer(manufacturer);
    356     cellular()->set_model_id(modem);
    357     cellular()->set_hardware_revision(version);
    358     SLOG(this, 2) << __func__ << ": " << manufacturer << ", " << modem << ", "
    359                   << version;
    360   }
    361   callback.Run(error);
    362 }
    363 
    364 void CellularCapabilityClassic::OnModemStateChangedSignal(
    365     uint32_t old_state, uint32_t new_state, uint32_t reason) {
    366   SLOG(this, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
    367                 << reason << ")";
    368   cellular()->OnModemStateChanged(ConvertClassicToModemState(new_state));
    369 }
    370 
    371 }  // namespace shill
    372