511054f407dcaa400a651306cbc0c24f2a01064b
[platform/framework/web/crosswalk.git] / src / chromeos / dbus / fake_shill_manager_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_manager_client.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "chromeos/chromeos_switches.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
16 #include "chromeos/dbus/shill_device_client.h"
17 #include "chromeos/dbus/shill_ipconfig_client.h"
18 #include "chromeos/dbus/shill_profile_client.h"
19 #include "chromeos/dbus/shill_property_changed_observer.h"
20 #include "chromeos/dbus/shill_service_client.h"
21 #include "dbus/bus.h"
22 #include "dbus/message.h"
23 #include "dbus/object_path.h"
24 #include "dbus/values_util.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h"
26
27 namespace chromeos {
28
29 namespace {
30
31 // Used to compare values for finding entries to erase in a ListValue.
32 // (ListValue only implements a const_iterator version of Find).
33 struct ValueEquals {
34   explicit ValueEquals(const base::Value* first) : first_(first) {}
35   bool operator()(const base::Value* second) const {
36     return first_->Equals(second);
37   }
38   const base::Value* first_;
39 };
40
41 // Appends string entries from |service_list_in| whose entries in ServiceClient
42 // have Type |match_type| to one of the output lists based on the entry's State.
43 void AppendServicesForType(
44     const base::ListValue* service_list_in,
45     const char* match_type,
46     bool technology_enabled,
47     std::vector<std::string>* active_service_list_out,
48     std::vector<std::string>* inactive_service_list_out,
49     std::vector<std::string>* disabled_service_list_out) {
50   ShillServiceClient::TestInterface* service_client =
51       DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
52   for (base::ListValue::const_iterator iter = service_list_in->begin();
53        iter != service_list_in->end(); ++iter) {
54     std::string service_path;
55     if (!(*iter)->GetAsString(&service_path))
56       continue;
57     const base::DictionaryValue* properties =
58         service_client->GetServiceProperties(service_path);
59     if (!properties) {
60       LOG(ERROR) << "Properties not found for service: " << service_path;
61       continue;
62     }
63     std::string type;
64     properties->GetString(shill::kTypeProperty, &type);
65     if (type != match_type)
66       continue;
67     bool visible = false;
68     if (technology_enabled)
69       properties->GetBoolean(shill::kVisibleProperty, &visible);
70     if (!visible) {
71       disabled_service_list_out->push_back(service_path);
72       continue;
73     }
74     std::string state;
75     properties->GetString(shill::kStateProperty, &state);
76     if (state == shill::kStateOnline ||
77         state == shill::kStateAssociation ||
78         state == shill::kStateConfiguration ||
79         state == shill::kStatePortal ||
80         state == shill::kStateReady) {
81       active_service_list_out->push_back(service_path);
82     } else {
83       inactive_service_list_out->push_back(service_path);
84     }
85   }
86 }
87
88 void LogErrorCallback(const std::string& error_name,
89                       const std::string& error_message) {
90   LOG(ERROR) << error_name << ": " << error_message;
91 }
92
93 bool IsConnectedState(const std::string& state) {
94   return state == shill::kStateOnline || state == shill::kStatePortal ||
95          state == shill::kStateReady;
96 }
97
98 void UpdatePortaledWifiState(const std::string& service_path) {
99   DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface()
100       ->SetServiceProperty(service_path,
101                            shill::kStateProperty,
102                            base::StringValue(shill::kStatePortal));
103 }
104
105 const char* kTechnologyUnavailable = "unavailable";
106 const char* kNetworkActivated = "activated";
107 const char* kNetworkDisabled = "disabled";
108 const char* kCellularServicePath = "/service/cellular1";
109
110 }  // namespace
111
112 // static
113 const char FakeShillManagerClient::kFakeEthernetNetworkGuid[] = "eth1_guid";
114
115 FakeShillManagerClient::FakeShillManagerClient()
116     : interactive_delay_(0),
117       weak_ptr_factory_(this) {
118   ParseCommandLineSwitch();
119 }
120
121 FakeShillManagerClient::~FakeShillManagerClient() {}
122
123 // ShillManagerClient overrides.
124
125 void FakeShillManagerClient::Init(dbus::Bus* bus) {}
126
127 void FakeShillManagerClient::AddPropertyChangedObserver(
128     ShillPropertyChangedObserver* observer) {
129   observer_list_.AddObserver(observer);
130 }
131
132 void FakeShillManagerClient::RemovePropertyChangedObserver(
133     ShillPropertyChangedObserver* observer) {
134   observer_list_.RemoveObserver(observer);
135 }
136
137 void FakeShillManagerClient::GetProperties(
138     const DictionaryValueCallback& callback) {
139   DVLOG(1) << "Manager.GetProperties";
140   base::MessageLoop::current()->PostTask(
141       FROM_HERE, base::Bind(
142           &FakeShillManagerClient::PassStubProperties,
143           weak_ptr_factory_.GetWeakPtr(),
144           callback));
145 }
146
147 void FakeShillManagerClient::GetNetworksForGeolocation(
148     const DictionaryValueCallback& callback) {
149   base::MessageLoop::current()->PostTask(
150       FROM_HERE, base::Bind(
151           &FakeShillManagerClient::PassStubGeoNetworks,
152           weak_ptr_factory_.GetWeakPtr(),
153           callback));
154 }
155
156 void FakeShillManagerClient::SetProperty(const std::string& name,
157                                          const base::Value& value,
158                                          const base::Closure& callback,
159                                          const ErrorCallback& error_callback) {
160   DVLOG(2) << "SetProperty: " << name;
161   stub_properties_.SetWithoutPathExpansion(name, value.DeepCopy());
162   CallNotifyObserversPropertyChanged(name);
163   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
164 }
165
166 void FakeShillManagerClient::RequestScan(const std::string& type,
167                                          const base::Closure& callback,
168                                          const ErrorCallback& error_callback) {
169   // For Stub purposes, default to a Wifi scan.
170   std::string device_type = shill::kTypeWifi;
171   if (!type.empty())
172     device_type = type;
173   ShillDeviceClient::TestInterface* device_client =
174       DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
175   std::string device_path = device_client->GetDevicePathForType(device_type);
176   if (!device_path.empty()) {
177     device_client->SetDeviceProperty(
178         device_path, shill::kScanningProperty, base::FundamentalValue(true));
179   }
180   base::MessageLoop::current()->PostDelayedTask(
181       FROM_HERE,
182       base::Bind(&FakeShillManagerClient::ScanCompleted,
183                  weak_ptr_factory_.GetWeakPtr(),
184                  device_path,
185                  callback),
186       base::TimeDelta::FromSeconds(interactive_delay_));
187 }
188
189 void FakeShillManagerClient::EnableTechnology(
190     const std::string& type,
191     const base::Closure& callback,
192     const ErrorCallback& error_callback) {
193   base::ListValue* enabled_list = NULL;
194   if (!stub_properties_.GetListWithoutPathExpansion(
195           shill::kAvailableTechnologiesProperty, &enabled_list)) {
196     base::MessageLoop::current()->PostTask(FROM_HERE, callback);
197     base::MessageLoop::current()->PostTask(
198         FROM_HERE,
199         base::Bind(error_callback, "StubError", "Property not found"));
200     return;
201   }
202   base::MessageLoop::current()->PostDelayedTask(
203       FROM_HERE,
204       base::Bind(&FakeShillManagerClient::SetTechnologyEnabled,
205                  weak_ptr_factory_.GetWeakPtr(),
206                  type,
207                  callback,
208                  true),
209       base::TimeDelta::FromSeconds(interactive_delay_));
210 }
211
212 void FakeShillManagerClient::DisableTechnology(
213     const std::string& type,
214     const base::Closure& callback,
215     const ErrorCallback& error_callback) {
216   base::ListValue* enabled_list = NULL;
217   if (!stub_properties_.GetListWithoutPathExpansion(
218           shill::kAvailableTechnologiesProperty, &enabled_list)) {
219     base::MessageLoop::current()->PostTask(
220         FROM_HERE,
221         base::Bind(error_callback, "StubError", "Property not found"));
222     return;
223   }
224   base::MessageLoop::current()->PostDelayedTask(
225       FROM_HERE,
226       base::Bind(&FakeShillManagerClient::SetTechnologyEnabled,
227                  weak_ptr_factory_.GetWeakPtr(),
228                  type,
229                  callback,
230                  false),
231       base::TimeDelta::FromSeconds(interactive_delay_));
232 }
233
234 void FakeShillManagerClient::ConfigureService(
235     const base::DictionaryValue& properties,
236     const ObjectPathCallback& callback,
237     const ErrorCallback& error_callback) {
238   ShillServiceClient::TestInterface* service_client =
239       DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
240
241   std::string guid;
242   std::string type;
243   if (!properties.GetString(shill::kGuidProperty, &guid) ||
244       !properties.GetString(shill::kTypeProperty, &type)) {
245     LOG(ERROR) << "ConfigureService requires GUID and Type to be defined";
246     // If the properties aren't filled out completely, then just return an empty
247     // object path.
248     base::MessageLoop::current()->PostTask(
249         FROM_HERE, base::Bind(callback, dbus::ObjectPath()));
250     return;
251   }
252
253   // For the purposes of this stub, we're going to assume that the GUID property
254   // is set to the service path because we don't want to re-implement Shill's
255   // property matching magic here.
256   std::string service_path = guid;
257
258   std::string ipconfig_path;
259   properties.GetString(shill::kIPConfigProperty, &ipconfig_path);
260
261   // Merge the new properties with existing properties, if any.
262   const base::DictionaryValue* existing_properties =
263       service_client->GetServiceProperties(service_path);
264   if (!existing_properties) {
265     // Add a new service to the service client stub because none exists, yet.
266     // This calls AddManagerService.
267     service_client->AddServiceWithIPConfig(service_path,
268                                            guid /* guid */,
269                                            guid /* name */,
270                                            type,
271                                            shill::kStateIdle,
272                                            ipconfig_path,
273                                            true /* visible */);
274     existing_properties = service_client->GetServiceProperties(service_path);
275   }
276
277   scoped_ptr<base::DictionaryValue> merged_properties(
278       existing_properties->DeepCopy());
279   merged_properties->MergeDictionary(&properties);
280
281   // Now set all the properties.
282   for (base::DictionaryValue::Iterator iter(*merged_properties);
283        !iter.IsAtEnd(); iter.Advance()) {
284     service_client->SetServiceProperty(service_path, iter.key(), iter.value());
285   }
286
287   // If the Profile property is set, add it to ProfileClient.
288   std::string profile_path;
289   merged_properties->GetStringWithoutPathExpansion(shill::kProfileProperty,
290                                                    &profile_path);
291   if (!profile_path.empty()) {
292     DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface()->
293         AddService(profile_path, service_path);
294   }
295
296   base::MessageLoop::current()->PostTask(
297       FROM_HERE, base::Bind(callback, dbus::ObjectPath(service_path)));
298 }
299
300 void FakeShillManagerClient::ConfigureServiceForProfile(
301     const dbus::ObjectPath& profile_path,
302     const base::DictionaryValue& properties,
303     const ObjectPathCallback& callback,
304     const ErrorCallback& error_callback) {
305   std::string profile_property;
306   properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
307                                            &profile_property);
308   CHECK(profile_property == profile_path.value());
309   ConfigureService(properties, callback, error_callback);
310 }
311
312
313 void FakeShillManagerClient::GetService(
314     const base::DictionaryValue& properties,
315     const ObjectPathCallback& callback,
316     const ErrorCallback& error_callback) {
317   base::MessageLoop::current()->PostTask(
318       FROM_HERE, base::Bind(callback, dbus::ObjectPath()));
319 }
320
321 void FakeShillManagerClient::VerifyDestination(
322     const VerificationProperties& properties,
323     const BooleanCallback& callback,
324     const ErrorCallback& error_callback) {
325   base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
326 }
327
328 void FakeShillManagerClient::VerifyAndEncryptCredentials(
329     const VerificationProperties& properties,
330     const std::string& service_path,
331     const StringCallback& callback,
332     const ErrorCallback& error_callback) {
333   base::MessageLoop::current()->PostTask(
334       FROM_HERE, base::Bind(callback, "encrypted_credentials"));
335 }
336
337 void FakeShillManagerClient::VerifyAndEncryptData(
338     const VerificationProperties& properties,
339     const std::string& data,
340     const StringCallback& callback,
341     const ErrorCallback& error_callback) {
342   base::MessageLoop::current()->PostTask(
343       FROM_HERE, base::Bind(callback, "encrypted_data"));
344 }
345
346 void FakeShillManagerClient::ConnectToBestServices(
347     const base::Closure& callback,
348     const ErrorCallback& error_callback) {
349   if (best_service_.empty()) {
350     VLOG(1) << "No 'best' service set.";
351     return;
352   }
353
354   DBusThreadManager::Get()->GetShillServiceClient()->Connect(
355       dbus::ObjectPath(best_service_), callback, error_callback);
356 }
357
358 ShillManagerClient::TestInterface* FakeShillManagerClient::GetTestInterface() {
359   return this;
360 }
361
362 // ShillManagerClient::TestInterface overrides.
363
364 void FakeShillManagerClient::AddDevice(const std::string& device_path) {
365   if (GetListProperty(shill::kDevicesProperty)
366           ->AppendIfNotPresent(new base::StringValue(device_path))) {
367     CallNotifyObserversPropertyChanged(shill::kDevicesProperty);
368   }
369 }
370
371 void FakeShillManagerClient::RemoveDevice(const std::string& device_path) {
372   base::StringValue device_path_value(device_path);
373   if (GetListProperty(shill::kDevicesProperty)->Remove(
374       device_path_value, NULL)) {
375     CallNotifyObserversPropertyChanged(shill::kDevicesProperty);
376   }
377 }
378
379 void FakeShillManagerClient::ClearDevices() {
380   GetListProperty(shill::kDevicesProperty)->Clear();
381   CallNotifyObserversPropertyChanged(shill::kDevicesProperty);
382 }
383
384 void FakeShillManagerClient::AddTechnology(const std::string& type,
385                                            bool enabled) {
386   if (GetListProperty(shill::kAvailableTechnologiesProperty)
387           ->AppendIfNotPresent(new base::StringValue(type))) {
388     CallNotifyObserversPropertyChanged(
389         shill::kAvailableTechnologiesProperty);
390   }
391   if (enabled &&
392       GetListProperty(shill::kEnabledTechnologiesProperty)
393           ->AppendIfNotPresent(new base::StringValue(type))) {
394     CallNotifyObserversPropertyChanged(
395         shill::kEnabledTechnologiesProperty);
396   }
397 }
398
399 void FakeShillManagerClient::RemoveTechnology(const std::string& type) {
400   base::StringValue type_value(type);
401   if (GetListProperty(shill::kAvailableTechnologiesProperty)->Remove(
402       type_value, NULL)) {
403     CallNotifyObserversPropertyChanged(
404         shill::kAvailableTechnologiesProperty);
405   }
406   if (GetListProperty(shill::kEnabledTechnologiesProperty)->Remove(
407       type_value, NULL)) {
408     CallNotifyObserversPropertyChanged(
409         shill::kEnabledTechnologiesProperty);
410   }
411 }
412
413 void FakeShillManagerClient::SetTechnologyInitializing(const std::string& type,
414                                                        bool initializing) {
415   if (initializing) {
416     if (GetListProperty(shill::kUninitializedTechnologiesProperty)
417             ->AppendIfNotPresent(new base::StringValue(type))) {
418       CallNotifyObserversPropertyChanged(
419           shill::kUninitializedTechnologiesProperty);
420     }
421   } else {
422     if (GetListProperty(shill::kUninitializedTechnologiesProperty)->Remove(
423             base::StringValue(type), NULL)) {
424       CallNotifyObserversPropertyChanged(
425           shill::kUninitializedTechnologiesProperty);
426     }
427   }
428 }
429
430 void FakeShillManagerClient::AddGeoNetwork(
431     const std::string& technology,
432     const base::DictionaryValue& network) {
433   base::ListValue* list_value = NULL;
434   if (!stub_geo_networks_.GetListWithoutPathExpansion(technology,
435                                                       &list_value)) {
436     list_value = new base::ListValue;
437     stub_geo_networks_.SetWithoutPathExpansion(technology, list_value);
438   }
439   list_value->Append(network.DeepCopy());
440 }
441
442 void FakeShillManagerClient::AddProfile(const std::string& profile_path) {
443   const char* key = shill::kProfilesProperty;
444   if (GetListProperty(key)
445           ->AppendIfNotPresent(new base::StringValue(profile_path))) {
446     CallNotifyObserversPropertyChanged(key);
447   }
448 }
449
450 void FakeShillManagerClient::ClearProperties() {
451   stub_properties_.Clear();
452 }
453
454 void FakeShillManagerClient::SetManagerProperty(const std::string& key,
455                                                 const base::Value& value) {
456   SetProperty(key, value,
457               base::Bind(&base::DoNothing), base::Bind(&LogErrorCallback));
458 }
459
460 void FakeShillManagerClient::AddManagerService(
461     const std::string& service_path,
462     bool notify_observers) {
463   DVLOG(2) << "AddManagerService: " << service_path;
464   GetListProperty(shill::kServiceCompleteListProperty)
465       ->AppendIfNotPresent(new base::StringValue(service_path));
466   SortManagerServices(false);
467   if (notify_observers)
468     CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
469 }
470
471 void FakeShillManagerClient::RemoveManagerService(
472     const std::string& service_path) {
473   DVLOG(2) << "RemoveManagerService: " << service_path;
474   base::StringValue service_path_value(service_path);
475   GetListProperty(shill::kServiceCompleteListProperty)->Remove(
476       service_path_value, NULL);
477   CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
478 }
479
480 void FakeShillManagerClient::ClearManagerServices() {
481   DVLOG(1) << "ClearManagerServices";
482   GetListProperty(shill::kServiceCompleteListProperty)->Clear();
483   CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
484 }
485
486 void FakeShillManagerClient::ServiceStateChanged(
487     const std::string& service_path,
488     const std::string& state) {
489   if (service_path == default_service_ && !IsConnectedState(state)) {
490     // Default service is no longer connected; clear.
491     default_service_.clear();
492     base::StringValue default_service_value(default_service_);
493     SetManagerProperty(shill::kDefaultServiceProperty, default_service_value);
494   }
495 }
496
497 void FakeShillManagerClient::SortManagerServices(bool notify) {
498   DVLOG(1) << "SortManagerServices";
499   static const char* ordered_types[] = {shill::kTypeEthernet,
500                                         shill::kTypeEthernetEap,
501                                         shill::kTypeWifi,
502                                         shill::kTypeCellular,
503                                         shill::kTypeWimax,
504                                         shill::kTypeVPN};
505
506   base::ListValue* complete_list =
507       GetListProperty(shill::kServiceCompleteListProperty);
508   if (complete_list->empty())
509     return;
510   scoped_ptr<base::ListValue> prev_complete_list(complete_list->DeepCopy());
511
512   std::vector<std::string> active_services;
513   std::vector<std::string> inactive_services;
514   std::vector<std::string> disabled_services;
515   for (size_t i = 0; i < arraysize(ordered_types); ++i) {
516     AppendServicesForType(complete_list,
517                           ordered_types[i],
518                           TechnologyEnabled(ordered_types[i]),
519                           &active_services,
520                           &inactive_services,
521                           &disabled_services);
522   }
523   complete_list->Clear();
524   for (size_t i = 0; i < active_services.size(); ++i)
525     complete_list->AppendString(active_services[i]);
526   for (size_t i = 0; i < inactive_services.size(); ++i)
527     complete_list->AppendString(inactive_services[i]);
528   for (size_t i = 0; i < disabled_services.size(); ++i)
529     complete_list->AppendString(disabled_services[i]);
530
531   if (notify && !complete_list->Equals(prev_complete_list.get()))
532     CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
533
534   // Set the first active service as the Default service.
535   std::string new_default_service;
536   if (!active_services.empty()) {
537     ShillServiceClient::TestInterface* service_client =
538         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
539     std::string service_path = active_services[0];
540     const base::DictionaryValue* properties =
541         service_client->GetServiceProperties(service_path);
542     if (!properties) {
543       LOG(ERROR) << "Properties not found for service: " << service_path;
544     } else {
545       std::string state;
546       properties->GetString(shill::kStateProperty, &state);
547       if (IsConnectedState(state))
548         new_default_service = service_path;
549     }
550   }
551   if (default_service_ != new_default_service) {
552     default_service_ = new_default_service;
553     base::StringValue default_service_value(default_service_);
554     SetManagerProperty(shill::kDefaultServiceProperty, default_service_value);
555   }
556 }
557
558 int FakeShillManagerClient::GetInteractiveDelay() const {
559   return interactive_delay_;
560 }
561
562 void FakeShillManagerClient::SetBestServiceToConnect(
563     const std::string& service_path) {
564   best_service_ = service_path;
565 }
566
567 void FakeShillManagerClient::SetupDefaultEnvironment() {
568   DBusThreadManager* dbus_manager = DBusThreadManager::Get();
569   ShillServiceClient::TestInterface* services =
570       dbus_manager->GetShillServiceClient()->GetTestInterface();
571   DCHECK(services);
572   ShillProfileClient::TestInterface* profiles =
573       dbus_manager->GetShillProfileClient()->GetTestInterface();
574   DCHECK(profiles);
575   ShillDeviceClient::TestInterface* devices =
576       dbus_manager->GetShillDeviceClient()->GetTestInterface();
577   DCHECK(devices);
578   ShillIPConfigClient::TestInterface* ip_configs =
579       dbus_manager->GetShillIPConfigClient()->GetTestInterface();
580   DCHECK(ip_configs);
581
582   const std::string shared_profile = ShillProfileClient::GetSharedProfilePath();
583   profiles->AddProfile(shared_profile, std::string());
584
585   const bool add_to_visible = true;
586
587   // IPConfigs
588   base::DictionaryValue ipconfig_v4_dictionary;
589   ipconfig_v4_dictionary.SetStringWithoutPathExpansion(
590       shill::kAddressProperty, "0.0.0.0");
591   ipconfig_v4_dictionary.SetStringWithoutPathExpansion(
592       shill::kGatewayProperty, "0.0.0.1");
593   ipconfig_v4_dictionary.SetIntegerWithoutPathExpansion(
594       shill::kPrefixlenProperty, 0);
595   ipconfig_v4_dictionary.SetStringWithoutPathExpansion(
596       shill::kMethodProperty, shill::kTypeIPv4);
597   ip_configs->AddIPConfig("ipconfig_v4_path", ipconfig_v4_dictionary);
598   base::DictionaryValue ipconfig_v6_dictionary;
599   ipconfig_v6_dictionary.SetStringWithoutPathExpansion(
600       shill::kAddressProperty, "0:0:0:0:0:0:0:0");
601   ipconfig_v6_dictionary.SetStringWithoutPathExpansion(
602       shill::kMethodProperty, shill::kTypeIPv6);
603   ip_configs->AddIPConfig("ipconfig_v6_path", ipconfig_v6_dictionary);
604
605   bool enabled;
606   std::string state;
607
608   // Ethernet
609   state = GetInitialStateForType(shill::kTypeEthernet, &enabled);
610   if (state == shill::kStateOnline) {
611     AddTechnology(shill::kTypeEthernet, enabled);
612     devices->AddDevice(
613         "/device/eth1", shill::kTypeEthernet, "stub_eth_device1");
614     devices->SetDeviceProperty("/device/eth1",
615                                shill::kAddressProperty,
616                                base::StringValue("0123456789ab"));
617     base::ListValue eth_ip_configs;
618     eth_ip_configs.AppendString("ipconfig_v4_path");
619     eth_ip_configs.AppendString("ipconfig_v6_path");
620     devices->SetDeviceProperty("/device/eth1",
621                                shill::kIPConfigsProperty,
622                                eth_ip_configs);
623     const std::string kFakeEthernetNetworkPath = "/service/eth1";
624     services->AddService(kFakeEthernetNetworkPath,
625                          kFakeEthernetNetworkGuid,
626                          "eth1" /* name */,
627                          shill::kTypeEthernet,
628                          state,
629                          add_to_visible);
630     profiles->AddService(shared_profile, kFakeEthernetNetworkPath);
631   }
632
633   // Wifi
634   state = GetInitialStateForType(shill::kTypeWifi, &enabled);
635   if (state != kTechnologyUnavailable) {
636     bool portaled = false;
637     if (state == shill::kStatePortal) {
638       portaled = true;
639       state = shill::kStateIdle;
640     }
641     AddTechnology(shill::kTypeWifi, enabled);
642     devices->AddDevice("/device/wifi1", shill::kTypeWifi, "stub_wifi_device1");
643     devices->SetDeviceProperty("/device/wifi1",
644                                shill::kAddressProperty,
645                                base::StringValue("23456789abc"));
646     base::ListValue wifi_ip_configs;
647     wifi_ip_configs.AppendString("ipconfig_v4_path");
648     wifi_ip_configs.AppendString("ipconfig_v6_path");
649     devices->SetDeviceProperty("/device/wifi1",
650                                shill::kIPConfigsProperty,
651                                wifi_ip_configs);
652
653     const std::string kWifi1Path = "/service/wifi1";
654     services->AddService(kWifi1Path,
655                          "wifi1_guid",
656                          "wifi1" /* name */,
657                          shill::kTypeWifi,
658                          state,
659                          add_to_visible);
660     services->SetServiceProperty(kWifi1Path,
661                                  shill::kSecurityProperty,
662                                  base::StringValue(shill::kSecurityWep));
663     services->SetServiceProperty(kWifi1Path,
664                                  shill::kConnectableProperty,
665                                  base::FundamentalValue(true));
666     profiles->AddService(shared_profile, kWifi1Path);
667
668     const std::string kWifi2Path = "/service/wifi2";
669     services->AddService(kWifi2Path,
670                          "wifi2_PSK_guid",
671                          "wifi2_PSK" /* name */,
672                          shill::kTypeWifi,
673                          shill::kStateIdle,
674                          add_to_visible);
675     services->SetServiceProperty(kWifi2Path,
676                                  shill::kSecurityProperty,
677                                  base::StringValue(shill::kSecurityPsk));
678
679     base::FundamentalValue strength_value(80);
680     services->SetServiceProperty(
681         kWifi2Path, shill::kSignalStrengthProperty, strength_value);
682     profiles->AddService(shared_profile, kWifi2Path);
683
684     if (portaled) {
685       const std::string kPortaledWifiPath = "/service/portaled_wifi";
686       services->AddService(kPortaledWifiPath,
687                            "portaled_wifi_guid",
688                            "Portaled Wifi" /* name */,
689                            shill::kTypeWifi,
690                            shill::kStatePortal,
691                            add_to_visible);
692       services->SetServiceProperty(kPortaledWifiPath,
693                                    shill::kSecurityProperty,
694                                    base::StringValue(shill::kSecurityNone));
695       services->SetConnectBehavior(kPortaledWifiPath,
696                                    base::Bind(&UpdatePortaledWifiState,
697                                               "portaled_wifi"));
698       services->SetServiceProperty(kPortaledWifiPath,
699                                    shill::kConnectableProperty,
700                                    base::FundamentalValue(true));
701       profiles->AddService(shared_profile, kPortaledWifiPath);
702     }
703   }
704
705   // Wimax
706   state = GetInitialStateForType(shill::kTypeWimax, &enabled);
707   if (state != kTechnologyUnavailable) {
708     AddTechnology(shill::kTypeWimax, enabled);
709     devices->AddDevice(
710         "/device/wimax1", shill::kTypeWimax, "stub_wimax_device1");
711
712     services->AddService("/service/wimax1",
713                          "wimax1_guid",
714                          "wimax1" /* name */,
715                          shill::kTypeWimax,
716                          state,
717                          add_to_visible);
718     services->SetServiceProperty("/service/wimax1",
719                                  shill::kConnectableProperty,
720                                  base::FundamentalValue(true));
721     base::FundamentalValue strength_value(80);
722     services->SetServiceProperty(
723         "/service/wimax1", shill::kSignalStrengthProperty, strength_value);
724     base::StringValue identity_value("test.identity");
725     services->SetServiceProperty(
726         "/service/wimax1", shill::kEapIdentityProperty, identity_value);
727   }
728
729   // Cellular
730   state = GetInitialStateForType(shill::kTypeCellular, &enabled);
731   if (state != kTechnologyUnavailable) {
732     bool activated = false;
733     if (state == kNetworkActivated) {
734       activated = true;
735       state = shill::kStateIdle;
736     }
737     AddTechnology(shill::kTypeCellular, enabled);
738     devices->AddDevice(
739         "/device/cellular1", shill::kTypeCellular, "stub_cellular_device1");
740     devices->SetDeviceProperty("/device/cellular1",
741                                shill::kCarrierProperty,
742                                base::StringValue(shill::kCarrierSprint));
743
744     services->AddService(kCellularServicePath,
745                          "cellular1_guid",
746                          "cellular1" /* name */,
747                          shill::kTypeCellular,
748                          state,
749                          add_to_visible);
750     base::StringValue technology_value(shill::kNetworkTechnologyGsm);
751     services->SetServiceProperty(kCellularServicePath,
752                                  shill::kNetworkTechnologyProperty,
753                                  technology_value);
754
755     if (activated) {
756       services->SetServiceProperty(
757           kCellularServicePath,
758           shill::kActivationStateProperty,
759           base::StringValue(shill::kActivationStateActivated));
760       services->SetServiceProperty(kCellularServicePath,
761                                    shill::kConnectableProperty,
762                                    base::FundamentalValue(true));
763     } else {
764       services->SetServiceProperty(
765           kCellularServicePath,
766           shill::kActivationStateProperty,
767           base::StringValue(shill::kActivationStateNotActivated));
768     }
769
770     services->SetServiceProperty(kCellularServicePath,
771                                  shill::kRoamingStateProperty,
772                                  base::StringValue(shill::kRoamingStateHome));
773   }
774
775   // VPN
776   state = GetInitialStateForType(shill::kTypeVPN, &enabled);
777   if (state != kTechnologyUnavailable) {
778     // Set the "Provider" dictionary properties. Note: when setting these in
779     // Shill, "Provider.Type", etc keys are used, but when reading the values
780     // "Provider" . "Type", etc keys are used. Here we are setting the values
781     // that will be read (by the UI, tests, etc).
782     base::DictionaryValue provider_properties;
783     provider_properties.SetString(shill::kTypeProperty,
784                                   shill::kProviderOpenVpn);
785     provider_properties.SetString(shill::kHostProperty, "vpn_host");
786
787     services->AddService("/service/vpn1",
788                          "vpn1_guid",
789                          "vpn1" /* name */,
790                          shill::kTypeVPN,
791                          state,
792                          add_to_visible);
793     services->SetServiceProperty(
794         "/service/vpn1", shill::kProviderProperty, provider_properties);
795     profiles->AddService(shared_profile, "/service/vpn1");
796
797     services->AddService("/service/vpn2",
798                          "vpn2_guid",
799                          "vpn2" /* name */,
800                          shill::kTypeVPN,
801                          shill::kStateIdle,
802                          add_to_visible);
803     services->SetServiceProperty(
804         "/service/vpn2", shill::kProviderProperty, provider_properties);
805   }
806
807   // Additional device states
808   for (DevicePropertyMap::iterator iter1 = shill_device_property_map_.begin();
809        iter1 != shill_device_property_map_.end(); ++iter1) {
810     std::string device_type = iter1->first;
811     std::string device_path = devices->GetDevicePathForType(device_type);
812     for (ShillPropertyMap::iterator iter2 = iter1->second.begin();
813          iter2 != iter1->second.end(); ++iter2) {
814       devices->SetDeviceProperty(device_path, iter2->first, *(iter2->second));
815       delete iter2->second;
816     }
817   }
818
819   SortManagerServices(true);
820 }
821
822 // Private methods
823
824 void FakeShillManagerClient::PassStubProperties(
825     const DictionaryValueCallback& callback) const {
826   scoped_ptr<base::DictionaryValue> stub_properties(
827       stub_properties_.DeepCopy());
828   stub_properties->SetWithoutPathExpansion(
829       shill::kServiceCompleteListProperty,
830       GetEnabledServiceList(shill::kServiceCompleteListProperty));
831   callback.Run(DBUS_METHOD_CALL_SUCCESS, *stub_properties);
832 }
833
834 void FakeShillManagerClient::PassStubGeoNetworks(
835     const DictionaryValueCallback& callback) const {
836   callback.Run(DBUS_METHOD_CALL_SUCCESS, stub_geo_networks_);
837 }
838
839 void FakeShillManagerClient::CallNotifyObserversPropertyChanged(
840     const std::string& property) {
841   // Avoid unnecessary delayed task if we have no observers (e.g. during
842   // initial setup).
843   if (!observer_list_.might_have_observers())
844     return;
845   base::MessageLoop::current()->PostTask(
846       FROM_HERE,
847       base::Bind(&FakeShillManagerClient::NotifyObserversPropertyChanged,
848                  weak_ptr_factory_.GetWeakPtr(),
849                  property));
850 }
851
852 void FakeShillManagerClient::NotifyObserversPropertyChanged(
853     const std::string& property) {
854   DVLOG(1) << "NotifyObserversPropertyChanged: " << property;
855   base::Value* value = NULL;
856   if (!stub_properties_.GetWithoutPathExpansion(property, &value)) {
857     LOG(ERROR) << "Notify for unknown property: " << property;
858     return;
859   }
860   if (property == shill::kServiceCompleteListProperty) {
861     scoped_ptr<base::ListValue> services(GetEnabledServiceList(property));
862     FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
863                       observer_list_,
864                       OnPropertyChanged(property, *(services.get())));
865     return;
866   }
867   FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
868                     observer_list_,
869                     OnPropertyChanged(property, *value));
870 }
871
872 base::ListValue* FakeShillManagerClient::GetListProperty(
873     const std::string& property) {
874   base::ListValue* list_property = NULL;
875   if (!stub_properties_.GetListWithoutPathExpansion(
876       property, &list_property)) {
877     list_property = new base::ListValue;
878     stub_properties_.SetWithoutPathExpansion(property, list_property);
879   }
880   return list_property;
881 }
882
883 bool FakeShillManagerClient::TechnologyEnabled(const std::string& type) const {
884   if (type == shill::kTypeVPN)
885     return true;  // VPN is always "enabled" since there is no associated device
886   if (type == shill::kTypeEthernetEap)
887     return true;
888   bool enabled = false;
889   const base::ListValue* technologies;
890   if (stub_properties_.GetListWithoutPathExpansion(
891           shill::kEnabledTechnologiesProperty, &technologies)) {
892     base::StringValue type_value(type);
893     if (technologies->Find(type_value) != technologies->end())
894       enabled = true;
895   }
896   return enabled;
897 }
898
899 void FakeShillManagerClient::SetTechnologyEnabled(
900     const std::string& type,
901     const base::Closure& callback,
902     bool enabled) {
903   base::ListValue* enabled_list =
904       GetListProperty(shill::kEnabledTechnologiesProperty);
905   if (enabled)
906     enabled_list->AppendIfNotPresent(new base::StringValue(type));
907   else
908     enabled_list->Remove(base::StringValue(type), NULL);
909   CallNotifyObserversPropertyChanged(
910       shill::kEnabledTechnologiesProperty);
911   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
912   // May affect available services.
913   SortManagerServices(true);
914 }
915
916 base::ListValue* FakeShillManagerClient::GetEnabledServiceList(
917     const std::string& property) const {
918   base::ListValue* new_service_list = new base::ListValue;
919   const base::ListValue* service_list;
920   if (stub_properties_.GetListWithoutPathExpansion(property, &service_list)) {
921     ShillServiceClient::TestInterface* service_client =
922         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
923     for (base::ListValue::const_iterator iter = service_list->begin();
924          iter != service_list->end(); ++iter) {
925       std::string service_path;
926       if (!(*iter)->GetAsString(&service_path))
927         continue;
928       const base::DictionaryValue* properties =
929           service_client->GetServiceProperties(service_path);
930       if (!properties) {
931         LOG(ERROR) << "Properties not found for service: " << service_path;
932         continue;
933       }
934       std::string type;
935       properties->GetString(shill::kTypeProperty, &type);
936       if (TechnologyEnabled(type))
937         new_service_list->Append((*iter)->DeepCopy());
938     }
939   }
940   return new_service_list;
941 }
942
943 void FakeShillManagerClient::ScanCompleted(const std::string& device_path,
944                                            const base::Closure& callback) {
945   if (!device_path.empty()) {
946     DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface()->
947         SetDeviceProperty(device_path,
948                           shill::kScanningProperty,
949                           base::FundamentalValue(false));
950   }
951   DVLOG(2) << "ScanCompleted";
952   CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
953   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
954 }
955
956 void FakeShillManagerClient::ParseCommandLineSwitch() {
957   // Default setup
958   SetInitialNetworkState(shill::kTypeEthernet, shill::kStateOnline);
959   SetInitialNetworkState(shill::kTypeWifi, shill::kStateOnline);
960   SetInitialNetworkState(shill::kTypeCellular, shill::kStateIdle);
961   SetInitialNetworkState(shill::kTypeVPN, shill::kStateIdle);
962
963   // Parse additional options
964   CommandLine* command_line = CommandLine::ForCurrentProcess();
965   if (!command_line->HasSwitch(switches::kShillStub))
966     return;
967
968   std::string option_str =
969       command_line->GetSwitchValueASCII(switches::kShillStub);
970   VLOG(1) << "Parsing command line:" << option_str;
971   base::StringPairs string_pairs;
972   base::SplitStringIntoKeyValuePairs(option_str, '=', ',', &string_pairs);
973   for (base::StringPairs::iterator iter = string_pairs.begin();
974        iter != string_pairs.end(); ++iter) {
975     ParseOption((*iter).first, (*iter).second);
976   }
977 }
978
979 bool FakeShillManagerClient::ParseOption(const std::string& arg0,
980                                          const std::string& arg1) {
981   VLOG(1) << "Parsing command line option: '" << arg0 << "=" << arg1 << "'";
982   if ((arg0 == "clear" || arg0 == "reset") && arg1 == "1") {
983     shill_initial_state_map_.clear();
984     return true;
985   } else if (arg0 == "interactive") {
986     int seconds = 3;
987     if (!arg1.empty())
988       base::StringToInt(arg1, &seconds);
989     interactive_delay_ = seconds;
990     return true;
991   } else if (arg0 == "sim_lock") {
992     bool locked = (arg1 == "1") ? true : false;
993     base::DictionaryValue* simlock_dict = new base::DictionaryValue;
994     simlock_dict->Set(shill::kSIMLockEnabledProperty,
995                       new base::FundamentalValue(locked));
996   // TODO(stevenjb): Investigate why non-empty value breaks UI.
997   std::string lock_type = "";  // shill::kSIMLockPin
998     simlock_dict->SetString(shill::kSIMLockTypeProperty, lock_type);
999     simlock_dict->SetInteger(shill::kSIMLockRetriesLeftProperty, 5);
1000
1001     shill_device_property_map_
1002         [shill::kTypeCellular][shill::kSIMLockStatusProperty] = simlock_dict;
1003     shill_device_property_map_
1004         [shill::kTypeCellular][shill::kTechnologyFamilyProperty] =
1005             new base::StringValue(shill::kNetworkTechnologyGsm);
1006     return true;
1007   }
1008   return SetInitialNetworkState(arg0, arg1);
1009 }
1010
1011 bool FakeShillManagerClient::SetInitialNetworkState(std::string type_arg,
1012                                                     std::string state_arg) {
1013   std::string state;
1014   state_arg = base::StringToLowerASCII(state_arg);
1015   if (state_arg.empty() || state_arg == "1" || state_arg == "on" ||
1016       state_arg == "enabled" || state_arg == "connected" ||
1017       state_arg == "online") {
1018     // Enabled and connected (default value)
1019     state = shill::kStateOnline;
1020   } else if (state_arg == "0" || state_arg == "off" ||
1021              state_arg == "inactive" || state_arg == shill::kStateIdle) {
1022     // Technology enabled, services are created but are not connected.
1023     state = shill::kStateIdle;
1024   } else if (state_arg == "disabled" || state_arg == "disconnect") {
1025     // Technology disabled but available, services created but not connected.
1026     state = kNetworkDisabled;
1027   } else if (state_arg == "none" || state_arg == "offline") {
1028     // Technology not available, do not create services.
1029     state = kTechnologyUnavailable;
1030   } else if (state_arg == "portal") {
1031     // Technology is enabled, a service is connected and in Portal state.
1032     state = shill::kStatePortal;
1033   } else if (state_arg == "active" || state_arg == "activated") {
1034     // Technology is enabled, a service is connected and Activated.
1035     state = kNetworkActivated;
1036   } else {
1037     LOG(ERROR) << "Unrecognized initial state: " << state_arg;
1038     return false;
1039   }
1040
1041   type_arg = base::StringToLowerASCII(type_arg);
1042   // Special cases
1043   if (type_arg == "wireless") {
1044     shill_initial_state_map_[shill::kTypeWifi] = state;
1045     shill_initial_state_map_[shill::kTypeCellular] = state;
1046     return true;
1047   }
1048   // Convenience synonyms.
1049   if (type_arg == "eth")
1050     type_arg = shill::kTypeEthernet;
1051
1052   if (type_arg != shill::kTypeEthernet &&
1053       type_arg != shill::kTypeWifi &&
1054       type_arg != shill::kTypeCellular &&
1055       type_arg != shill::kTypeWimax &&
1056       type_arg != shill::kTypeVPN) {
1057     LOG(WARNING) << "Unrecognized Shill network type: " << type_arg;
1058     return false;
1059   }
1060
1061   // Unconnected or disabled ethernet is the same as unavailable.
1062   if (type_arg == shill::kTypeEthernet &&
1063       (state == shill::kStateIdle || state == kNetworkDisabled)) {
1064     state = kTechnologyUnavailable;
1065   }
1066
1067   shill_initial_state_map_[type_arg] = state;
1068   return true;
1069 }
1070
1071 std::string FakeShillManagerClient::GetInitialStateForType(
1072     const std::string& type,
1073     bool* enabled) {
1074   std::map<std::string, std::string>::const_iterator iter =
1075       shill_initial_state_map_.find(type);
1076   if (iter == shill_initial_state_map_.end()) {
1077     *enabled = false;
1078     return kTechnologyUnavailable;
1079   }
1080   std::string state = iter->second;
1081   if (state == kNetworkDisabled) {
1082     *enabled = false;
1083     return shill::kStateIdle;
1084   }
1085   *enabled = true;
1086   if ((state == shill::kStatePortal && type != shill::kTypeWifi) ||
1087       (state == kNetworkActivated && type != shill::kTypeCellular)) {
1088     LOG(WARNING) << "Invalid state: " << state << " for " << type;
1089     return shill::kStateIdle;
1090   }
1091   return state;
1092 }
1093
1094 }  // namespace chromeos