Home | History | Annotate | Download | only in dbus
      1 // Copyright (c) 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/shill_manager_client_stub.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/values.h"
     11 #include "chromeos/chromeos_switches.h"
     12 #include "chromeos/dbus/dbus_thread_manager.h"
     13 #include "chromeos/dbus/shill_device_client.h"
     14 #include "chromeos/dbus/shill_profile_client.h"
     15 #include "chromeos/dbus/shill_property_changed_observer.h"
     16 #include "chromeos/dbus/shill_service_client.h"
     17 #include "dbus/bus.h"
     18 #include "dbus/message.h"
     19 #include "dbus/object_path.h"
     20 #include "dbus/object_proxy.h"
     21 #include "dbus/values_util.h"
     22 #include "third_party/cros_system_api/dbus/service_constants.h"
     23 
     24 namespace chromeos {
     25 
     26 namespace {
     27 
     28 // Used to compare values for finding entries to erase in a ListValue.
     29 // (ListValue only implements a const_iterator version of Find).
     30 struct ValueEquals {
     31   explicit ValueEquals(const base::Value* first) : first_(first) {}
     32   bool operator()(const base::Value* second) const {
     33     return first_->Equals(second);
     34   }
     35   const base::Value* first_;
     36 };
     37 
     38 // Appends string entries from |service_list_in| whose entries in ServiceClient
     39 // have Type |match_type| to either an active list or an inactive list
     40 // based on the entry's State.
     41 void AppendServicesForType(
     42     const base::ListValue* service_list_in,
     43     const char* match_type,
     44     std::vector<std::string>* active_service_list_out,
     45     std::vector<std::string>* inactive_service_list_out) {
     46   ShillServiceClient::TestInterface* service_client =
     47       DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
     48   for (base::ListValue::const_iterator iter = service_list_in->begin();
     49        iter != service_list_in->end(); ++iter) {
     50     std::string service_path;
     51     if (!(*iter)->GetAsString(&service_path))
     52       continue;
     53     const base::DictionaryValue* properties =
     54         service_client->GetServiceProperties(service_path);
     55     if (!properties) {
     56       LOG(ERROR) << "Properties not found for service: " << service_path;
     57       continue;
     58     }
     59     std::string type;
     60     properties->GetString(flimflam::kTypeProperty, &type);
     61     if (type != match_type)
     62       continue;
     63     std::string state;
     64     properties->GetString(flimflam::kStateProperty, &state);
     65     if (state == flimflam::kStateOnline ||
     66         state == flimflam::kStateAssociation ||
     67         state == flimflam::kStateConfiguration ||
     68         state == flimflam::kStatePortal ||
     69         state == flimflam::kStateReady) {
     70       active_service_list_out->push_back(service_path);
     71     } else {
     72       inactive_service_list_out->push_back(service_path);
     73     }
     74   }
     75 }
     76 
     77 }  // namespace
     78 
     79 ShillManagerClientStub::ShillManagerClientStub()
     80     : weak_ptr_factory_(this) {
     81   SetDefaultProperties();
     82 }
     83 
     84 ShillManagerClientStub::~ShillManagerClientStub() {}
     85 
     86 // ShillManagerClient overrides.
     87 
     88 void ShillManagerClientStub::AddPropertyChangedObserver(
     89     ShillPropertyChangedObserver* observer) {
     90   observer_list_.AddObserver(observer);
     91 }
     92 
     93 void ShillManagerClientStub::RemovePropertyChangedObserver(
     94     ShillPropertyChangedObserver* observer) {
     95   observer_list_.RemoveObserver(observer);
     96 }
     97 
     98 void ShillManagerClientStub::GetProperties(
     99     const DictionaryValueCallback& callback) {
    100   base::MessageLoop::current()->PostTask(
    101       FROM_HERE, base::Bind(
    102           &ShillManagerClientStub::PassStubProperties,
    103           weak_ptr_factory_.GetWeakPtr(),
    104           callback));
    105 }
    106 
    107 void ShillManagerClientStub::GetNetworksForGeolocation(
    108     const DictionaryValueCallback& callback) {
    109   base::MessageLoop::current()->PostTask(
    110       FROM_HERE, base::Bind(
    111           &ShillManagerClientStub::PassStubGeoNetworks,
    112           weak_ptr_factory_.GetWeakPtr(),
    113           callback));
    114 }
    115 
    116 void ShillManagerClientStub::SetProperty(const std::string& name,
    117                                          const base::Value& value,
    118                                          const base::Closure& callback,
    119                                          const ErrorCallback& error_callback) {
    120   stub_properties_.SetWithoutPathExpansion(name, value.DeepCopy());
    121   CallNotifyObserversPropertyChanged(name, 0);
    122   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
    123 }
    124 
    125 void ShillManagerClientStub::RequestScan(const std::string& type,
    126                                          const base::Closure& callback,
    127                                          const ErrorCallback& error_callback) {
    128   // For Stub purposes, default to a Wifi scan.
    129   std::string device_type = flimflam::kTypeWifi;
    130   if (!type.empty())
    131     device_type = type;
    132   ShillDeviceClient::TestInterface* device_client =
    133       DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
    134   std::string device_path = device_client->GetDevicePathForType(device_type);
    135   if (!device_path.empty()) {
    136     device_client->SetDeviceProperty(device_path,
    137                                      flimflam::kScanningProperty,
    138                                      base::FundamentalValue(true));
    139   }
    140   const int kScanDurationSeconds = 3;
    141   int scan_duration_seconds = kScanDurationSeconds;
    142   if (!CommandLine::ForCurrentProcess()->HasSwitch(
    143       chromeos::switches::kEnableStubInteractive)) {
    144     scan_duration_seconds = 0;
    145   }
    146   base::MessageLoop::current()->PostDelayedTask(
    147       FROM_HERE,
    148       base::Bind(&ShillManagerClientStub::ScanCompleted,
    149                  weak_ptr_factory_.GetWeakPtr(), device_path, callback),
    150       base::TimeDelta::FromSeconds(scan_duration_seconds));
    151 }
    152 
    153 void ShillManagerClientStub::EnableTechnology(
    154     const std::string& type,
    155     const base::Closure& callback,
    156     const ErrorCallback& error_callback) {
    157   base::ListValue* enabled_list = NULL;
    158   if (!stub_properties_.GetListWithoutPathExpansion(
    159       flimflam::kEnabledTechnologiesProperty, &enabled_list)) {
    160     base::MessageLoop::current()->PostTask(FROM_HERE, callback);
    161     base::MessageLoop::current()->PostTask(
    162         FROM_HERE,
    163         base::Bind(error_callback, "StubError", "Property not found"));
    164     return;
    165   }
    166   if (CommandLine::ForCurrentProcess()->HasSwitch(
    167           chromeos::switches::kEnableStubInteractive)) {
    168     const int kEnableTechnologyDelaySeconds = 3;
    169     base::MessageLoop::current()->PostDelayedTask(
    170         FROM_HERE,
    171         base::Bind(&ShillManagerClientStub::SetTechnologyEnabled,
    172                    weak_ptr_factory_.GetWeakPtr(), type, callback, true),
    173         base::TimeDelta::FromSeconds(kEnableTechnologyDelaySeconds));
    174   } else {
    175     SetTechnologyEnabled(type, callback, true);
    176   }
    177 }
    178 
    179 void ShillManagerClientStub::DisableTechnology(
    180     const std::string& type,
    181     const base::Closure& callback,
    182     const ErrorCallback& error_callback) {
    183   base::ListValue* enabled_list = NULL;
    184   if (!stub_properties_.GetListWithoutPathExpansion(
    185       flimflam::kEnabledTechnologiesProperty, &enabled_list)) {
    186     base::MessageLoop::current()->PostTask(
    187         FROM_HERE,
    188         base::Bind(error_callback, "StubError", "Property not found"));
    189     return;
    190   }
    191   if (CommandLine::ForCurrentProcess()->HasSwitch(
    192           chromeos::switches::kEnableStubInteractive)) {
    193     const int kDisableTechnologyDelaySeconds = 3;
    194     base::MessageLoop::current()->PostDelayedTask(
    195         FROM_HERE,
    196         base::Bind(&ShillManagerClientStub::SetTechnologyEnabled,
    197                    weak_ptr_factory_.GetWeakPtr(), type, callback, false),
    198         base::TimeDelta::FromSeconds(kDisableTechnologyDelaySeconds));
    199   } else {
    200     SetTechnologyEnabled(type, callback, false);
    201   }
    202 }
    203 
    204 void ShillManagerClientStub::ConfigureService(
    205     const base::DictionaryValue& properties,
    206     const ObjectPathCallback& callback,
    207     const ErrorCallback& error_callback) {
    208   ShillServiceClient::TestInterface* service_client =
    209       DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
    210 
    211   std::string guid;
    212   std::string type;
    213   if (!properties.GetString(flimflam::kGuidProperty, &guid) ||
    214       !properties.GetString(flimflam::kTypeProperty, &type)) {
    215     LOG(ERROR) << "ConfigureService requies GUID and Type to be defined";
    216     // If the properties aren't filled out completely, then just return an empty
    217     // object path.
    218     base::MessageLoop::current()->PostTask(
    219         FROM_HERE, base::Bind(callback, dbus::ObjectPath()));
    220     return;
    221   }
    222 
    223   // For the purposes of this stub, we're going to assume that the GUID property
    224   // is set to the service path because we don't want to re-implement Shill's
    225   // property matching magic here.
    226   std::string service_path = guid;
    227 
    228   std::string ipconfig_path;
    229   properties.GetString(shill::kIPConfigProperty, &ipconfig_path);
    230 
    231   // Merge the new properties with existing properties, if any.
    232   const base::DictionaryValue* existing_properties =
    233       service_client->GetServiceProperties(service_path);
    234   if (!existing_properties) {
    235     // Add a new service to the service client stub because none exists, yet.
    236     // This calls AddManagerService.
    237     service_client->AddServiceWithIPConfig(service_path, guid, type,
    238                                            flimflam::kStateIdle, ipconfig_path,
    239                                            true /* visible */,
    240                                            true /* watch */);
    241     existing_properties = service_client->GetServiceProperties(service_path);
    242   }
    243 
    244   scoped_ptr<base::DictionaryValue> merged_properties(
    245       existing_properties->DeepCopy());
    246   merged_properties->MergeDictionary(&properties);
    247 
    248   // Now set all the properties.
    249   for (base::DictionaryValue::Iterator iter(*merged_properties);
    250        !iter.IsAtEnd(); iter.Advance()) {
    251     service_client->SetServiceProperty(service_path, iter.key(), iter.value());
    252   }
    253 
    254   // If the Profile property is set, add it to ProfileClient.
    255   std::string profile_path;
    256   merged_properties->GetStringWithoutPathExpansion(flimflam::kProfileProperty,
    257                                                    &profile_path);
    258   if (!profile_path.empty()) {
    259     DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface()->
    260         AddService(profile_path, service_path);
    261   }
    262 
    263   base::MessageLoop::current()->PostTask(
    264       FROM_HERE, base::Bind(callback, dbus::ObjectPath(service_path)));
    265 }
    266 
    267 void ShillManagerClientStub::ConfigureServiceForProfile(
    268     const dbus::ObjectPath& profile_path,
    269     const base::DictionaryValue& properties,
    270     const ObjectPathCallback& callback,
    271     const ErrorCallback& error_callback) {
    272   std::string profile_property;
    273   properties.GetStringWithoutPathExpansion(flimflam::kProfileProperty,
    274                                            &profile_property);
    275   CHECK(profile_property == profile_path.value());
    276   ConfigureService(properties, callback, error_callback);
    277 }
    278 
    279 
    280 void ShillManagerClientStub::GetService(
    281     const base::DictionaryValue& properties,
    282     const ObjectPathCallback& callback,
    283     const ErrorCallback& error_callback) {
    284   base::MessageLoop::current()->PostTask(
    285       FROM_HERE, base::Bind(callback, dbus::ObjectPath()));
    286 }
    287 
    288 void ShillManagerClientStub::VerifyDestination(
    289     const VerificationProperties& properties,
    290     const BooleanCallback& callback,
    291     const ErrorCallback& error_callback) {
    292   base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
    293 }
    294 
    295 void ShillManagerClientStub::VerifyAndEncryptCredentials(
    296     const VerificationProperties& properties,
    297     const std::string& service_path,
    298     const StringCallback& callback,
    299     const ErrorCallback& error_callback) {
    300   base::MessageLoop::current()->PostTask(
    301       FROM_HERE, base::Bind(callback, "encrypted_credentials"));
    302 }
    303 
    304 void ShillManagerClientStub::VerifyAndEncryptData(
    305     const VerificationProperties& properties,
    306     const std::string& data,
    307     const StringCallback& callback,
    308     const ErrorCallback& error_callback) {
    309   base::MessageLoop::current()->PostTask(FROM_HERE,
    310                                    base::Bind(callback, "encrypted_data"));
    311 }
    312 
    313 void ShillManagerClientStub::ConnectToBestServices(
    314     const base::Closure& callback,
    315     const ErrorCallback& error_callback) {
    316 }
    317 
    318 ShillManagerClient::TestInterface* ShillManagerClientStub::GetTestInterface() {
    319   return this;
    320 }
    321 
    322 // ShillManagerClient::TestInterface overrides.
    323 
    324 void ShillManagerClientStub::AddDevice(const std::string& device_path) {
    325   if (GetListProperty(flimflam::kDevicesProperty)->AppendIfNotPresent(
    326       base::Value::CreateStringValue(device_path))) {
    327     CallNotifyObserversPropertyChanged(flimflam::kDevicesProperty, 0);
    328   }
    329 }
    330 
    331 void ShillManagerClientStub::RemoveDevice(const std::string& device_path) {
    332   base::StringValue device_path_value(device_path);
    333   if (GetListProperty(flimflam::kDevicesProperty)->Remove(
    334       device_path_value, NULL)) {
    335     CallNotifyObserversPropertyChanged(flimflam::kDevicesProperty, 0);
    336   }
    337 }
    338 
    339 void ShillManagerClientStub::ClearDevices() {
    340   GetListProperty(flimflam::kDevicesProperty)->Clear();
    341   CallNotifyObserversPropertyChanged(flimflam::kDevicesProperty, 0);
    342 }
    343 
    344 void ShillManagerClientStub::AddTechnology(const std::string& type,
    345                                            bool enabled) {
    346   if (GetListProperty(flimflam::kAvailableTechnologiesProperty)->
    347       AppendIfNotPresent(base::Value::CreateStringValue(type))) {
    348     CallNotifyObserversPropertyChanged(
    349         flimflam::kAvailableTechnologiesProperty, 0);
    350   }
    351   if (enabled &&
    352       GetListProperty(flimflam::kEnabledTechnologiesProperty)->
    353       AppendIfNotPresent(base::Value::CreateStringValue(type))) {
    354     CallNotifyObserversPropertyChanged(
    355         flimflam::kEnabledTechnologiesProperty, 0);
    356   }
    357 }
    358 
    359 void ShillManagerClientStub::RemoveTechnology(const std::string& type) {
    360   base::StringValue type_value(type);
    361   if (GetListProperty(flimflam::kAvailableTechnologiesProperty)->Remove(
    362       type_value, NULL)) {
    363     CallNotifyObserversPropertyChanged(
    364         flimflam::kAvailableTechnologiesProperty, 0);
    365   }
    366   if (GetListProperty(flimflam::kEnabledTechnologiesProperty)->Remove(
    367       type_value, NULL)) {
    368     CallNotifyObserversPropertyChanged(
    369         flimflam::kEnabledTechnologiesProperty, 0);
    370   }
    371 }
    372 
    373 void ShillManagerClientStub::SetTechnologyInitializing(const std::string& type,
    374                                                        bool initializing) {
    375   if (initializing) {
    376     if (GetListProperty(shill::kUninitializedTechnologiesProperty)->
    377         AppendIfNotPresent(base::Value::CreateStringValue(type))) {
    378       CallNotifyObserversPropertyChanged(
    379           shill::kUninitializedTechnologiesProperty, 0);
    380     }
    381   } else {
    382     if (GetListProperty(shill::kUninitializedTechnologiesProperty)->Remove(
    383             base::StringValue(type), NULL)) {
    384       CallNotifyObserversPropertyChanged(
    385           shill::kUninitializedTechnologiesProperty, 0);
    386     }
    387   }
    388 }
    389 
    390 void ShillManagerClientStub::ClearProperties() {
    391   stub_properties_.Clear();
    392 }
    393 
    394 void ShillManagerClientStub::AddManagerService(const std::string& service_path,
    395                                                bool add_to_visible_list,
    396                                                bool add_to_watch_list) {
    397   // Always add to ServiceCompleteListProperty.
    398   GetListProperty(shill::kServiceCompleteListProperty)->AppendIfNotPresent(
    399       base::Value::CreateStringValue(service_path));
    400   // If visible, add to Services and notify if new.
    401   if (add_to_visible_list &&
    402       GetListProperty(flimflam::kServicesProperty)->AppendIfNotPresent(
    403       base::Value::CreateStringValue(service_path))) {
    404     CallNotifyObserversPropertyChanged(flimflam::kServicesProperty, 0);
    405   }
    406   if (add_to_watch_list)
    407     AddServiceToWatchList(service_path);
    408 }
    409 
    410 void ShillManagerClientStub::RemoveManagerService(
    411     const std::string& service_path) {
    412   base::StringValue service_path_value(service_path);
    413   if (GetListProperty(flimflam::kServicesProperty)->Remove(
    414       service_path_value, NULL)) {
    415     CallNotifyObserversPropertyChanged(flimflam::kServicesProperty, 0);
    416   }
    417   GetListProperty(shill::kServiceCompleteListProperty)->Remove(
    418       service_path_value, NULL);
    419   if (GetListProperty(flimflam::kServiceWatchListProperty)->Remove(
    420       service_path_value, NULL)) {
    421     CallNotifyObserversPropertyChanged(
    422         flimflam::kServiceWatchListProperty, 0);
    423   }
    424 }
    425 
    426 void ShillManagerClientStub::ClearManagerServices() {
    427   GetListProperty(flimflam::kServicesProperty)->Clear();
    428   GetListProperty(shill::kServiceCompleteListProperty)->Clear();
    429   GetListProperty(flimflam::kServiceWatchListProperty)->Clear();
    430   CallNotifyObserversPropertyChanged(flimflam::kServicesProperty, 0);
    431   CallNotifyObserversPropertyChanged(flimflam::kServiceWatchListProperty, 0);
    432 }
    433 
    434 void ShillManagerClientStub::SortManagerServices() {
    435   static const char* ordered_types[] = {
    436     flimflam::kTypeEthernet,
    437     flimflam::kTypeWifi,
    438     flimflam::kTypeCellular,
    439     flimflam::kTypeWimax,
    440     flimflam::kTypeVPN
    441   };
    442   base::ListValue* service_list = GetListProperty(flimflam::kServicesProperty);
    443   if (!service_list || service_list->empty())
    444     return;
    445   std::vector<std::string> active_services;
    446   std::vector<std::string> inactive_services;
    447   for (size_t i = 0; i < arraysize(ordered_types); ++i) {
    448     AppendServicesForType(service_list, ordered_types[i],
    449                           &active_services, &inactive_services);
    450   }
    451   service_list->Clear();
    452   for (size_t i = 0; i < active_services.size(); ++i)
    453     service_list->AppendString(active_services[i]);
    454   for (size_t i = 0; i < inactive_services.size(); ++i)
    455     service_list->AppendString(inactive_services[i]);
    456 
    457   CallNotifyObserversPropertyChanged(flimflam::kServicesProperty, 0);
    458 }
    459 
    460 void ShillManagerClientStub::AddGeoNetwork(
    461     const std::string& technology,
    462     const base::DictionaryValue& network) {
    463   base::ListValue* list_value = NULL;
    464   if (!stub_geo_networks_.GetListWithoutPathExpansion(
    465       technology, &list_value)) {
    466     list_value = new base::ListValue;
    467     stub_geo_networks_.SetWithoutPathExpansion(technology, list_value);
    468   }
    469   list_value->Append(network.DeepCopy());
    470 }
    471 
    472 void ShillManagerClientStub::AddProfile(const std::string& profile_path) {
    473   const char* key = flimflam::kProfilesProperty;
    474   if (GetListProperty(key)->AppendIfNotPresent(
    475           new base::StringValue(profile_path))) {
    476     CallNotifyObserversPropertyChanged(key, 0);
    477   }
    478 }
    479 
    480 void ShillManagerClientStub::AddServiceToWatchList(
    481     const std::string& service_path) {
    482   // Remove and insert the service, moving it to the front of the watch list.
    483   GetListProperty(flimflam::kServiceWatchListProperty)->Remove(
    484       base::StringValue(service_path), NULL);
    485   GetListProperty(flimflam::kServiceWatchListProperty)->Insert(
    486       0, base::Value::CreateStringValue(service_path));
    487   CallNotifyObserversPropertyChanged(
    488       flimflam::kServiceWatchListProperty, 0);
    489 }
    490 
    491 void ShillManagerClientStub::SetDefaultProperties() {
    492   // Stub Technologies.
    493   if (!CommandLine::ForCurrentProcess()->HasSwitch(
    494           chromeos::switches::kDisableStubEthernet)) {
    495     AddTechnology(flimflam::kTypeEthernet, true);
    496   }
    497   AddTechnology(flimflam::kTypeWifi, true);
    498   AddTechnology(flimflam::kTypeCellular, true);
    499   AddTechnology(flimflam::kTypeWimax, true);
    500 }
    501 
    502 void ShillManagerClientStub::PassStubProperties(
    503     const DictionaryValueCallback& callback) const {
    504   scoped_ptr<base::DictionaryValue> stub_properties(
    505       stub_properties_.DeepCopy());
    506   // Remove disabled services from the list.
    507   stub_properties->SetWithoutPathExpansion(
    508       flimflam::kServicesProperty,
    509       GetEnabledServiceList(flimflam::kServicesProperty));
    510   stub_properties->SetWithoutPathExpansion(
    511       flimflam::kServiceWatchListProperty,
    512       GetEnabledServiceList(flimflam::kServiceWatchListProperty));
    513   callback.Run(DBUS_METHOD_CALL_SUCCESS, *stub_properties);
    514 }
    515 
    516 void ShillManagerClientStub::PassStubGeoNetworks(
    517     const DictionaryValueCallback& callback) const {
    518   callback.Run(DBUS_METHOD_CALL_SUCCESS, stub_geo_networks_);
    519 }
    520 
    521 void ShillManagerClientStub::CallNotifyObserversPropertyChanged(
    522     const std::string& property,
    523     int delay_ms) {
    524   // Avoid unnecessary delayed task if we have no observers (e.g. during
    525   // initial setup).
    526   if (observer_list_.size() == 0)
    527     return;
    528   if (!CommandLine::ForCurrentProcess()->HasSwitch(
    529           chromeos::switches::kEnableStubInteractive)) {
    530     delay_ms = 0;
    531   }
    532   base::MessageLoop::current()->PostDelayedTask(
    533       FROM_HERE,
    534       base::Bind(&ShillManagerClientStub::NotifyObserversPropertyChanged,
    535                  weak_ptr_factory_.GetWeakPtr(),
    536                  property),
    537                  base::TimeDelta::FromMilliseconds(delay_ms));
    538 }
    539 
    540 void ShillManagerClientStub::NotifyObserversPropertyChanged(
    541     const std::string& property) {
    542   if (property == flimflam::kServicesProperty ||
    543       property == flimflam::kServiceWatchListProperty) {
    544     scoped_ptr<base::ListValue> services(GetEnabledServiceList(property));
    545     FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
    546                       observer_list_,
    547                       OnPropertyChanged(property, *(services.get())));
    548     return;
    549   }
    550   base::Value* value = NULL;
    551   if (!stub_properties_.GetWithoutPathExpansion(property, &value)) {
    552     LOG(ERROR) << "Notify for unknown property: " << property;
    553     return;
    554   }
    555   FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
    556                     observer_list_,
    557                     OnPropertyChanged(property, *value));
    558 }
    559 
    560 base::ListValue* ShillManagerClientStub::GetListProperty(
    561     const std::string& property) {
    562   base::ListValue* list_property = NULL;
    563   if (!stub_properties_.GetListWithoutPathExpansion(
    564       property, &list_property)) {
    565     list_property = new base::ListValue;
    566     stub_properties_.SetWithoutPathExpansion(property, list_property);
    567   }
    568   return list_property;
    569 }
    570 
    571 bool ShillManagerClientStub::TechnologyEnabled(const std::string& type) const {
    572   if (type == flimflam::kTypeVPN)
    573     return true;  // VPN is always "enabled" since there is no associated device
    574   bool enabled = false;
    575   const base::ListValue* technologies;
    576   if (stub_properties_.GetListWithoutPathExpansion(
    577           flimflam::kEnabledTechnologiesProperty, &technologies)) {
    578     base::StringValue type_value(type);
    579     if (technologies->Find(type_value) != technologies->end())
    580       enabled = true;
    581   }
    582   return enabled;
    583 }
    584 
    585 void ShillManagerClientStub::SetTechnologyEnabled(
    586     const std::string& type,
    587     const base::Closure& callback,
    588     bool enabled) {
    589   base::ListValue* enabled_list = NULL;
    590   stub_properties_.GetListWithoutPathExpansion(
    591       flimflam::kEnabledTechnologiesProperty, &enabled_list);
    592   DCHECK(enabled_list);
    593   if (enabled)
    594     enabled_list->AppendIfNotPresent(new base::StringValue(type));
    595   else
    596     enabled_list->Remove(base::StringValue(type), NULL);
    597   CallNotifyObserversPropertyChanged(
    598       flimflam::kEnabledTechnologiesProperty, 0 /* already delayed */);
    599   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
    600   // May affect available services
    601   CallNotifyObserversPropertyChanged(flimflam::kServicesProperty, 0);
    602   CallNotifyObserversPropertyChanged(flimflam::kServiceWatchListProperty, 0);
    603 }
    604 
    605 base::ListValue* ShillManagerClientStub::GetEnabledServiceList(
    606     const std::string& property) const {
    607   base::ListValue* new_service_list = new base::ListValue;
    608   const base::ListValue* service_list;
    609   if (stub_properties_.GetListWithoutPathExpansion(property, &service_list)) {
    610     ShillServiceClient::TestInterface* service_client =
    611         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
    612     for (base::ListValue::const_iterator iter = service_list->begin();
    613          iter != service_list->end(); ++iter) {
    614       std::string service_path;
    615       if (!(*iter)->GetAsString(&service_path))
    616         continue;
    617       const base::DictionaryValue* properties =
    618           service_client->GetServiceProperties(service_path);
    619       if (!properties) {
    620         LOG(ERROR) << "Properties not found for service: " << service_path;
    621         continue;
    622       }
    623       std::string name;
    624       properties->GetString(flimflam::kNameProperty, &name);
    625       std::string type;
    626       properties->GetString(flimflam::kTypeProperty, &type);
    627       if (TechnologyEnabled(type))
    628         new_service_list->Append((*iter)->DeepCopy());
    629     }
    630   }
    631   return new_service_list;
    632 }
    633 
    634 void ShillManagerClientStub::ScanCompleted(const std::string& device_path,
    635                                            const base::Closure& callback) {
    636   if (!device_path.empty()) {
    637     DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface()->
    638         SetDeviceProperty(device_path,
    639                           flimflam::kScanningProperty,
    640                           base::FundamentalValue(false));
    641   }
    642   CallNotifyObserversPropertyChanged(flimflam::kServicesProperty, 0);
    643   CallNotifyObserversPropertyChanged(flimflam::kServiceWatchListProperty,
    644                                      0);
    645   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
    646 }
    647 
    648 }  // namespace chromeos
    649