cellular_service.cc revision 7ea768e15de860c8a27143ead02a8d3f15ab9f47
18a3188dbc04245c17a4729d16a632547ce4bf585mukesh agrawal// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
23bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone// Use of this source code is governed by a BSD-style license that can be
33bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone// found in the LICENSE file.
43bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone
53bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone#include "shill/cellular_service.h"
63bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone
73bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone#include <string>
83bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone
934af218abe6a99144ffe01332ce36fbad94f2628Chris Masone#include <base/stringprintf.h>
103bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone#include <chromeos/dbus/service_constants.h>
113bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone
12b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov#include "shill/adaptor_interfaces.h"
133bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone#include "shill/cellular.h"
1430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood#include "shill/property_accessor.h"
1530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood#include "shill/store_interface.h"
163bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone
173bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masoneusing std::string;
183bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone
193bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masonenamespace shill {
20c5f56564e1594f218c44e9b77c4c6645cd9239e8Darin Petkov
21a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawal// statics
221582bddf620625f9e6f6c407a707d6a916387df1Christopher Wileyconst char CellularService::kAutoConnActivating[] = "activating";
23d47738866711ed29c04a82647d9acb7b8a668924mukesh agrawalconst char CellularService::kAutoConnBadPPPCredentials[] =
24d47738866711ed29c04a82647d9acb7b8a668924mukesh agrawal    "bad PPP credentials";
2519f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chanconst char CellularService::kAutoConnDeviceDisabled[] = "device disabled";
26398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Leconst char CellularService::kAutoConnOutOfCredits[] = "device out of credits";
27398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Leconst char CellularService::kAutoConnOutOfCreditsDetectionInProgress[] =
28398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    "device detecting out-of-credits";
29398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Leconst int64 CellularService::kOutOfCreditsConnectionDropSeconds = 15;
30398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Leconst int CellularService::kOutOfCreditsMaxConnectAttempts = 3;
3199dc56dd45ec8429c3de57365658540820ceb000Thieu Leconst int64 CellularService::kOutOfCreditsResumeIgnoreSeconds = 5;
32a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawalconst char CellularService::kStoragePPPUsername[] = "Cellular.PPP.Username";
33a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawalconst char CellularService::kStoragePPPPassword[] = "Cellular.PPP.Password";
3430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
35381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov// TODO(petkov): Add these to system_api/dbus/service_constants.h
36381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovnamespace {
37381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovconst char kKeyOLPURL[] = "url";
38381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovconst char kKeyOLPMethod[] = "method";
39381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovconst char kKeyOLPPostData[] = "postdata";
403ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawalconst char kCellularPPPUsernameProperty[] = "Cellular.PPP.Username";
413ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawalconst char kCellularPPPPasswordProperty[] = "Cellular.PPP.Password";
423ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawal}  // namespace
433ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawal
443ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawalnamespace {
453ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawalconst char kStorageAPN[] = "Cellular.APN";
463ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawalconst char kStorageLastGoodAPN[] = "Cellular.LastGoodAPN";
4719f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chan}  // namespace
48381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
4930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodstatic bool GetNonEmptyField(const Stringmap &stringmap,
5030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                             const string &fieldname,
5130bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                             string *value) {
5230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  Stringmap::const_iterator it = stringmap.find(fieldname);
5330bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  if (it != stringmap.end() && !it->second.empty()) {
5430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    *value = it->second;
5530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    return true;
5630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  }
5730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  return false;
5830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
5930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
60381928f996d23a21d4cfbed70d07cbf9029f625dDarin PetkovCellularService::OLP::OLP() {
61381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  SetURL("");
62381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  SetMethod("");
63381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  SetPostData("");
64381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
65381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
66381928f996d23a21d4cfbed70d07cbf9029f625dDarin PetkovCellularService::OLP::~OLP() {}
67381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
68381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovvoid CellularService::OLP::CopyFrom(const OLP &olp) {
69381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  dict_ = olp.dict_;
70381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
71381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
72381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovbool CellularService::OLP::Equals(const OLP &olp) const {
73381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  return dict_ == olp.dict_;
74381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
75381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
76381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovconst string &CellularService::OLP::GetURL() const {
77381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  return dict_.find(kKeyOLPURL)->second;
78381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
79381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
80381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovvoid CellularService::OLP::SetURL(const string &url) {
81381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  dict_[kKeyOLPURL] = url;
82381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
83381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
84381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovconst string &CellularService::OLP::GetMethod() const {
85381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  return dict_.find(kKeyOLPMethod)->second;
86381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
87381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
88381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovvoid CellularService::OLP::SetMethod(const string &method) {
89381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  dict_[kKeyOLPMethod] = method;
90381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
91381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
92381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovconst string &CellularService::OLP::GetPostData() const {
93381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  return dict_.find(kKeyOLPPostData)->second;
94381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
95381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
96381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovvoid CellularService::OLP::SetPostData(const string &post_data) {
97381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  dict_[kKeyOLPPostData] = post_data;
98381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
99381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
100381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovconst Stringmap &CellularService::OLP::ToDict() const {
101381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  return dict_;
102381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
103381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
1040d36b4fb5424a4c6f890e65a62a3b29e26eddb7aPrathmesh PrabhuCellularService::CellularService(ModemInfo *modem_info,
10551a7e939ed0d260392a40bc5d58e6d2651c6ddc0mukesh agrawal                                 const CellularRefPtr &device)
1060d36b4fb5424a4c6f890e65a62a3b29e26eddb7aPrathmesh Prabhu    : Service(modem_info->control_interface(), modem_info->dispatcher(),
1070d36b4fb5424a4c6f890e65a62a3b29e26eddb7aPrathmesh Prabhu              modem_info->metrics(), modem_info->manager(),
1083426c8fc7a3943f2d8fcb2ec78f0593088b42bedThieu Le              Technology::kCellular),
109398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      weak_ptr_factory_(this),
1103d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan      activate_over_non_cellular_network_(false),
1117cf36b0cbc1e382fb714cf412d100c9f7ad86c09Thieu Le      cellular_(device),
112398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      is_auto_connecting_(false),
113398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      enforce_out_of_credits_detection_(false),
114398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      num_connect_attempts_(0),
115398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      out_of_credits_detection_in_progress_(false),
116398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      out_of_credits_(false) {
117cbfb34e699532f62eb5b381d0ea3a15d39e00b7cmukesh agrawal  SetConnectable(true);
118de29fa8d95092f28548b5e4537a6c61e21ae760bmukesh agrawal  PropertyStore *store = this->mutable_store();
1193d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan  store->RegisterConstBool(kActivateOverNonCellularNetworkProperty,
1203d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan                           &activate_over_non_cellular_network_);
1217ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  store->RegisterConstString(kActivationStateProperty, &activation_state_);
1227ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  HelpRegisterDerivedStringmap(kCellularApnProperty,
12330bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                               &CellularService::GetApn,
12430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                               &CellularService::SetApn);
1257ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  store->RegisterConstStringmap(kCellularLastGoodApnProperty,
12627c4aa55b33d3a3836cf70c8f7094bce1c5ead8cChris Masone                                &last_good_apn_info_);
1277ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  store->RegisterConstString(kNetworkTechnologyProperty, &network_technology_);
128398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  store->RegisterConstBool(kOutOfCreditsProperty, &out_of_credits_);
1297ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  store->RegisterConstStringmap(kPaymentPortalProperty, &olp_.ToDict());
1307ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  store->RegisterConstString(kRoamingStateProperty, &roaming_state_);
1317ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  store->RegisterConstStringmap(kServingOperatorProperty,
1323335b3773067671301a8a02a1f9eefd17a3ce607Darin Petkov                                &serving_operator_.ToDict());
1337ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  store->RegisterConstString(kUsageURLProperty, &usage_url_);
1343ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawal  store->RegisterString(kCellularPPPUsernameProperty, &ppp_username_);
1353ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawal  store->RegisterWriteOnlyString(kCellularPPPPasswordProperty, &ppp_password_);
136ac635a8fb539fd44f3e24c33872b61fd064c0d60Darin Petkov
137457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov  string name = device->CreateFriendlyServiceName();
138457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov  set_friendly_name(name);
1397ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  SetStorageIdentifier(string(kTypeCellular) + "_" +
140457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov                       device->address() + "_" + name);
1413bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone}
1423bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone
1433bd3c8c33917221d1074f1aa19272e45c0ce2793Chris MasoneCellularService::~CellularService() { }
1443bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone
14519f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chanbool CellularService::IsAutoConnectable(const char **reason) const {
14619f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chan  if (!cellular_->running()) {
14719f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chan    *reason = kAutoConnDeviceDisabled;
14819f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chan    return false;
14919f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chan  }
1501582bddf620625f9e6f6c407a707d6a916387df1Christopher Wiley  if (cellular_->IsActivating()) {
1511582bddf620625f9e6f6c407a707d6a916387df1Christopher Wiley    *reason = kAutoConnActivating;
1521582bddf620625f9e6f6c407a707d6a916387df1Christopher Wiley    return false;
1531582bddf620625f9e6f6c407a707d6a916387df1Christopher Wiley  }
154d47738866711ed29c04a82647d9acb7b8a668924mukesh agrawal  if (failure() == kFailurePPPAuth) {
155d47738866711ed29c04a82647d9acb7b8a668924mukesh agrawal    *reason = kAutoConnBadPPPCredentials;
156d47738866711ed29c04a82647d9acb7b8a668924mukesh agrawal    return false;
157d47738866711ed29c04a82647d9acb7b8a668924mukesh agrawal  }
158398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (out_of_credits_detection_in_progress_) {
159398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    *reason = kAutoConnOutOfCreditsDetectionInProgress;
160398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    return false;
161398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  }
162398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (out_of_credits_) {
163398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    *reason = kAutoConnOutOfCredits;
164398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    return false;
165398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  }
16619f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chan  return Service::IsAutoConnectable(reason);
16719f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chan}
16819f83971a35d7f2c7b08aae6eb0abdc8e52ba057Ben Chan
16930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodvoid CellularService::HelpRegisterDerivedStringmap(
17030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    const string &name,
17130bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    Stringmap(CellularService::*get)(Error *error),
172bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawal    bool(CellularService::*set)(
17330bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood        const Stringmap &value, Error *error)) {
17430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  mutable_store()->RegisterDerivedStringmap(
17530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood      name,
17630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood      StringmapAccessor(
17730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood          new CustomAccessor<CellularService, Stringmap>(this, get, set)));
17830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
17930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
18030bc0ecfcdad79f652eab10c7cda9adca33a04faEric ShienbroodStringmap *CellularService::GetUserSpecifiedApn() {
1817ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  Stringmap::iterator it = apn_info_.find(kApnProperty);
18230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  if (it == apn_info_.end() || it->second.empty())
18330bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    return NULL;
18430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  return &apn_info_;
18530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
18630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
18730bc0ecfcdad79f652eab10c7cda9adca33a04faEric ShienbroodStringmap *CellularService::GetLastGoodApn() {
18830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  Stringmap::iterator it =
1897ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan      last_good_apn_info_.find(kApnProperty);
19030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  if (it == last_good_apn_info_.end() || it->second.empty())
19130bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    return NULL;
19230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  return &last_good_apn_info_;
19330bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
19430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
19530bc0ecfcdad79f652eab10c7cda9adca33a04faEric ShienbroodStringmap CellularService::GetApn(Error */*error*/) {
19630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  return apn_info_;
19730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
19830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
199bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawalbool CellularService::SetApn(const Stringmap &value, Error *error) {
20030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  // Only copy in the fields we care about, and validate the contents.
201c7073307211b6b5a090a14b951524ac210ab1c9cEric Shienbrood  // If the "apn" field is missing or empty, the APN is cleared.
20230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  string str;
203bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawal  Stringmap new_apn_info;
2047ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  if (GetNonEmptyField(value, kApnProperty, &str)) {
2057ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan    new_apn_info[kApnProperty] = str;
2067ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan    if (GetNonEmptyField(value, kApnUsernameProperty, &str))
2077ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan      new_apn_info[kApnUsernameProperty] = str;
2087ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan    if (GetNonEmptyField(value, kApnPasswordProperty, &str))
2097ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan      new_apn_info[kApnPasswordProperty] = str;
210bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawal  }
211bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawal  if (apn_info_ == new_apn_info) {
212bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawal    return false;
213bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawal  }
214bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawal  apn_info_ = new_apn_info;
2157ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  if (ContainsKey(apn_info_, kApnProperty)) {
216c7073307211b6b5a090a14b951524ac210ab1c9cEric Shienbrood    // Clear the last good APN, otherwise the one the user just
217c7073307211b6b5a090a14b951524ac210ab1c9cEric Shienbrood    // set won't be used, since LastGoodApn comes first in the
218c7073307211b6b5a090a14b951524ac210ab1c9cEric Shienbrood    // search order when trying to connect. Only do this if a
219c7073307211b6b5a090a14b951524ac210ab1c9cEric Shienbrood    // non-empty user APN has been supplied. If the user APN is
220c7073307211b6b5a090a14b951524ac210ab1c9cEric Shienbrood    // being cleared, leave LastGoodApn alone.
221c7073307211b6b5a090a14b951524ac210ab1c9cEric Shienbrood    ClearLastGoodApn();
22230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  }
2237ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  adaptor()->EmitStringmapChanged(kCellularApnProperty, apn_info_);
22430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  SaveToCurrentProfile();
225bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawal  return true;
22630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
22730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
22830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodvoid CellularService::SetLastGoodApn(const Stringmap &apn_info) {
22930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  last_good_apn_info_ = apn_info;
2307ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  adaptor()->EmitStringmapChanged(kCellularLastGoodApnProperty,
23130bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                  last_good_apn_info_);
23230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  SaveToCurrentProfile();
23330bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
23430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
23530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodvoid CellularService::ClearLastGoodApn() {
23630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  last_good_apn_info_.clear();
2377ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  adaptor()->EmitStringmapChanged(kCellularLastGoodApnProperty,
23830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                  last_good_apn_info_);
23930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  SaveToCurrentProfile();
24030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
24130bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
24299dc56dd45ec8429c3de57365658540820ceb000Thieu Levoid CellularService::OnAfterResume() {
24399dc56dd45ec8429c3de57365658540820ceb000Thieu Le  Service::OnAfterResume();
24499dc56dd45ec8429c3de57365658540820ceb000Thieu Le  resume_start_time_ = base::Time::Now();
24599dc56dd45ec8429c3de57365658540820ceb000Thieu Le}
24699dc56dd45ec8429c3de57365658540820ceb000Thieu Le
24730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodbool CellularService::Load(StoreInterface *storage) {
24830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  // Load properties common to all Services.
24930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  if (!Service::Load(storage))
25030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    return false;
25130bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
25230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  const string id = GetStorageIdentifier();
25330bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  LoadApn(storage, id, kStorageAPN, &apn_info_);
25430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  LoadApn(storage, id, kStorageLastGoodAPN, &last_good_apn_info_);
255a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawal
256a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawal  const string old_username = ppp_username_;
257a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawal  const string old_password = ppp_password_;
2583ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawal  storage->GetString(id, kStoragePPPUsername, &ppp_username_);
2593ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawal  storage->GetString(id, kStoragePPPPassword, &ppp_password_);
260a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawal  if (IsFailed() && failure() == kFailurePPPAuth &&
261a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawal      (old_username != ppp_username_ || old_password != ppp_password_)) {
262a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawal    SetState(kStateIdle);
263a70ec27425dcc4527ece33c1b95f37129ba26653mukesh agrawal  }
26430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  return true;
26530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
26630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
26730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodvoid CellularService::LoadApn(StoreInterface *storage,
26830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                              const string &storage_group,
26930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                              const string &keytag,
27030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                              Stringmap *apn_info) {
2717ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  if (!LoadApnField(storage, storage_group, keytag, kApnProperty, apn_info))
27230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    return;
2737ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  LoadApnField(storage, storage_group, keytag, kApnUsernameProperty, apn_info);
2747ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  LoadApnField(storage, storage_group, keytag, kApnPasswordProperty, apn_info);
27530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
27630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
27730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodbool CellularService::LoadApnField(StoreInterface *storage,
27830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                   const string &storage_group,
27930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                   const string &keytag,
28030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                   const string &apntag,
28130bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                   Stringmap *apn_info) {
28230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  string value;
28330bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  if (storage->GetString(storage_group, keytag + "." + apntag, &value) &&
28430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood      !value.empty()) {
28530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    (*apn_info)[apntag] = value;
28630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    return true;
28730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  }
28830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  return false;
28930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
29030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
291398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Levoid CellularService::PerformOutOfCreditsDetection(ConnectState curr_state,
292398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le                                                   ConnectState new_state) {
293398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // WORKAROUND:
294398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // Some modems on Verizon network does not properly redirect when a SIM
295398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // runs out of credits.  This workaround is used to detect an out-of-credits
296398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // condition by by retrying a connect request if it was dropped within
297398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // kOutOfCreditsConnectionDropSeconds.  If the number of retries exceeds
298398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // kOutOfCreditsMaxConnectAttempts, then the SIM is considered
299398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // out-of-credits and the cellular service kOutOfCreditsProperty is set.
300398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // This will signal Chrome to display the appropriate UX and also suppress
301398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // auto-connect until the next time the user manually connects.
302398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  //
303398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // TODO(thieule): Remove this workaround (crosbug.com/p/18169).
3043a8683d45789f9ce3f3e5cc82ed4762a7818d7c0Thieu Le  if (out_of_credits_) {
3053a8683d45789f9ce3f3e5cc82ed4762a7818d7c0Thieu Le    SLOG(Cellular, 2) << __func__
3063a8683d45789f9ce3f3e5cc82ed4762a7818d7c0Thieu Le                      << ": Already out-of-credits, skipping check";
3073a8683d45789f9ce3f3e5cc82ed4762a7818d7c0Thieu Le    return;
3083a8683d45789f9ce3f3e5cc82ed4762a7818d7c0Thieu Le  }
309398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  base::TimeDelta
31099dc56dd45ec8429c3de57365658540820ceb000Thieu Le      time_since_resume = base::Time::Now() - resume_start_time_;
31199dc56dd45ec8429c3de57365658540820ceb000Thieu Le  if (time_since_resume.InSeconds() < kOutOfCreditsResumeIgnoreSeconds) {
31299dc56dd45ec8429c3de57365658540820ceb000Thieu Le    // On platforms that power down the modem during suspend, make sure that
31399dc56dd45ec8429c3de57365658540820ceb000Thieu Le    // we do not display a false out-of-credits warning to the user
31499dc56dd45ec8429c3de57365658540820ceb000Thieu Le    // due to the sequence below by skipping out-of-credits detection
31599dc56dd45ec8429c3de57365658540820ceb000Thieu Le    // immediately after a resume.
31699dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //   1. User suspends Chromebook.
31799dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //   2. Hardware turns off power to modem.
31899dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //   3. User resumes Chromebook.
31999dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //   4. Hardware restores power to modem.
32099dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //   5. ModemManager still has instance of old modem.
32199dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //      ModemManager does not delete this instance until udev fires a
32299dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //      device removed event.  ModemManager does not detect new modem
32399dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //      until udev fires a new device event.
32499dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //   6. Shill performs auto-connect against the old modem.
32599dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //      Make sure at this step that we do not display a false
32699dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //      out-of-credits warning.
32799dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //   7. Udev fires device removed event.
32899dc56dd45ec8429c3de57365658540820ceb000Thieu Le    //   8. Udev fires new device event.
32999dc56dd45ec8429c3de57365658540820ceb000Thieu Le    SLOG(Cellular, 2) <<
33099dc56dd45ec8429c3de57365658540820ceb000Thieu Le        "Skipping out-of-credits detection, too soon since resume.";
33199dc56dd45ec8429c3de57365658540820ceb000Thieu Le    ResetOutOfCreditsState();
33299dc56dd45ec8429c3de57365658540820ceb000Thieu Le    return;
33399dc56dd45ec8429c3de57365658540820ceb000Thieu Le  }
33499dc56dd45ec8429c3de57365658540820ceb000Thieu Le  base::TimeDelta
335398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      time_since_connect = base::Time::Now() - connect_start_time_;
336398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (time_since_connect.InSeconds() > kOutOfCreditsConnectionDropSeconds) {
337398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    ResetOutOfCreditsState();
338398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    return;
339398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  }
340398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  // Verizon can drop the connection in two ways:
341398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  //   - Denies the connect request
342398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  //   - Allows connect request but disconnects later
343398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  bool connection_dropped =
344398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      (IsConnectedState(curr_state) || IsConnectingState(curr_state)) &&
345398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      (new_state == kStateFailure || new_state == kStateIdle);
346398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (!connection_dropped)
347398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    return;
348398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (explicitly_disconnected())
349398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    return;
3507ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  if (roaming_state_ == kRoamingStateRoaming &&
351398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      !cellular_->allow_roaming_property())
352398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    return;
353398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (time_since_connect.InSeconds() <= kOutOfCreditsConnectionDropSeconds) {
354398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    if (num_connect_attempts_ < kOutOfCreditsMaxConnectAttempts) {
355398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      SLOG(Cellular, 2) << "Out-Of-Credits detection: Reconnecting "
356398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le                        << "(retry #" << num_connect_attempts_ << ")";
357398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      // Prevent autoconnect logic from kicking in while we perform the
358398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      // out-of-credits detection.
359398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      out_of_credits_detection_in_progress_ = true;
360398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      dispatcher()->PostTask(
361398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le          Bind(&CellularService::OutOfCreditsReconnect,
362398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le               weak_ptr_factory_.GetWeakPtr()));
363398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    } else {
364398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      LOG(ERROR) <<
365398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le          "Out-Of-Credits detection: Marking service as out-of-credits";
36691fccf6ff2ee20d77905ce71a7e9815b2e2c02d7Thieu Le      metrics()->NotifyCellularOutOfCredits(
36791fccf6ff2ee20d77905ce71a7e9815b2e2c02d7Thieu Le          Metrics::kCellularOutOfCreditsReasonConnectDisconnectLoop);
368398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      SetOutOfCredits(true);
369398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le      ResetOutOfCreditsState();
370398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    }
371398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  }
372398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le}
373398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le
374398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Levoid CellularService::OutOfCreditsReconnect() {
375398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  Error error;
376dc7b8447aa220fae51b73fd8610cbfed14ed57fcmukesh agrawal  Connect(&error, __func__);
377398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le}
378398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le
379398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Levoid CellularService::ResetOutOfCreditsState() {
380398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  out_of_credits_detection_in_progress_ = false;
381398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  num_connect_attempts_ = 0;
382398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le}
383398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le
38430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodbool CellularService::Save(StoreInterface *storage) {
38530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  // Save properties common to all Services.
38630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  if (!Service::Save(storage))
38730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    return false;
38830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
38930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  const string id = GetStorageIdentifier();
39030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  SaveApn(storage, id, GetUserSpecifiedApn(), kStorageAPN);
39130bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  SaveApn(storage, id, GetLastGoodApn(), kStorageLastGoodAPN);
3923ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawal  SaveString(storage, id, kStoragePPPUsername, ppp_username_, false, true);
3933ffe52c6eb79db079a8b5685d2c8bd96f6b49b79mukesh agrawal  SaveString(storage, id, kStoragePPPPassword, ppp_password_, false, true);
39430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  return true;
39530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
39630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
39730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodvoid CellularService::SaveApn(StoreInterface *storage,
39830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                              const string &storage_group,
39930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                              const Stringmap *apn_info,
40030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                              const string &keytag) {
4017ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  SaveApnField(storage, storage_group, apn_info, keytag, kApnProperty);
4027ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  SaveApnField(storage, storage_group, apn_info, keytag, kApnUsernameProperty);
4037ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  SaveApnField(storage, storage_group, apn_info, keytag, kApnPasswordProperty);
40430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
40530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
40630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbroodvoid CellularService::SaveApnField(StoreInterface *storage,
40730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                   const string &storage_group,
40830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                   const Stringmap *apn_info,
40930bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                   const string &keytag,
41030bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood                                   const string &apntag) {
41130bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  const string key = keytag + "." + apntag;
41230bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  string str;
41330bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  if (apn_info && GetNonEmptyField(*apn_info, apntag, &str))
41430bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    storage->SetString(storage_group, key, str);
41530bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood  else
41630bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood    storage->DeleteKey(storage_group, key);
41730bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood}
41830bc0ecfcdad79f652eab10c7cda9adca33a04faEric Shienbrood
4197cf36b0cbc1e382fb714cf412d100c9f7ad86c09Thieu Levoid CellularService::AutoConnect() {
4207cf36b0cbc1e382fb714cf412d100c9f7ad86c09Thieu Le  is_auto_connecting_ = true;
4217cf36b0cbc1e382fb714cf412d100c9f7ad86c09Thieu Le  Service::AutoConnect();
4227cf36b0cbc1e382fb714cf412d100c9f7ad86c09Thieu Le  is_auto_connecting_ = false;
4237cf36b0cbc1e382fb714cf412d100c9f7ad86c09Thieu Le}
4247cf36b0cbc1e382fb714cf412d100c9f7ad86c09Thieu Le
425dc7b8447aa220fae51b73fd8610cbfed14ed57fcmukesh agrawalvoid CellularService::Connect(Error *error, const char *reason) {
426398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (num_connect_attempts_ == 0)
427398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    SetOutOfCredits(false);
428398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  connect_start_time_ = base::Time::Now();
429398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  num_connect_attempts_++;
430dc7b8447aa220fae51b73fd8610cbfed14ed57fcmukesh agrawal  Service::Connect(error, reason);
4314d6d941563c2c394e5e650d7ee2d24183fff87b3Darin Petkov  cellular_->Connect(error);
432398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (error->IsFailure())
433398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    ResetOutOfCreditsState();
434c5f56564e1594f218c44e9b77c4c6645cd9239e8Darin Petkov}
4353bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone
436fb0625ef0cfd0ad36439138c04fec5ea963132d7Darin Petkovvoid CellularService::Disconnect(Error *error) {
437fb0625ef0cfd0ad36439138c04fec5ea963132d7Darin Petkov  Service::Disconnect(error);
438fb0625ef0cfd0ad36439138c04fec5ea963132d7Darin Petkov  cellular_->Disconnect(error);
439fb0625ef0cfd0ad36439138c04fec5ea963132d7Darin Petkov}
440fb0625ef0cfd0ad36439138c04fec5ea963132d7Darin Petkov
441b100ae709f1b774a646d946eae604a2bf6326fd4Darin Petkovvoid CellularService::ActivateCellularModem(const string &carrier,
4429a24553461df7036755060423f90804011612249Eric Shienbrood                                            Error *error,
4439a24553461df7036755060423f90804011612249Eric Shienbrood                                            const ResultCallback &callback) {
4449a24553461df7036755060423f90804011612249Eric Shienbrood  cellular_->Activate(carrier, error, callback);
445c408e69059dc709408c1a51f4b757424d08b15f5Darin Petkov}
446c408e69059dc709408c1a51f4b757424d08b15f5Darin Petkov
447c7b1560b03c070fad239767f868322e6b3bdd932Arman Ugurayvoid CellularService::CompleteCellularActivation(Error *error) {
448c7b1560b03c070fad239767f868322e6b3bdd932Arman Uguray  cellular_->CompleteActivation(error);
449c7b1560b03c070fad239767f868322e6b3bdd932Arman Uguray}
450c7b1560b03c070fad239767f868322e6b3bdd932Arman Uguray
451398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Levoid CellularService::SetState(ConnectState new_state) {
452398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (enforce_out_of_credits_detection_)
453398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    PerformOutOfCreditsDetection(state(), new_state);
454398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  Service::SetState(new_state);
455398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le}
456398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le
457313324136473f9120b1e485a408f51ae938dcb64Darin Petkovvoid CellularService::SetStorageIdentifier(const string &identifier) {
458313324136473f9120b1e485a408f51ae938dcb64Darin Petkov  storage_identifier_ = identifier;
459313324136473f9120b1e485a408f51ae938dcb64Darin Petkov  std::replace_if(storage_identifier_.begin(),
460313324136473f9120b1e485a408f51ae938dcb64Darin Petkov                  storage_identifier_.end(),
461313324136473f9120b1e485a408f51ae938dcb64Darin Petkov                  &Service::IllegalChar, '_');
462313324136473f9120b1e485a408f51ae938dcb64Darin Petkov}
463313324136473f9120b1e485a408f51ae938dcb64Darin Petkov
4646515aabcd1fbbb9ff2090c9675c17eeef64e7474Chris Masonestring CellularService::GetStorageIdentifier() const {
465313324136473f9120b1e485a408f51ae938dcb64Darin Petkov  return storage_identifier_;
46634af218abe6a99144ffe01332ce36fbad94f2628Chris Masone}
46734af218abe6a99144ffe01332ce36fbad94f2628Chris Masone
4681b7a616197af7ff753dbe7614a8e207b1e10ac1aGaurav Shahstring CellularService::GetDeviceRpcId(Error */*error*/) {
46995207da4b896bd0a4186163f6f9ebda044a5a7b9Chris Masone  return cellular_->GetRpcIdentifier();
47095207da4b896bd0a4186163f6f9ebda044a5a7b9Chris Masone}
47195207da4b896bd0a4186163f6f9ebda044a5a7b9Chris Masone
4723d6de0eef9998899e9b8b500e628f7180a18da8fBen Chanvoid CellularService::SetActivateOverNonCellularNetwork(bool state) {
4733d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan  if (state == activate_over_non_cellular_network_) {
4743d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan    return;
4753d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan  }
4763d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan  activate_over_non_cellular_network_ = state;
4773d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan  adaptor()->EmitBoolChanged(kActivateOverNonCellularNetworkProperty, state);
4783d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan}
4793d6de0eef9998899e9b8b500e628f7180a18da8fBen Chan
480b9c9933d529e34ce784d4f322d9596cbd9e6ba1cDarin Petkovvoid CellularService::SetActivationState(const string &state) {
481b9c9933d529e34ce784d4f322d9596cbd9e6ba1cDarin Petkov  if (state == activation_state_) {
482b9c9933d529e34ce784d4f322d9596cbd9e6ba1cDarin Petkov    return;
483b9c9933d529e34ce784d4f322d9596cbd9e6ba1cDarin Petkov  }
484b9c9933d529e34ce784d4f322d9596cbd9e6ba1cDarin Petkov  activation_state_ = state;
4857ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  adaptor()->EmitStringChanged(kActivationStateProperty, state);
4867ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  SetConnectableFull(state != kActivationStateNotActivated);
487b9c9933d529e34ce784d4f322d9596cbd9e6ba1cDarin Petkov}
488b9c9933d529e34ce784d4f322d9596cbd9e6ba1cDarin Petkov
489381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkovvoid CellularService::SetOLP(const OLP &olp) {
490381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  if (olp_.Equals(olp)) {
491381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov    return;
492381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  }
493381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  olp_.CopyFrom(olp);
4947ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  adaptor()->EmitStringmapChanged(kPaymentPortalProperty,
495381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov                                  olp.ToDict());
496381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
497381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
4982717a10096e12e46413adf47b39c5b19cd33bce7Arman Ugurayvoid CellularService::SetUsageURL(const string &url) {
499381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  if (url == usage_url_) {
500381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov    return;
501381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  }
502381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov  usage_url_ = url;
5037ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  adaptor()->EmitStringChanged(kUsageURLProperty, url);
504381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov}
505381928f996d23a21d4cfbed70d07cbf9029f625dDarin Petkov
506b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkovvoid CellularService::SetNetworkTechnology(const string &technology) {
507b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov  if (technology == network_technology_) {
508b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov    return;
509b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov  }
510b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov  network_technology_ = technology;
5117ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  adaptor()->EmitStringChanged(kNetworkTechnologyProperty,
512b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov                               technology);
513b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov}
514b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov
515b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkovvoid CellularService::SetRoamingState(const string &state) {
516b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov  if (state == roaming_state_) {
517b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov    return;
518b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov  }
519b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov  roaming_state_ = state;
5207ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  adaptor()->EmitStringChanged(kRoamingStateProperty, state);
521b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov}
522b72cf40dc315f9ae3537980f4fd85e737c125a03Darin Petkov
523398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Levoid CellularService::SetOutOfCredits(bool state) {
524398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  if (state == out_of_credits_) {
525398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le    return;
526398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  }
527398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  out_of_credits_ = state;
528398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le  adaptor()->EmitBoolChanged(kOutOfCreditsProperty, state);
529398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le}
530398b1da04e413f89f0edeb53e939e3a2d2866298Thieu Le
5313335b3773067671301a8a02a1f9eefd17a3ce607Darin Petkovconst Cellular::Operator &CellularService::serving_operator() const {
5323335b3773067671301a8a02a1f9eefd17a3ce607Darin Petkov  return serving_operator_;
5333335b3773067671301a8a02a1f9eefd17a3ce607Darin Petkov}
5343335b3773067671301a8a02a1f9eefd17a3ce607Darin Petkov
5359cb026860ded74991fa26700e07389c9d9e3c841Darin Petkovvoid CellularService::SetServingOperator(const Cellular::Operator &oper) {
5369cb026860ded74991fa26700e07389c9d9e3c841Darin Petkov  if (serving_operator_.Equals(oper)) {
5379cb026860ded74991fa26700e07389c9d9e3c841Darin Petkov    return;
5389cb026860ded74991fa26700e07389c9d9e3c841Darin Petkov  }
5393335b3773067671301a8a02a1f9eefd17a3ce607Darin Petkov  serving_operator_.CopyFrom(oper);
5407ea768e15de860c8a27143ead02a8d3f15ab9f47Ben Chan  adaptor()->EmitStringmapChanged(kServingOperatorProperty, oper.ToDict());
5413335b3773067671301a8a02a1f9eefd17a3ce607Darin Petkov}
5423335b3773067671301a8a02a1f9eefd17a3ce607Darin Petkov
5433bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone}  // namespace shill
544