Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chromeos / dbus / fake_shill_service_client.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chromeos/dbus/fake_shill_service_client.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/values.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_device_client.h"
15 #include "chromeos/dbus/shill_manager_client.h"
16 #include "chromeos/dbus/shill_profile_client.h"
17 #include "chromeos/dbus/shill_property_changed_observer.h"
18 #include "chromeos/network/shill_property_util.h"
19 #include "dbus/bus.h"
20 #include "dbus/message.h"
21 #include "dbus/object_path.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
23
24 namespace chromeos {
25
26 namespace {
27
28 void PassStubListValue(const ShillServiceClient::ListValueCallback& callback,
29                        base::ListValue* value) {
30   callback.Run(*value);
31 }
32
33 void PassStubServiceProperties(
34     const ShillServiceClient::DictionaryValueCallback& callback,
35     DBusMethodCallStatus call_status,
36     const base::DictionaryValue* properties) {
37   callback.Run(call_status, *properties);
38 }
39
40 void CallSortManagerServices() {
41   DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
42       SortManagerServices(true);
43 }
44
45 int GetInteractiveDelay() {
46   return DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
47       GetInteractiveDelay();
48 }
49
50 }  // namespace
51
52 FakeShillServiceClient::FakeShillServiceClient() : weak_ptr_factory_(this) {
53 }
54
55 FakeShillServiceClient::~FakeShillServiceClient() {
56   STLDeleteContainerPairSecondPointers(
57       observer_list_.begin(), observer_list_.end());
58 }
59
60
61 // ShillServiceClient overrides.
62
63 void FakeShillServiceClient::Init(dbus::Bus* bus) {
64 }
65
66 void FakeShillServiceClient::AddPropertyChangedObserver(
67     const dbus::ObjectPath& service_path,
68     ShillPropertyChangedObserver* observer) {
69   GetObserverList(service_path).AddObserver(observer);
70 }
71
72 void FakeShillServiceClient::RemovePropertyChangedObserver(
73     const dbus::ObjectPath& service_path,
74     ShillPropertyChangedObserver* observer) {
75   GetObserverList(service_path).RemoveObserver(observer);
76 }
77
78 void FakeShillServiceClient::GetProperties(
79     const dbus::ObjectPath& service_path,
80     const DictionaryValueCallback& callback) {
81   base::DictionaryValue* nested_dict = NULL;
82   scoped_ptr<base::DictionaryValue> result_properties;
83   DBusMethodCallStatus call_status;
84   stub_services_.GetDictionaryWithoutPathExpansion(service_path.value(),
85                                                    &nested_dict);
86   if (nested_dict) {
87     result_properties.reset(nested_dict->DeepCopy());
88     // Remove credentials that Shill wouldn't send.
89     result_properties->RemoveWithoutPathExpansion(shill::kPassphraseProperty,
90                                                   NULL);
91     call_status = DBUS_METHOD_CALL_SUCCESS;
92   } else {
93     // This may happen if we remove services from the list.
94     VLOG(2) << "Properties not found for: " << service_path.value();
95     result_properties.reset(new base::DictionaryValue);
96     call_status = DBUS_METHOD_CALL_FAILURE;
97   }
98
99   base::MessageLoop::current()->PostTask(
100       FROM_HERE,
101       base::Bind(&PassStubServiceProperties,
102                  callback,
103                  call_status,
104                  base::Owned(result_properties.release())));
105 }
106
107 void FakeShillServiceClient::SetProperty(const dbus::ObjectPath& service_path,
108                                          const std::string& name,
109                                          const base::Value& value,
110                                          const base::Closure& callback,
111                                          const ErrorCallback& error_callback) {
112   if (!SetServiceProperty(service_path.value(), name, value)) {
113     LOG(ERROR) << "Service not found: " << service_path.value();
114     error_callback.Run("Error.InvalidService", "Invalid Service");
115     return;
116   }
117   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
118 }
119
120 void FakeShillServiceClient::SetProperties(
121     const dbus::ObjectPath& service_path,
122     const base::DictionaryValue& properties,
123     const base::Closure& callback,
124     const ErrorCallback& error_callback) {
125   for (base::DictionaryValue::Iterator iter(properties);
126        !iter.IsAtEnd(); iter.Advance()) {
127     if (!SetServiceProperty(service_path.value(), iter.key(), iter.value())) {
128       LOG(ERROR) << "Service not found: " << service_path.value();
129       error_callback.Run("Error.InvalidService", "Invalid Service");
130       return;
131     }
132   }
133   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
134 }
135
136 void FakeShillServiceClient::ClearProperty(
137     const dbus::ObjectPath& service_path,
138     const std::string& name,
139     const base::Closure& callback,
140     const ErrorCallback& error_callback) {
141   base::DictionaryValue* dict = NULL;
142   if (!stub_services_.GetDictionaryWithoutPathExpansion(
143       service_path.value(), &dict)) {
144     error_callback.Run("Error.InvalidService", "Invalid Service");
145     return;
146   }
147   dict->RemoveWithoutPathExpansion(name, NULL);
148   // Note: Shill does not send notifications when properties are cleared.
149   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
150 }
151
152 void FakeShillServiceClient::ClearProperties(
153     const dbus::ObjectPath& service_path,
154     const std::vector<std::string>& names,
155     const ListValueCallback& callback,
156     const ErrorCallback& error_callback) {
157   base::DictionaryValue* dict = NULL;
158   if (!stub_services_.GetDictionaryWithoutPathExpansion(
159       service_path.value(), &dict)) {
160     error_callback.Run("Error.InvalidService", "Invalid Service");
161     return;
162   }
163   scoped_ptr<base::ListValue> results(new base::ListValue);
164   for (std::vector<std::string>::const_iterator iter = names.begin();
165       iter != names.end(); ++iter) {
166     dict->RemoveWithoutPathExpansion(*iter, NULL);
167     // Note: Shill does not send notifications when properties are cleared.
168     results->AppendBoolean(true);
169   }
170   base::MessageLoop::current()->PostTask(
171       FROM_HERE,
172       base::Bind(&PassStubListValue,
173                  callback, base::Owned(results.release())));
174 }
175
176 void FakeShillServiceClient::Connect(const dbus::ObjectPath& service_path,
177                                      const base::Closure& callback,
178                                      const ErrorCallback& error_callback) {
179   VLOG(1) << "FakeShillServiceClient::Connect: " << service_path.value();
180   base::DictionaryValue* service_properties = NULL;
181   if (!stub_services_.GetDictionary(
182           service_path.value(), &service_properties)) {
183     LOG(ERROR) << "Service not found: " << service_path.value();
184     error_callback.Run("Error.InvalidService", "Invalid Service");
185     return;
186   }
187
188   // Set any other services of the same Type to 'offline' first, before setting
189   // State to Association which will trigger sorting Manager.Services and
190   // sending an update.
191   SetOtherServicesOffline(service_path.value());
192
193   // Set Associating.
194   base::StringValue associating_value(shill::kStateAssociation);
195   SetServiceProperty(service_path.value(),
196                      shill::kStateProperty,
197                      associating_value);
198
199   // Stay Associating until the state is changed again after a delay.
200   base::MessageLoop::current()->PostDelayedTask(
201       FROM_HERE,
202       base::Bind(&FakeShillServiceClient::ContinueConnect,
203                  weak_ptr_factory_.GetWeakPtr(),
204                  service_path.value()),
205       base::TimeDelta::FromSeconds(GetInteractiveDelay()));
206
207   callback.Run();
208 }
209
210 void FakeShillServiceClient::Disconnect(const dbus::ObjectPath& service_path,
211                                         const base::Closure& callback,
212                                         const ErrorCallback& error_callback) {
213   base::Value* service;
214   if (!stub_services_.Get(service_path.value(), &service)) {
215     error_callback.Run("Error.InvalidService", "Invalid Service");
216     return;
217   }
218   // Set Idle after a delay
219   base::StringValue idle_value(shill::kStateIdle);
220   base::MessageLoop::current()->PostDelayedTask(
221       FROM_HERE,
222       base::Bind(&FakeShillServiceClient::SetProperty,
223                  weak_ptr_factory_.GetWeakPtr(),
224                  service_path,
225                  shill::kStateProperty,
226                  idle_value,
227                  base::Bind(&base::DoNothing),
228                  error_callback),
229       base::TimeDelta::FromSeconds(GetInteractiveDelay()));
230   callback.Run();
231 }
232
233 void FakeShillServiceClient::Remove(const dbus::ObjectPath& service_path,
234                                     const base::Closure& callback,
235                                     const ErrorCallback& error_callback) {
236   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
237 }
238
239 void FakeShillServiceClient::ActivateCellularModem(
240     const dbus::ObjectPath& service_path,
241     const std::string& carrier,
242     const base::Closure& callback,
243     const ErrorCallback& error_callback) {
244   base::DictionaryValue* service_properties =
245       GetModifiableServiceProperties(service_path.value(), false);
246   if (!service_properties) {
247     LOG(ERROR) << "Service not found: " << service_path.value();
248     error_callback.Run("Error.InvalidService", "Invalid Service");
249   }
250   SetServiceProperty(service_path.value(),
251                      shill::kActivationStateProperty,
252                      base::StringValue(shill::kActivationStateActivating));
253   // Set Activated after a delay
254   base::MessageLoop::current()->PostDelayedTask(
255       FROM_HERE,
256       base::Bind(&FakeShillServiceClient::SetCellularActivated,
257                  weak_ptr_factory_.GetWeakPtr(),
258                  service_path,
259                  error_callback),
260       base::TimeDelta::FromSeconds(GetInteractiveDelay()));
261
262   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
263 }
264
265 void FakeShillServiceClient::CompleteCellularActivation(
266     const dbus::ObjectPath& service_path,
267     const base::Closure& callback,
268     const ErrorCallback& error_callback) {
269   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
270 }
271
272 void FakeShillServiceClient::GetLoadableProfileEntries(
273     const dbus::ObjectPath& service_path,
274     const DictionaryValueCallback& callback) {
275   // Provide a dictionary with a single { profile_path, service_path } entry
276   // if the Profile property is set, or an empty dictionary.
277   scoped_ptr<base::DictionaryValue> result_properties(
278       new base::DictionaryValue);
279   base::DictionaryValue* service_properties =
280       GetModifiableServiceProperties(service_path.value(), false);
281   if (service_properties) {
282     std::string profile_path;
283     if (service_properties->GetStringWithoutPathExpansion(
284             shill::kProfileProperty, &profile_path)) {
285       result_properties->SetStringWithoutPathExpansion(
286           profile_path, service_path.value());
287     }
288   } else {
289     LOG(WARNING) << "Service not in profile: " << service_path.value();
290   }
291
292   DBusMethodCallStatus call_status = DBUS_METHOD_CALL_SUCCESS;
293   base::MessageLoop::current()->PostTask(
294       FROM_HERE,
295       base::Bind(&PassStubServiceProperties,
296                  callback,
297                  call_status,
298                  base::Owned(result_properties.release())));
299 }
300
301 ShillServiceClient::TestInterface* FakeShillServiceClient::GetTestInterface() {
302   return this;
303 }
304
305 // ShillServiceClient::TestInterface overrides.
306
307 void FakeShillServiceClient::AddService(const std::string& service_path,
308                                         const std::string& guid,
309                                         const std::string& name,
310                                         const std::string& type,
311                                         const std::string& state,
312                                         bool visible) {
313   AddServiceWithIPConfig(service_path, guid, name,
314                          type, state, "" /* ipconfig_path */,
315                          visible);
316 }
317
318 void FakeShillServiceClient::AddServiceWithIPConfig(
319     const std::string& service_path,
320     const std::string& guid,
321     const std::string& name,
322     const std::string& type,
323     const std::string& state,
324     const std::string& ipconfig_path,
325     bool visible) {
326   base::DictionaryValue* properties = SetServiceProperties(
327       service_path, guid, name, type, state, visible);
328
329   std::string profile_path;
330   if (properties->GetStringWithoutPathExpansion(shill::kProfileProperty,
331                                                 &profile_path) &&
332       !profile_path.empty()) {
333     DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface()->
334         UpdateService(profile_path, service_path);
335   }
336
337   if (!ipconfig_path.empty()) {
338     properties->SetWithoutPathExpansion(
339         shill::kIPConfigProperty,
340         new base::StringValue(ipconfig_path));
341   }
342
343   DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
344       AddManagerService(service_path, true);
345 }
346
347
348 base::DictionaryValue* FakeShillServiceClient::SetServiceProperties(
349     const std::string& service_path,
350     const std::string& guid,
351     const std::string& name,
352     const std::string& type,
353     const std::string& state,
354     bool visible) {
355   base::DictionaryValue* properties =
356       GetModifiableServiceProperties(service_path, true);
357   connect_behavior_.erase(service_path);
358
359   std::string profile_path;
360   base::DictionaryValue profile_properties;
361   if (DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface()->
362       GetService(service_path, &profile_path, &profile_properties)) {
363     properties->SetWithoutPathExpansion(
364         shill::kProfileProperty,
365         new base::StringValue(profile_path));
366   }
367
368   // If |guid| is provided, set Service.GUID to that. Otherwise if a GUID is
369   // stored in a profile entry, use that. Otherwise leave it blank. Shill does
370   // not enforce a valid guid, we do that at the NetworkStateHandler layer.
371   std::string guid_to_set = guid;
372   if (guid_to_set.empty()) {
373     profile_properties.GetStringWithoutPathExpansion(
374         shill::kGuidProperty, &guid_to_set);
375   }
376   if (!guid_to_set.empty()) {
377     properties->SetWithoutPathExpansion(shill::kGuidProperty,
378                                         new base::StringValue(guid_to_set));
379   }
380   shill_property_util::SetSSID(name, properties);
381   properties->SetWithoutPathExpansion(
382       shill::kNameProperty,
383       new base::StringValue(name));
384   std::string device_path =
385       DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface()->
386       GetDevicePathForType(type);
387   properties->SetWithoutPathExpansion(
388       shill::kDeviceProperty,
389       new base::StringValue(device_path));
390   properties->SetWithoutPathExpansion(
391       shill::kTypeProperty,
392       new base::StringValue(type));
393   properties->SetWithoutPathExpansion(
394       shill::kStateProperty,
395       new base::StringValue(state));
396   properties->SetWithoutPathExpansion(
397       shill::kVisibleProperty,
398       new base::FundamentalValue(visible));
399   if (type == shill::kTypeWifi) {
400     properties->SetWithoutPathExpansion(
401         shill::kSecurityProperty,
402         new base::StringValue(shill::kSecurityNone));
403     properties->SetWithoutPathExpansion(
404         shill::kModeProperty,
405         new base::StringValue(shill::kModeManaged));
406   }
407   return properties;
408 }
409
410 void FakeShillServiceClient::RemoveService(const std::string& service_path) {
411   stub_services_.RemoveWithoutPathExpansion(service_path, NULL);
412   connect_behavior_.erase(service_path);
413   DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
414       RemoveManagerService(service_path);
415 }
416
417 bool FakeShillServiceClient::SetServiceProperty(const std::string& service_path,
418                                                 const std::string& property,
419                                                 const base::Value& value) {
420   base::DictionaryValue* dict = NULL;
421   if (!stub_services_.GetDictionaryWithoutPathExpansion(service_path, &dict))
422     return false;
423
424   VLOG(1) << "Service.SetProperty: " << property << " = " << value
425           << " For: " << service_path;
426
427   base::DictionaryValue new_properties;
428   std::string changed_property;
429   bool case_sensitive = true;
430   if (StartsWithASCII(property, "Provider.", case_sensitive) ||
431       StartsWithASCII(property, "OpenVPN.", case_sensitive) ||
432       StartsWithASCII(property, "L2TPIPsec.", case_sensitive)) {
433     // These properties are only nested within the Provider dictionary if read
434     // from Shill.
435     base::DictionaryValue* provider = new base::DictionaryValue;
436     provider->SetWithoutPathExpansion(property, value.DeepCopy());
437     new_properties.SetWithoutPathExpansion(shill::kProviderProperty, provider);
438     changed_property = shill::kProviderProperty;
439   } else {
440     new_properties.SetWithoutPathExpansion(property, value.DeepCopy());
441     changed_property = property;
442   }
443
444   dict->MergeDictionary(&new_properties);
445
446   // Add or update the profile entry.
447   ShillProfileClient::TestInterface* profile_test =
448       DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
449   if (property == shill::kProfileProperty) {
450     std::string profile_path;
451     if (value.GetAsString(&profile_path)) {
452       if (!profile_path.empty())
453         profile_test->AddService(profile_path, service_path);
454     } else {
455       LOG(ERROR) << "Profile value is not a String!";
456     }
457   } else {
458     std::string profile_path;
459     if (dict->GetStringWithoutPathExpansion(
460             shill::kProfileProperty, &profile_path) && !profile_path.empty()) {
461       profile_test->UpdateService(profile_path, service_path);
462     }
463   }
464
465   // Notify the Manager if the state changed (affects DefaultService).
466   if (property == shill::kStateProperty) {
467     std::string state;
468     value.GetAsString(&state);
469     DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
470         ServiceStateChanged(service_path, state);
471   }
472
473   // If the State or Visibility changes, the sort order of service lists may
474   // change and the DefaultService property may change.
475   if (property == shill::kStateProperty ||
476       property == shill::kVisibleProperty) {
477     base::MessageLoop::current()->PostTask(
478         FROM_HERE, base::Bind(&CallSortManagerServices));
479   }
480
481   // Notifiy Chrome of the property change.
482   base::MessageLoop::current()->PostTask(
483       FROM_HERE,
484       base::Bind(&FakeShillServiceClient::NotifyObserversPropertyChanged,
485                  weak_ptr_factory_.GetWeakPtr(),
486                  dbus::ObjectPath(service_path), changed_property));
487   return true;
488 }
489
490 const base::DictionaryValue* FakeShillServiceClient::GetServiceProperties(
491     const std::string& service_path) const {
492   const base::DictionaryValue* properties = NULL;
493   stub_services_.GetDictionaryWithoutPathExpansion(service_path, &properties);
494   return properties;
495 }
496
497 void FakeShillServiceClient::ClearServices() {
498   DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
499       ClearManagerServices();
500
501   stub_services_.Clear();
502   connect_behavior_.clear();
503 }
504
505 void FakeShillServiceClient::SetConnectBehavior(const std::string& service_path,
506                                 const base::Closure& behavior) {
507   connect_behavior_[service_path] = behavior;
508 }
509
510 void FakeShillServiceClient::NotifyObserversPropertyChanged(
511     const dbus::ObjectPath& service_path,
512     const std::string& property) {
513   base::DictionaryValue* dict = NULL;
514   std::string path = service_path.value();
515   if (!stub_services_.GetDictionaryWithoutPathExpansion(path, &dict)) {
516     LOG(ERROR) << "Notify for unknown service: " << path;
517     return;
518   }
519   base::Value* value = NULL;
520   if (!dict->GetWithoutPathExpansion(property, &value)) {
521     LOG(ERROR) << "Notify for unknown property: "
522                << path << " : " << property;
523     return;
524   }
525   FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
526                     GetObserverList(service_path),
527                     OnPropertyChanged(property, *value));
528 }
529
530 base::DictionaryValue* FakeShillServiceClient::GetModifiableServiceProperties(
531     const std::string& service_path, bool create_if_missing) {
532   base::DictionaryValue* properties = NULL;
533   if (!stub_services_.GetDictionaryWithoutPathExpansion(service_path,
534                                                         &properties) &&
535       create_if_missing) {
536     properties = new base::DictionaryValue;
537     stub_services_.Set(service_path, properties);
538   }
539   return properties;
540 }
541
542 FakeShillServiceClient::PropertyObserverList&
543 FakeShillServiceClient::GetObserverList(const dbus::ObjectPath& device_path) {
544   std::map<dbus::ObjectPath, PropertyObserverList*>::iterator iter =
545       observer_list_.find(device_path);
546   if (iter != observer_list_.end())
547     return *(iter->second);
548   PropertyObserverList* observer_list = new PropertyObserverList();
549   observer_list_[device_path] = observer_list;
550   return *observer_list;
551 }
552
553 void FakeShillServiceClient::SetOtherServicesOffline(
554     const std::string& service_path) {
555   const base::DictionaryValue* service_properties = GetServiceProperties(
556       service_path);
557   if (!service_properties) {
558     LOG(ERROR) << "Missing service: " << service_path;
559     return;
560   }
561   std::string service_type;
562   service_properties->GetString(shill::kTypeProperty, &service_type);
563   // Set all other services of the same type to offline (Idle).
564   for (base::DictionaryValue::Iterator iter(stub_services_);
565        !iter.IsAtEnd(); iter.Advance()) {
566     std::string path = iter.key();
567     if (path == service_path)
568       continue;
569     base::DictionaryValue* properties;
570     if (!stub_services_.GetDictionaryWithoutPathExpansion(path, &properties))
571       NOTREACHED();
572
573     std::string type;
574     properties->GetString(shill::kTypeProperty, &type);
575     if (type != service_type)
576       continue;
577     properties->SetWithoutPathExpansion(
578         shill::kStateProperty,
579         new base::StringValue(shill::kStateIdle));
580   }
581 }
582
583 void FakeShillServiceClient::SetCellularActivated(
584     const dbus::ObjectPath& service_path,
585     const ErrorCallback& error_callback) {
586   SetProperty(service_path,
587               shill::kActivationStateProperty,
588               base::StringValue(shill::kActivationStateActivated),
589               base::Bind(&base::DoNothing),
590               error_callback);
591   SetProperty(service_path,
592               shill::kConnectableProperty,
593               base::FundamentalValue(true),
594               base::Bind(&base::DoNothing),
595               error_callback);
596 }
597
598 void FakeShillServiceClient::ContinueConnect(
599     const std::string& service_path) {
600   VLOG(1) << "FakeShillServiceClient::ContinueConnect: " << service_path;
601   base::DictionaryValue* service_properties = NULL;
602   if (!stub_services_.GetDictionary(service_path, &service_properties)) {
603     LOG(ERROR) << "Service not found: " << service_path;
604     return;
605   }
606
607   if (ContainsKey(connect_behavior_, service_path)) {
608     const base::Closure& custom_connect_behavior =
609         connect_behavior_[service_path];
610     VLOG(1) << "Running custom connect behavior for " << service_path;
611     custom_connect_behavior.Run();
612     return;
613   }
614
615   // No custom connect behavior set, continue with the default connect behavior.
616   std::string passphrase;
617   service_properties->GetStringWithoutPathExpansion(
618       shill::kPassphraseProperty, &passphrase);
619   if (passphrase == "failure") {
620     // Simulate a password failure.
621     SetServiceProperty(service_path,
622                        shill::kStateProperty,
623                        base::StringValue(shill::kStateFailure));
624     base::MessageLoop::current()->PostTask(
625         FROM_HERE,
626         base::Bind(
627             base::IgnoreResult(&FakeShillServiceClient::SetServiceProperty),
628             weak_ptr_factory_.GetWeakPtr(),
629             service_path,
630             shill::kErrorProperty,
631             base::StringValue(shill::kErrorBadPassphrase)));
632   } else {
633     // Set Online.
634     VLOG(1) << "Setting state to Online " << service_path;
635     SetServiceProperty(service_path,
636                        shill::kStateProperty,
637                        base::StringValue(shill::kStateOnline));
638   }
639 }
640
641 }  // namespace chromeos