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_service.h"
     18 
     19 #include <string>
     20 
     21 #include <base/strings/stringprintf.h>
     22 #if defined(__ANDROID__)
     23 #include <dbus/service_constants.h>
     24 #else
     25 #include <chromeos/dbus/service_constants.h>
     26 #endif  // __ANDROID__
     27 
     28 #include "shill/adaptor_interfaces.h"
     29 #include "shill/cellular/cellular.h"
     30 #include "shill/property_accessor.h"
     31 #include "shill/store_interface.h"
     32 
     33 using std::string;
     34 
     35 namespace shill {
     36 
     37 namespace Logging {
     38 static auto kModuleLogScope = ScopeLogger::kCellular;
     39 static string ObjectID(CellularService* c) { return c->GetRpcIdentifier(); }
     40 }
     41 
     42 // statics
     43 const char CellularService::kAutoConnActivating[] = "activating";
     44 const char CellularService::kAutoConnBadPPPCredentials[] =
     45     "bad PPP credentials";
     46 const char CellularService::kAutoConnDeviceDisabled[] = "device disabled";
     47 const char CellularService::kAutoConnOutOfCredits[] = "device out of credits";
     48 const char CellularService::kAutoConnOutOfCreditsDetectionInProgress[] =
     49     "device detecting out-of-credits";
     50 const char CellularService::kStoragePPPUsername[] = "Cellular.PPP.Username";
     51 const char CellularService::kStoragePPPPassword[] = "Cellular.PPP.Password";
     52 
     53 // TODO(petkov): Add these to system_api/dbus/service_constants.h
     54 namespace {
     55 const char kCellularPPPUsernameProperty[] = "Cellular.PPP.Username";
     56 const char kCellularPPPPasswordProperty[] = "Cellular.PPP.Password";
     57 }  // namespace
     58 
     59 namespace {
     60 const char kStorageAPN[] = "Cellular.APN";
     61 const char kStorageLastGoodAPN[] = "Cellular.LastGoodAPN";
     62 }  // namespace
     63 
     64 static bool GetNonEmptyField(const Stringmap& stringmap,
     65                              const string& fieldname,
     66                              string* value) {
     67   Stringmap::const_iterator it = stringmap.find(fieldname);
     68   if (it != stringmap.end() && !it->second.empty()) {
     69     *value = it->second;
     70     return true;
     71   }
     72   return false;
     73 }
     74 
     75 CellularService::CellularService(ModemInfo* modem_info,
     76                                  const CellularRefPtr& device)
     77     : Service(modem_info->control_interface(), modem_info->dispatcher(),
     78               modem_info->metrics(), modem_info->manager(),
     79               Technology::kCellular),
     80       weak_ptr_factory_(this),
     81       activation_type_(kActivationTypeUnknown),
     82       cellular_(device),
     83       is_auto_connecting_(false) {
     84   SetConnectable(true);
     85   PropertyStore* store = this->mutable_store();
     86   HelpRegisterDerivedString(kActivationTypeProperty,
     87                             &CellularService::CalculateActivationType,
     88                             nullptr);
     89   store->RegisterConstString(kActivationStateProperty, &activation_state_);
     90   HelpRegisterDerivedStringmap(kCellularApnProperty,
     91                                &CellularService::GetApn,
     92                                &CellularService::SetApn);
     93   store->RegisterConstStringmap(kCellularLastGoodApnProperty,
     94                                 &last_good_apn_info_);
     95   store->RegisterConstString(kNetworkTechnologyProperty, &network_technology_);
     96   HelpRegisterDerivedBool(kOutOfCreditsProperty,
     97                           &CellularService::IsOutOfCredits,
     98                           nullptr);
     99   store->RegisterConstStringmap(kPaymentPortalProperty, &olp_);
    100   store->RegisterConstString(kRoamingStateProperty, &roaming_state_);
    101   store->RegisterConstStringmap(kServingOperatorProperty, &serving_operator_);
    102   store->RegisterConstString(kUsageURLProperty, &usage_url_);
    103   store->RegisterString(kCellularPPPUsernameProperty, &ppp_username_);
    104   store->RegisterWriteOnlyString(kCellularPPPPasswordProperty, &ppp_password_);
    105 
    106   set_friendly_name(cellular_->CreateDefaultFriendlyServiceName());
    107   SetStorageIdentifier(string(kTypeCellular) + "_" +
    108                        cellular_->address() + "_" + friendly_name());
    109   // Assume we are not performing any out-of-credits detection.
    110   // The capability can reinitialize with the appropriate type later.
    111   InitOutOfCreditsDetection(OutOfCreditsDetector::OOCTypeNone);
    112 }
    113 
    114 CellularService::~CellularService() { }
    115 
    116 bool CellularService::IsAutoConnectable(const char** reason) const {
    117   if (!cellular_->running()) {
    118     *reason = kAutoConnDeviceDisabled;
    119     return false;
    120   }
    121   if (cellular_->IsActivating()) {
    122     *reason = kAutoConnActivating;
    123     return false;
    124   }
    125   if (failure() == kFailurePPPAuth) {
    126     *reason = kAutoConnBadPPPCredentials;
    127     return false;
    128   }
    129   if (out_of_credits_detector_->IsDetecting()) {
    130     *reason = kAutoConnOutOfCreditsDetectionInProgress;
    131     return false;
    132   }
    133   if (out_of_credits_detector_->out_of_credits()) {
    134     *reason = kAutoConnOutOfCredits;
    135     return false;
    136   }
    137   return Service::IsAutoConnectable(reason);
    138 }
    139 
    140 void CellularService::HelpRegisterDerivedString(
    141     const string& name,
    142     string(CellularService::*get)(Error* error),
    143     bool(CellularService::*set)(const string& value, Error* error)) {
    144   mutable_store()->RegisterDerivedString(
    145       name,
    146       StringAccessor(
    147           new CustomAccessor<CellularService, string>(this, get, set)));
    148 }
    149 
    150 void CellularService::HelpRegisterDerivedStringmap(
    151     const string& name,
    152     Stringmap(CellularService::*get)(Error* error),
    153     bool(CellularService::*set)(
    154         const Stringmap& value, Error* error)) {
    155   mutable_store()->RegisterDerivedStringmap(
    156       name,
    157       StringmapAccessor(
    158           new CustomAccessor<CellularService, Stringmap>(this, get, set)));
    159 }
    160 
    161 void CellularService::HelpRegisterDerivedBool(
    162     const string& name,
    163     bool(CellularService::*get)(Error* error),
    164     bool(CellularService::*set)(const bool&, Error*)) {
    165   mutable_store()->RegisterDerivedBool(
    166     name,
    167     BoolAccessor(new CustomAccessor<CellularService, bool>(this, get, set)));
    168 }
    169 
    170 Stringmap* CellularService::GetUserSpecifiedApn() {
    171   Stringmap::iterator it = apn_info_.find(kApnProperty);
    172   if (it == apn_info_.end() || it->second.empty())
    173     return nullptr;
    174   return &apn_info_;
    175 }
    176 
    177 Stringmap* CellularService::GetLastGoodApn() {
    178   Stringmap::iterator it = last_good_apn_info_.find(kApnProperty);
    179   if (it == last_good_apn_info_.end() || it->second.empty())
    180     return nullptr;
    181   return &last_good_apn_info_;
    182 }
    183 
    184 string CellularService::CalculateActivationType(Error* error) {
    185   return GetActivationTypeString();
    186 }
    187 
    188 Stringmap CellularService::GetApn(Error* /*error*/) {
    189   return apn_info_;
    190 }
    191 
    192 bool CellularService::SetApn(const Stringmap& value, Error* error) {
    193   // Only copy in the fields we care about, and validate the contents.
    194   // If the "apn" field is missing or empty, the APN is cleared.
    195   string str;
    196   Stringmap new_apn_info;
    197   if (GetNonEmptyField(value, kApnProperty, &str)) {
    198     new_apn_info[kApnProperty] = str;
    199     if (GetNonEmptyField(value, kApnUsernameProperty, &str))
    200       new_apn_info[kApnUsernameProperty] = str;
    201     if (GetNonEmptyField(value, kApnPasswordProperty, &str))
    202       new_apn_info[kApnPasswordProperty] = str;
    203   }
    204   if (apn_info_ == new_apn_info) {
    205     return false;
    206   }
    207   apn_info_ = new_apn_info;
    208   if (ContainsKey(apn_info_, kApnProperty)) {
    209     // Clear the last good APN, otherwise the one the user just
    210     // set won't be used, since LastGoodApn comes first in the
    211     // search order when trying to connect. Only do this if a
    212     // non-empty user APN has been supplied. If the user APN is
    213     // being cleared, leave LastGoodApn alone.
    214     ClearLastGoodApn();
    215   }
    216   adaptor()->EmitStringmapChanged(kCellularApnProperty, apn_info_);
    217   return true;
    218 }
    219 
    220 void CellularService::SetLastGoodApn(const Stringmap& apn_info) {
    221   last_good_apn_info_ = apn_info;
    222   adaptor()->EmitStringmapChanged(kCellularLastGoodApnProperty,
    223                                   last_good_apn_info_);
    224 }
    225 
    226 void CellularService::ClearLastGoodApn() {
    227   last_good_apn_info_.clear();
    228   adaptor()->EmitStringmapChanged(kCellularLastGoodApnProperty,
    229                                   last_good_apn_info_);
    230 }
    231 
    232 void CellularService::OnAfterResume() {
    233   Service::OnAfterResume();
    234   resume_start_time_ = base::Time::Now();
    235 }
    236 
    237 void CellularService::InitOutOfCreditsDetection(
    238     OutOfCreditsDetector::OOCType ooc_type) {
    239   out_of_credits_detector_.reset(
    240       OutOfCreditsDetector::CreateDetector(ooc_type,
    241                                            dispatcher(),
    242                                            manager(),
    243                                            metrics(),
    244                                            this));
    245 }
    246 
    247 bool CellularService::Load(StoreInterface* storage) {
    248   // Load properties common to all Services.
    249   if (!Service::Load(storage))
    250     return false;
    251 
    252   const string id = GetStorageIdentifier();
    253   LoadApn(storage, id, kStorageAPN, &apn_info_);
    254   LoadApn(storage, id, kStorageLastGoodAPN, &last_good_apn_info_);
    255 
    256   const string old_username = ppp_username_;
    257   const string old_password = ppp_password_;
    258   storage->GetString(id, kStoragePPPUsername, &ppp_username_);
    259   storage->GetString(id, kStoragePPPPassword, &ppp_password_);
    260   if (IsFailed() && failure() == kFailurePPPAuth &&
    261       (old_username != ppp_username_ || old_password != ppp_password_)) {
    262     SetState(kStateIdle);
    263   }
    264   return true;
    265 }
    266 
    267 void CellularService::LoadApn(StoreInterface* storage,
    268                               const string& storage_group,
    269                               const string& keytag,
    270                               Stringmap* apn_info) {
    271   if (!LoadApnField(storage, storage_group, keytag, kApnProperty, apn_info))
    272     return;
    273   LoadApnField(storage, storage_group, keytag, kApnUsernameProperty, apn_info);
    274   LoadApnField(storage, storage_group, keytag, kApnPasswordProperty, apn_info);
    275 }
    276 
    277 bool CellularService::LoadApnField(StoreInterface* storage,
    278                                    const string& storage_group,
    279                                    const string& keytag,
    280                                    const string& apntag,
    281                                    Stringmap* apn_info) {
    282   string value;
    283   if (storage->GetString(storage_group, keytag + "." + apntag, &value) &&
    284       !value.empty()) {
    285     (*apn_info)[apntag] = value;
    286     return true;
    287   }
    288   return false;
    289 }
    290 
    291 bool CellularService::Save(StoreInterface* storage) {
    292   // Save properties common to all Services.
    293   if (!Service::Save(storage))
    294     return false;
    295 
    296   const string id = GetStorageIdentifier();
    297   SaveApn(storage, id, GetUserSpecifiedApn(), kStorageAPN);
    298   SaveApn(storage, id, GetLastGoodApn(), kStorageLastGoodAPN);
    299   SaveString(storage, id, kStoragePPPUsername, ppp_username_, false, true);
    300   SaveString(storage, id, kStoragePPPPassword, ppp_password_, false, true);
    301   return true;
    302 }
    303 
    304 void CellularService::SaveApn(StoreInterface* storage,
    305                               const string& storage_group,
    306                               const Stringmap* apn_info,
    307                               const string& keytag) {
    308   SaveApnField(storage, storage_group, apn_info, keytag, kApnProperty);
    309   SaveApnField(storage, storage_group, apn_info, keytag, kApnUsernameProperty);
    310   SaveApnField(storage, storage_group, apn_info, keytag, kApnPasswordProperty);
    311 }
    312 
    313 void CellularService::SaveApnField(StoreInterface* storage,
    314                                    const string& storage_group,
    315                                    const Stringmap* apn_info,
    316                                    const string& keytag,
    317                                    const string& apntag) {
    318   const string key = keytag + "." + apntag;
    319   string str;
    320   if (apn_info && GetNonEmptyField(*apn_info, apntag, &str))
    321     storage->SetString(storage_group, key, str);
    322   else
    323     storage->DeleteKey(storage_group, key);
    324 }
    325 
    326 bool CellularService::IsOutOfCredits(Error* /*error*/) {
    327   return out_of_credits_detector_->out_of_credits();
    328 }
    329 
    330 void CellularService::set_out_of_credits_detector(
    331     OutOfCreditsDetector* detector) {
    332   out_of_credits_detector_.reset(detector);
    333 }
    334 
    335 void CellularService::SignalOutOfCreditsChanged(bool state) const {
    336   adaptor()->EmitBoolChanged(kOutOfCreditsProperty, state);
    337 }
    338 
    339 void CellularService::AutoConnect() {
    340   is_auto_connecting_ = true;
    341   Service::AutoConnect();
    342   is_auto_connecting_ = false;
    343 }
    344 
    345 void CellularService::Connect(Error* error, const char* reason) {
    346   Service::Connect(error, reason);
    347   cellular_->Connect(error);
    348   if (error->IsFailure())
    349     out_of_credits_detector_->ResetDetector();
    350 }
    351 
    352 void CellularService::Disconnect(Error* error, const char* reason) {
    353   Service::Disconnect(error, reason);
    354   cellular_->Disconnect(error, reason);
    355 }
    356 
    357 void CellularService::ActivateCellularModem(const string& carrier,
    358                                             Error* error,
    359                                             const ResultCallback& callback) {
    360   cellular_->Activate(carrier, error, callback);
    361 }
    362 
    363 void CellularService::CompleteCellularActivation(Error* error) {
    364   cellular_->CompleteActivation(error);
    365 }
    366 
    367 void CellularService::SetState(ConnectState new_state) {
    368   out_of_credits_detector_->NotifyServiceStateChanged(state(), new_state);
    369   Service::SetState(new_state);
    370 }
    371 
    372 void CellularService::SetStorageIdentifier(const string& identifier) {
    373   SLOG(this, 3) << __func__ << ": " << identifier;
    374   storage_identifier_ = identifier;
    375   std::replace_if(storage_identifier_.begin(),
    376                   storage_identifier_.end(),
    377                   &Service::IllegalChar, '_');
    378 }
    379 
    380 string CellularService::GetStorageIdentifier() const {
    381   return storage_identifier_;
    382 }
    383 
    384 string CellularService::GetDeviceRpcId(Error* /*error*/) const {
    385   return cellular_->GetRpcIdentifier();
    386 }
    387 
    388 void CellularService::SetActivationType(ActivationType type) {
    389   if (type == activation_type_) {
    390     return;
    391   }
    392   activation_type_ = type;
    393   adaptor()->EmitStringChanged(kActivationTypeProperty,
    394                                GetActivationTypeString());
    395 }
    396 
    397 string CellularService::GetActivationTypeString() const {
    398   switch (activation_type_) {
    399     case kActivationTypeNonCellular:
    400       return shill::kActivationTypeNonCellular;
    401     case kActivationTypeOMADM:
    402       return shill::kActivationTypeOMADM;
    403     case kActivationTypeOTA:
    404       return shill::kActivationTypeOTA;
    405     case kActivationTypeOTASP:
    406       return shill::kActivationTypeOTASP;
    407     case kActivationTypeUnknown:
    408       return "";
    409     default:
    410       NOTREACHED();
    411       return "";  // Make compiler happy.
    412   }
    413 }
    414 
    415 void CellularService::SetActivationState(const string& state) {
    416   if (state == activation_state_) {
    417     return;
    418   }
    419   activation_state_ = state;
    420   adaptor()->EmitStringChanged(kActivationStateProperty, state);
    421   SetConnectableFull(state != kActivationStateNotActivated);
    422 }
    423 
    424 void CellularService::SetOLP(const string& url,
    425                              const string& method,
    426                              const string& post_data) {
    427   Stringmap olp;
    428   olp[kPaymentPortalURL] = url;
    429   olp[kPaymentPortalMethod] = method;
    430   olp[kPaymentPortalPostData] = post_data;
    431 
    432   if (olp_ == olp) {
    433     return;
    434   }
    435   olp_ = olp;
    436   adaptor()->EmitStringmapChanged(kPaymentPortalProperty, olp);
    437 }
    438 
    439 void CellularService::SetUsageURL(const string& url) {
    440   if (url == usage_url_) {
    441     return;
    442   }
    443   usage_url_ = url;
    444   adaptor()->EmitStringChanged(kUsageURLProperty, url);
    445 }
    446 
    447 void CellularService::SetNetworkTechnology(const string& technology) {
    448   if (technology == network_technology_) {
    449     return;
    450   }
    451   network_technology_ = technology;
    452   adaptor()->EmitStringChanged(kNetworkTechnologyProperty,
    453                                technology);
    454 }
    455 
    456 void CellularService::SetRoamingState(const string& state) {
    457   if (state == roaming_state_) {
    458     return;
    459   }
    460   roaming_state_ = state;
    461   adaptor()->EmitStringChanged(kRoamingStateProperty, state);
    462 }
    463 
    464 void CellularService::set_serving_operator(const Stringmap& serving_operator) {
    465   if (serving_operator_ == serving_operator)
    466     return;
    467 
    468   serving_operator_ = serving_operator;
    469   adaptor()->EmitStringmapChanged(kServingOperatorProperty, serving_operator_);
    470 }
    471 
    472 }  // namespace shill
    473