blob: cc969bbaac6fa0083c38fc9e0a1eb3a416da680f [file] [log] [blame]
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Chris Masone3bd3c8c2011-06-13 08:20:26 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/cellular_service.h"
6
7#include <string>
8
Ben Chana0ddf462014-02-06 11:32:42 -08009#include <base/strings/stringprintf.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070010#include <chromeos/dbus/service_constants.h>
11
Darin Petkovb72cf402011-11-22 14:51:39 +010012#include "shill/adaptor_interfaces.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070013#include "shill/cellular.h"
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -040014#include "shill/property_accessor.h"
15#include "shill/store_interface.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070016
17using std::string;
18
19namespace shill {
Darin Petkovc5f56562011-08-06 16:40:05 -070020
mukesh agrawala70ec272013-08-19 16:08:31 -070021// statics
Christopher Wiley1582bdd2012-11-15 11:31:14 -080022const char CellularService::kAutoConnActivating[] = "activating";
mukesh agrawald4773882013-08-14 17:21:14 -070023const char CellularService::kAutoConnBadPPPCredentials[] =
24 "bad PPP credentials";
Ben Chan19f83972012-10-03 23:25:56 -070025const char CellularService::kAutoConnDeviceDisabled[] = "device disabled";
Thieu Le398b1da2013-03-11 17:31:10 -070026const char CellularService::kAutoConnOutOfCredits[] = "device out of credits";
27const char CellularService::kAutoConnOutOfCreditsDetectionInProgress[] =
28 "device detecting out-of-credits";
mukesh agrawala70ec272013-08-19 16:08:31 -070029const char CellularService::kStoragePPPUsername[] = "Cellular.PPP.Username";
30const char CellularService::kStoragePPPPassword[] = "Cellular.PPP.Password";
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -040031
Darin Petkov381928f2012-02-02 23:00:12 +010032// TODO(petkov): Add these to system_api/dbus/service_constants.h
33namespace {
mukesh agrawal3ffe52c2013-06-20 15:21:29 -070034const char kCellularPPPUsernameProperty[] = "Cellular.PPP.Username";
35const char kCellularPPPPasswordProperty[] = "Cellular.PPP.Password";
36} // namespace
37
38namespace {
39const char kStorageAPN[] = "Cellular.APN";
40const char kStorageLastGoodAPN[] = "Cellular.LastGoodAPN";
Ben Chan19f83972012-10-03 23:25:56 -070041} // namespace
Darin Petkov381928f2012-02-02 23:00:12 +010042
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -040043static bool GetNonEmptyField(const Stringmap &stringmap,
44 const string &fieldname,
45 string *value) {
46 Stringmap::const_iterator it = stringmap.find(fieldname);
47 if (it != stringmap.end() && !it->second.empty()) {
48 *value = it->second;
49 return true;
50 }
51 return false;
52}
53
Prathmesh Prabhu0d36b4f2013-04-01 11:45:54 -070054CellularService::CellularService(ModemInfo *modem_info,
mukesh agrawal51a7e932011-07-27 16:18:26 -070055 const CellularRefPtr &device)
Prathmesh Prabhu0d36b4f2013-04-01 11:45:54 -070056 : Service(modem_info->control_interface(), modem_info->dispatcher(),
57 modem_info->metrics(), modem_info->manager(),
Thieu Le3426c8f2012-01-11 17:35:11 -080058 Technology::kCellular),
Thieu Le398b1da2013-03-11 17:31:10 -070059 weak_ptr_factory_(this),
Ben Chan3d6de0e2012-12-10 12:01:34 -080060 activate_over_non_cellular_network_(false),
Thieu Le7cf36b02013-01-30 17:15:56 -080061 cellular_(device),
Ben Chana0ddf462014-02-06 11:32:42 -080062 is_auto_connecting_(false) {
mukesh agrawalcbfb34e2013-04-17 19:33:25 -070063 SetConnectable(true);
mukesh agrawalde29fa82011-09-16 16:16:36 -070064 PropertyStore *store = this->mutable_store();
Ben Chan3d6de0e2012-12-10 12:01:34 -080065 store->RegisterConstBool(kActivateOverNonCellularNetworkProperty,
66 &activate_over_non_cellular_network_);
Ben Chan7ea768e2013-09-20 15:08:40 -070067 store->RegisterConstString(kActivationStateProperty, &activation_state_);
68 HelpRegisterDerivedStringmap(kCellularApnProperty,
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -040069 &CellularService::GetApn,
70 &CellularService::SetApn);
Ben Chan7ea768e2013-09-20 15:08:40 -070071 store->RegisterConstStringmap(kCellularLastGoodApnProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -070072 &last_good_apn_info_);
Ben Chan7ea768e2013-09-20 15:08:40 -070073 store->RegisterConstString(kNetworkTechnologyProperty, &network_technology_);
Thieu Le43ce4d42013-10-04 16:08:55 -070074 HelpRegisterDerivedBool(kOutOfCreditsProperty,
75 &CellularService::IsOutOfCredits,
76 NULL);
Prathmesh Prabhu92df6192014-04-29 18:08:08 -070077 store->RegisterConstStringmap(kPaymentPortalProperty, &olp_);
Ben Chan7ea768e2013-09-20 15:08:40 -070078 store->RegisterConstString(kRoamingStateProperty, &roaming_state_);
79 store->RegisterConstStringmap(kServingOperatorProperty,
Darin Petkov3335b372011-08-22 11:05:32 -070080 &serving_operator_.ToDict());
Ben Chan7ea768e2013-09-20 15:08:40 -070081 store->RegisterConstString(kUsageURLProperty, &usage_url_);
mukesh agrawal3ffe52c2013-06-20 15:21:29 -070082 store->RegisterString(kCellularPPPUsernameProperty, &ppp_username_);
83 store->RegisterWriteOnlyString(kCellularPPPPasswordProperty, &ppp_password_);
Darin Petkovac635a82012-01-10 16:51:58 +010084
Prathmesh Prabhu95afcbb2014-04-08 16:05:42 -070085 set_friendly_name(cellular_->CreateDefaultFriendlyServiceName());
Ben Chan7ea768e2013-09-20 15:08:40 -070086 SetStorageIdentifier(string(kTypeCellular) + "_" +
Prathmesh Prabhu401a5b92014-04-29 17:37:55 -070087 cellular_->address() + "_" + friendly_name());
Thieu Le43ce4d42013-10-04 16:08:55 -070088 // Assume we are not performing any out-of-credits detection.
89 // The capability can reinitialize with the appropriate type later.
90 InitOutOfCreditsDetection(OutOfCreditsDetector::OOCTypeNone);
Chris Masone3bd3c8c2011-06-13 08:20:26 -070091}
92
93CellularService::~CellularService() { }
94
Ben Chan19f83972012-10-03 23:25:56 -070095bool CellularService::IsAutoConnectable(const char **reason) const {
96 if (!cellular_->running()) {
97 *reason = kAutoConnDeviceDisabled;
98 return false;
99 }
Christopher Wiley1582bdd2012-11-15 11:31:14 -0800100 if (cellular_->IsActivating()) {
101 *reason = kAutoConnActivating;
102 return false;
103 }
mukesh agrawald4773882013-08-14 17:21:14 -0700104 if (failure() == kFailurePPPAuth) {
105 *reason = kAutoConnBadPPPCredentials;
106 return false;
107 }
Thieu Le43ce4d42013-10-04 16:08:55 -0700108 if (out_of_credits_detector_->IsDetecting()) {
Thieu Le398b1da2013-03-11 17:31:10 -0700109 *reason = kAutoConnOutOfCreditsDetectionInProgress;
110 return false;
111 }
Thieu Le43ce4d42013-10-04 16:08:55 -0700112 if (out_of_credits_detector_->out_of_credits()) {
Thieu Le398b1da2013-03-11 17:31:10 -0700113 *reason = kAutoConnOutOfCredits;
114 return false;
115 }
Ben Chan19f83972012-10-03 23:25:56 -0700116 return Service::IsAutoConnectable(reason);
117}
118
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400119void CellularService::HelpRegisterDerivedStringmap(
120 const string &name,
121 Stringmap(CellularService::*get)(Error *error),
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700122 bool(CellularService::*set)(
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400123 const Stringmap &value, Error *error)) {
124 mutable_store()->RegisterDerivedStringmap(
125 name,
126 StringmapAccessor(
127 new CustomAccessor<CellularService, Stringmap>(this, get, set)));
128}
129
Thieu Le43ce4d42013-10-04 16:08:55 -0700130void CellularService::HelpRegisterDerivedBool(
131 const string &name,
Alex Vakulenko8a532292014-06-16 17:18:44 -0700132 bool(CellularService::*get)(Error *error),
Thieu Le43ce4d42013-10-04 16:08:55 -0700133 bool(CellularService::*set)(const bool&, Error *)) {
134 mutable_store()->RegisterDerivedBool(
135 name,
136 BoolAccessor(new CustomAccessor<CellularService, bool>(this, get, set)));
137}
138
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400139Stringmap *CellularService::GetUserSpecifiedApn() {
Ben Chan7ea768e2013-09-20 15:08:40 -0700140 Stringmap::iterator it = apn_info_.find(kApnProperty);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400141 if (it == apn_info_.end() || it->second.empty())
142 return NULL;
143 return &apn_info_;
144}
145
146Stringmap *CellularService::GetLastGoodApn() {
Paul Stewart6db7b242014-05-02 15:34:21 -0700147 Stringmap::iterator it = last_good_apn_info_.find(kApnProperty);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400148 if (it == last_good_apn_info_.end() || it->second.empty())
149 return NULL;
150 return &last_good_apn_info_;
151}
152
153Stringmap CellularService::GetApn(Error */*error*/) {
154 return apn_info_;
155}
156
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700157bool CellularService::SetApn(const Stringmap &value, Error *error) {
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400158 // Only copy in the fields we care about, and validate the contents.
Eric Shienbroodc7073302012-04-03 14:41:44 -0400159 // If the "apn" field is missing or empty, the APN is cleared.
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400160 string str;
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700161 Stringmap new_apn_info;
Ben Chan7ea768e2013-09-20 15:08:40 -0700162 if (GetNonEmptyField(value, kApnProperty, &str)) {
163 new_apn_info[kApnProperty] = str;
164 if (GetNonEmptyField(value, kApnUsernameProperty, &str))
165 new_apn_info[kApnUsernameProperty] = str;
166 if (GetNonEmptyField(value, kApnPasswordProperty, &str))
167 new_apn_info[kApnPasswordProperty] = str;
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700168 }
169 if (apn_info_ == new_apn_info) {
170 return false;
171 }
172 apn_info_ = new_apn_info;
Ben Chan7ea768e2013-09-20 15:08:40 -0700173 if (ContainsKey(apn_info_, kApnProperty)) {
Eric Shienbroodc7073302012-04-03 14:41:44 -0400174 // Clear the last good APN, otherwise the one the user just
175 // set won't be used, since LastGoodApn comes first in the
176 // search order when trying to connect. Only do this if a
177 // non-empty user APN has been supplied. If the user APN is
178 // being cleared, leave LastGoodApn alone.
179 ClearLastGoodApn();
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400180 }
Ben Chan7ea768e2013-09-20 15:08:40 -0700181 adaptor()->EmitStringmapChanged(kCellularApnProperty, apn_info_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700182 return true;
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400183}
184
185void CellularService::SetLastGoodApn(const Stringmap &apn_info) {
186 last_good_apn_info_ = apn_info;
Ben Chan7ea768e2013-09-20 15:08:40 -0700187 adaptor()->EmitStringmapChanged(kCellularLastGoodApnProperty,
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400188 last_good_apn_info_);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400189}
190
191void CellularService::ClearLastGoodApn() {
192 last_good_apn_info_.clear();
Ben Chan7ea768e2013-09-20 15:08:40 -0700193 adaptor()->EmitStringmapChanged(kCellularLastGoodApnProperty,
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400194 last_good_apn_info_);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400195}
196
Thieu Le99dc56d2013-04-01 14:22:21 -0700197void CellularService::OnAfterResume() {
198 Service::OnAfterResume();
199 resume_start_time_ = base::Time::Now();
200}
201
Thieu Le43ce4d42013-10-04 16:08:55 -0700202void CellularService::InitOutOfCreditsDetection(
203 OutOfCreditsDetector::OOCType ooc_type) {
204 out_of_credits_detector_.reset(
205 OutOfCreditsDetector::CreateDetector(ooc_type,
206 dispatcher(),
207 manager(),
208 metrics(),
209 this));
210}
211
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400212bool CellularService::Load(StoreInterface *storage) {
213 // Load properties common to all Services.
214 if (!Service::Load(storage))
215 return false;
216
217 const string id = GetStorageIdentifier();
218 LoadApn(storage, id, kStorageAPN, &apn_info_);
219 LoadApn(storage, id, kStorageLastGoodAPN, &last_good_apn_info_);
mukesh agrawala70ec272013-08-19 16:08:31 -0700220
221 const string old_username = ppp_username_;
222 const string old_password = ppp_password_;
mukesh agrawal3ffe52c2013-06-20 15:21:29 -0700223 storage->GetString(id, kStoragePPPUsername, &ppp_username_);
224 storage->GetString(id, kStoragePPPPassword, &ppp_password_);
mukesh agrawala70ec272013-08-19 16:08:31 -0700225 if (IsFailed() && failure() == kFailurePPPAuth &&
226 (old_username != ppp_username_ || old_password != ppp_password_)) {
227 SetState(kStateIdle);
228 }
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400229 return true;
230}
231
232void CellularService::LoadApn(StoreInterface *storage,
233 const string &storage_group,
234 const string &keytag,
235 Stringmap *apn_info) {
Ben Chan7ea768e2013-09-20 15:08:40 -0700236 if (!LoadApnField(storage, storage_group, keytag, kApnProperty, apn_info))
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400237 return;
Ben Chan7ea768e2013-09-20 15:08:40 -0700238 LoadApnField(storage, storage_group, keytag, kApnUsernameProperty, apn_info);
239 LoadApnField(storage, storage_group, keytag, kApnPasswordProperty, apn_info);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400240}
241
242bool CellularService::LoadApnField(StoreInterface *storage,
243 const string &storage_group,
244 const string &keytag,
245 const string &apntag,
246 Stringmap *apn_info) {
247 string value;
248 if (storage->GetString(storage_group, keytag + "." + apntag, &value) &&
249 !value.empty()) {
250 (*apn_info)[apntag] = value;
251 return true;
252 }
253 return false;
254}
255
256bool CellularService::Save(StoreInterface *storage) {
257 // Save properties common to all Services.
258 if (!Service::Save(storage))
259 return false;
260
261 const string id = GetStorageIdentifier();
262 SaveApn(storage, id, GetUserSpecifiedApn(), kStorageAPN);
263 SaveApn(storage, id, GetLastGoodApn(), kStorageLastGoodAPN);
mukesh agrawal3ffe52c2013-06-20 15:21:29 -0700264 SaveString(storage, id, kStoragePPPUsername, ppp_username_, false, true);
265 SaveString(storage, id, kStoragePPPPassword, ppp_password_, false, true);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400266 return true;
267}
268
269void CellularService::SaveApn(StoreInterface *storage,
270 const string &storage_group,
271 const Stringmap *apn_info,
272 const string &keytag) {
Ben Chan7ea768e2013-09-20 15:08:40 -0700273 SaveApnField(storage, storage_group, apn_info, keytag, kApnProperty);
274 SaveApnField(storage, storage_group, apn_info, keytag, kApnUsernameProperty);
275 SaveApnField(storage, storage_group, apn_info, keytag, kApnPasswordProperty);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400276}
277
278void CellularService::SaveApnField(StoreInterface *storage,
279 const string &storage_group,
280 const Stringmap *apn_info,
281 const string &keytag,
282 const string &apntag) {
283 const string key = keytag + "." + apntag;
284 string str;
285 if (apn_info && GetNonEmptyField(*apn_info, apntag, &str))
286 storage->SetString(storage_group, key, str);
287 else
288 storage->DeleteKey(storage_group, key);
289}
290
Thieu Le43ce4d42013-10-04 16:08:55 -0700291bool CellularService::IsOutOfCredits(Error */*error*/) {
292 return out_of_credits_detector_->out_of_credits();
293}
294
295void CellularService::set_out_of_credits_detector(
296 OutOfCreditsDetector *detector) {
297 out_of_credits_detector_.reset(detector);
298}
299
300void CellularService::SignalOutOfCreditsChanged(bool state) const {
301 adaptor()->EmitBoolChanged(kOutOfCreditsProperty, state);
302}
303
Thieu Le7cf36b02013-01-30 17:15:56 -0800304void CellularService::AutoConnect() {
305 is_auto_connecting_ = true;
306 Service::AutoConnect();
307 is_auto_connecting_ = false;
308}
309
mukesh agrawaldc7b8442012-09-27 13:48:14 -0700310void CellularService::Connect(Error *error, const char *reason) {
mukesh agrawaldc7b8442012-09-27 13:48:14 -0700311 Service::Connect(error, reason);
Darin Petkov4d6d9412011-08-24 13:19:54 -0700312 cellular_->Connect(error);
Thieu Le398b1da2013-03-11 17:31:10 -0700313 if (error->IsFailure())
Thieu Le43ce4d42013-10-04 16:08:55 -0700314 out_of_credits_detector_->ResetDetector();
Darin Petkovc5f56562011-08-06 16:40:05 -0700315}
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700316
Samuel Tan0d061192014-07-07 15:45:15 -0700317void CellularService::Disconnect(Error *error, const char *reason) {
318 Service::Disconnect(error, reason);
319 cellular_->Disconnect(error, reason);
Darin Petkovfb0625e2012-01-16 13:05:56 +0100320}
321
Darin Petkovb100ae72011-08-24 16:19:45 -0700322void CellularService::ActivateCellularModem(const string &carrier,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500323 Error *error,
324 const ResultCallback &callback) {
325 cellular_->Activate(carrier, error, callback);
Darin Petkovc408e692011-08-17 13:47:15 -0700326}
327
Arman Ugurayc7b15602013-02-16 00:56:18 -0800328void CellularService::CompleteCellularActivation(Error *error) {
329 cellular_->CompleteActivation(error);
330}
331
Thieu Le398b1da2013-03-11 17:31:10 -0700332void CellularService::SetState(ConnectState new_state) {
Thieu Le43ce4d42013-10-04 16:08:55 -0700333 out_of_credits_detector_->NotifyServiceStateChanged(state(), new_state);
Thieu Le398b1da2013-03-11 17:31:10 -0700334 Service::SetState(new_state);
335}
336
Darin Petkov31332412012-01-28 01:50:02 +0100337void CellularService::SetStorageIdentifier(const string &identifier) {
Prathmesh Prabhu401a5b92014-04-29 17:37:55 -0700338 SLOG(Cellular, 3) << __func__ << ": " << identifier;
Darin Petkov31332412012-01-28 01:50:02 +0100339 storage_identifier_ = identifier;
340 std::replace_if(storage_identifier_.begin(),
341 storage_identifier_.end(),
342 &Service::IllegalChar, '_');
343}
344
Chris Masone6515aab2011-10-12 16:19:09 -0700345string CellularService::GetStorageIdentifier() const {
Darin Petkov31332412012-01-28 01:50:02 +0100346 return storage_identifier_;
Chris Masone34af2182011-08-22 11:59:36 -0700347}
348
Paul Stewart1cf7eb82013-12-03 19:34:36 -0800349string CellularService::GetDeviceRpcId(Error */*error*/) const {
Chris Masone95207da2011-06-29 16:50:49 -0700350 return cellular_->GetRpcIdentifier();
351}
352
Ben Chan3d6de0e2012-12-10 12:01:34 -0800353void CellularService::SetActivateOverNonCellularNetwork(bool state) {
354 if (state == activate_over_non_cellular_network_) {
355 return;
356 }
357 activate_over_non_cellular_network_ = state;
358 adaptor()->EmitBoolChanged(kActivateOverNonCellularNetworkProperty, state);
359}
360
Darin Petkovb9c99332012-01-12 13:13:00 +0100361void CellularService::SetActivationState(const string &state) {
362 if (state == activation_state_) {
363 return;
364 }
365 activation_state_ = state;
Ben Chan7ea768e2013-09-20 15:08:40 -0700366 adaptor()->EmitStringChanged(kActivationStateProperty, state);
367 SetConnectableFull(state != kActivationStateNotActivated);
Darin Petkovb9c99332012-01-12 13:13:00 +0100368}
369
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700370void CellularService::SetOLP(const string &url,
371 const string &method,
372 const string &post_data) {
373 Stringmap olp;
374 olp[kPaymentPortalURL] = url;
375 olp[kPaymentPortalMethod] = method;
376 olp[kPaymentPortalPostData] = post_data;
377
378 if (olp_ == olp) {
Darin Petkov381928f2012-02-02 23:00:12 +0100379 return;
380 }
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700381 olp_ = olp;
382 adaptor()->EmitStringmapChanged(kPaymentPortalProperty, olp);
Darin Petkov381928f2012-02-02 23:00:12 +0100383}
384
Arman Uguray2717a102013-01-29 23:36:06 -0800385void CellularService::SetUsageURL(const string &url) {
Darin Petkov381928f2012-02-02 23:00:12 +0100386 if (url == usage_url_) {
387 return;
388 }
389 usage_url_ = url;
Ben Chan7ea768e2013-09-20 15:08:40 -0700390 adaptor()->EmitStringChanged(kUsageURLProperty, url);
Darin Petkov381928f2012-02-02 23:00:12 +0100391}
392
Darin Petkovb72cf402011-11-22 14:51:39 +0100393void CellularService::SetNetworkTechnology(const string &technology) {
394 if (technology == network_technology_) {
395 return;
396 }
397 network_technology_ = technology;
Ben Chan7ea768e2013-09-20 15:08:40 -0700398 adaptor()->EmitStringChanged(kNetworkTechnologyProperty,
Darin Petkovb72cf402011-11-22 14:51:39 +0100399 technology);
400}
401
402void CellularService::SetRoamingState(const string &state) {
403 if (state == roaming_state_) {
404 return;
405 }
406 roaming_state_ = state;
Ben Chan7ea768e2013-09-20 15:08:40 -0700407 adaptor()->EmitStringChanged(kRoamingStateProperty, state);
Darin Petkovb72cf402011-11-22 14:51:39 +0100408}
409
Darin Petkov3335b372011-08-22 11:05:32 -0700410const Cellular::Operator &CellularService::serving_operator() const {
411 return serving_operator_;
412}
413
Darin Petkov9cb02682012-01-28 00:17:38 +0100414void CellularService::SetServingOperator(const Cellular::Operator &oper) {
415 if (serving_operator_.Equals(oper)) {
416 return;
417 }
Darin Petkov3335b372011-08-22 11:05:32 -0700418 serving_operator_.CopyFrom(oper);
Ben Chan7ea768e2013-09-20 15:08:40 -0700419 adaptor()->EmitStringmapChanged(kServingOperatorProperty, oper.ToDict());
Darin Petkov3335b372011-08-22 11:05:32 -0700420}
421
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700422} // namespace shill