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