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/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/values_util.h"
     21 #include "third_party/cros_system_api/dbus/service_constants.h"
     22 
     23 namespace chromeos {
     24 
     25 namespace {
     26 
     27 // Used to compare values for finding entries to erase in a ListValue.
     28 // (ListValue only implements a const_iterator version of Find).
     29 struct ValueEquals {
     30   explicit ValueEquals(const base::Value* first) : first_(first) {}
     31   bool operator()(const base::Value* second) const {
     32     return first_->Equals(second);
     33   }
     34   const base::Value* first_;
     35 };
     36 
     37 // Appends string entries from |service_list_in| whose entries in ServiceClient
     38 // have Type |match_type| to either an active list or an inactive list
     39 // based on the entry's State.
     40 void AppendServicesForType(
     41     const base::ListValue* service_list_in,
     42     const char* match_type,
     43     std::vector<std::string>* active_service_list_out,
     44     std::vector<std::string>* inactive_service_list_out) {
     45   ShillServiceClient::TestInterface* service_client =
     46       DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
     47   for (base::ListValue::const_iterator iter = service_list_in->begin();
     48        iter != service_list_in->end(); ++iter) {
     49     std::string service_path;
     50     if (!(*iter)->GetAsString(&service_path))
     51       continue;
     52     const base::DictionaryValue* properties =
     53         service_client->GetServiceProperties(service_path);
     54     if (!properties) {
     55       LOG(ERROR) << "Properties not found for service: " << service_path;
     56       continue;
     57     }
     58     std::string type;
     59     properties->GetString(shill::kTypeProperty, &type);
     60     if (type != match_type)
     61       continue;
     62     std::string state;
     63     properties->GetString(shill::kStateProperty, &state);
     64     if (state == shill::kStateOnline ||
     65         state == shill::kStateAssociation ||
     66         state == shill::kStateConfiguration ||
     67         state == shill::kStatePortal ||
     68         state == shill::kStateReady) {
     69       active_service_list_out->push_back(service_path);
     70     } else {
     71       inactive_service_list_out->push_back(service_path);
     72     }
     73   }
     74 }
     75 
     76 }  // namespace
     77 
     78 FakeShillManagerClient::FakeShillManagerClient()
     79     : weak_ptr_factory_(this) {
     80 }
     81 
     82 FakeShillManagerClient::~FakeShillManagerClient() {}
     83 
     84 // ShillManagerClient overrides.
     85 
     86 void FakeShillManagerClient::Init(dbus::Bus* bus) {}
     87 
     88 void FakeShillManagerClient::AddPropertyChangedObserver(
     89     ShillPropertyChangedObserver* observer) {
     90   observer_list_.AddObserver(observer);
     91 }
     92 
     93 void FakeShillManagerClient::RemovePropertyChangedObserver(
     94     ShillPropertyChangedObserver* observer) {
     95   observer_list_.RemoveObserver(observer);
     96 }
     97 
     98 void FakeShillManagerClient::GetProperties(
     99     const DictionaryValueCallback& callback) {
    100   base::MessageLoop::current()->PostTask(
    101       FROM_HERE, base::Bind(
    102           &FakeShillManagerClient::PassStubProperties,
    103           weak_ptr_factory_.GetWeakPtr(),
    104           callback));
    105 }
    106 
    107 void FakeShillManagerClient::GetNetworksForGeolocation(
    108     const DictionaryValueCallback& callback) {
    109   base::MessageLoop::current()->PostTask(
    110       FROM_HERE, base::Bind(
    111           &FakeShillManagerClient::PassStubGeoNetworks,
    112           weak_ptr_factory_.GetWeakPtr(),
    113           callback));
    114 }
    115 
    116 void FakeShillManagerClient::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 FakeShillManagerClient::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 = shill::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                                      shill::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(&FakeShillManagerClient::ScanCompleted,
    149                  weak_ptr_factory_.GetWeakPtr(), device_path, callback),
    150       base::TimeDelta::FromSeconds(scan_duration_seconds));
    151 }
    152 
    153 void FakeShillManagerClient::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       shill::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(&FakeShillManagerClient::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 FakeShillManagerClient::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       shill::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(&FakeShillManagerClient::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 FakeShillManagerClient::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(shill::kGuidProperty, &guid) ||
    214       !properties.GetString(shill::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                                            shill::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(shill::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 FakeShillManagerClient::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(shill::kProfileProperty,
    274                                            &profile_property);
    275   CHECK(profile_property == profile_path.value());
    276   ConfigureService(properties, callback, error_callback);
    277 }
    278 
    279 
    280 void FakeShillManagerClient::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 FakeShillManagerClient::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 FakeShillManagerClient::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 FakeShillManagerClient::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 FakeShillManagerClient::ConnectToBestServices(
    314     const base::Closure& callback,
    315     const ErrorCallback& error_callback) {
    316 }
    317 
    318 ShillManagerClient::TestInterface* FakeShillManagerClient::GetTestInterface() {
    319   return this;
    320 }
    321 
    322 // ShillManagerClient::TestInterface overrides.
    323 
    324 void FakeShillManagerClient::AddDevice(const std::string& device_path) {
    325   if (GetListProperty(shill::kDevicesProperty)->AppendIfNotPresent(
    326       base::Value::CreateStringValue(device_path))) {
    327     CallNotifyObserversPropertyChanged(shill::kDevicesProperty, 0);
    328   }
    329 }
    330 
    331 void FakeShillManagerClient::RemoveDevice(const std::string& device_path) {
    332   base::StringValue device_path_value(device_path);
    333   if (GetListProperty(shill::kDevicesProperty)->Remove(
    334       device_path_value, NULL)) {
    335     CallNotifyObserversPropertyChanged(shill::kDevicesProperty, 0);
    336   }
    337 }
    338 
    339 void FakeShillManagerClient::ClearDevices() {
    340   GetListProperty(shill::kDevicesProperty)->Clear();
    341   CallNotifyObserversPropertyChanged(shill::kDevicesProperty, 0);
    342 }
    343 
    344 void FakeShillManagerClient::AddTechnology(const std::string& type,
    345                                            bool enabled) {
    346   if (GetListProperty(shill::kAvailableTechnologiesProperty)->
    347       AppendIfNotPresent(base::Value::CreateStringValue(type))) {
    348     CallNotifyObserversPropertyChanged(
    349         shill::kAvailableTechnologiesProperty, 0);
    350   }
    351   if (enabled &&
    352       GetListProperty(shill::kEnabledTechnologiesProperty)->
    353       AppendIfNotPresent(base::Value::CreateStringValue(type))) {
    354     CallNotifyObserversPropertyChanged(
    355         shill::kEnabledTechnologiesProperty, 0);
    356   }
    357 }
    358 
    359 void FakeShillManagerClient::RemoveTechnology(const std::string& type) {
    360   base::StringValue type_value(type);
    361   if (GetListProperty(shill::kAvailableTechnologiesProperty)->Remove(
    362       type_value, NULL)) {
    363     CallNotifyObserversPropertyChanged(
    364         shill::kAvailableTechnologiesProperty, 0);
    365   }
    366   if (GetListProperty(shill::kEnabledTechnologiesProperty)->Remove(
    367       type_value, NULL)) {
    368     CallNotifyObserversPropertyChanged(
    369         shill::kEnabledTechnologiesProperty, 0);
    370   }
    371 }
    372 
    373 void FakeShillManagerClient::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 FakeShillManagerClient::ClearProperties() {
    391   stub_properties_.Clear();
    392 }
    393 
    394 void FakeShillManagerClient::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(shill::kServicesProperty)->AppendIfNotPresent(
    403       base::Value::CreateStringValue(service_path))) {
    404     CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
    405   }
    406   if (add_to_watch_list)
    407     AddServiceToWatchList(service_path);
    408 }
    409 
    410 void FakeShillManagerClient::RemoveManagerService(
    411     const std::string& service_path) {
    412   base::StringValue service_path_value(service_path);
    413   if (GetListProperty(shill::kServicesProperty)->Remove(
    414       service_path_value, NULL)) {
    415     CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
    416   }
    417   GetListProperty(shill::kServiceCompleteListProperty)->Remove(
    418       service_path_value, NULL);
    419   if (GetListProperty(shill::kServiceWatchListProperty)->Remove(
    420       service_path_value, NULL)) {
    421     CallNotifyObserversPropertyChanged(
    422         shill::kServiceWatchListProperty, 0);
    423   }
    424 }
    425 
    426 void FakeShillManagerClient::ClearManagerServices() {
    427   GetListProperty(shill::kServicesProperty)->Clear();
    428   GetListProperty(shill::kServiceCompleteListProperty)->Clear();
    429   GetListProperty(shill::kServiceWatchListProperty)->Clear();
    430   CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
    431   CallNotifyObserversPropertyChanged(shill::kServiceWatchListProperty, 0);
    432 }
    433 
    434 void FakeShillManagerClient::SortManagerServices() {
    435   static const char* ordered_types[] = {
    436     shill::kTypeEthernet,
    437     shill::kTypeWifi,
    438     shill::kTypeCellular,
    439     shill::kTypeWimax,
    440     shill::kTypeVPN
    441   };
    442   base::ListValue* service_list = GetListProperty(shill::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(shill::kServicesProperty, 0);
    458 }
    459 
    460 void FakeShillManagerClient::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 FakeShillManagerClient::AddProfile(const std::string& profile_path) {
    473   const char* key = shill::kProfilesProperty;
    474   if (GetListProperty(key)->AppendIfNotPresent(
    475           new base::StringValue(profile_path))) {
    476     CallNotifyObserversPropertyChanged(key, 0);
    477   }
    478 }
    479 
    480 void FakeShillManagerClient::AddServiceToWatchList(
    481     const std::string& service_path) {
    482   // Remove and insert the service, moving it to the front of the watch list.
    483   GetListProperty(shill::kServiceWatchListProperty)->Remove(
    484       base::StringValue(service_path), NULL);
    485   GetListProperty(shill::kServiceWatchListProperty)->Insert(
    486       0, base::Value::CreateStringValue(service_path));
    487   CallNotifyObserversPropertyChanged(
    488       shill::kServiceWatchListProperty, 0);
    489 }
    490 
    491 void FakeShillManagerClient::PassStubProperties(
    492     const DictionaryValueCallback& callback) const {
    493   scoped_ptr<base::DictionaryValue> stub_properties(
    494       stub_properties_.DeepCopy());
    495   // Remove disabled services from the list.
    496   stub_properties->SetWithoutPathExpansion(
    497       shill::kServicesProperty,
    498       GetEnabledServiceList(shill::kServicesProperty));
    499   stub_properties->SetWithoutPathExpansion(
    500       shill::kServiceWatchListProperty,
    501       GetEnabledServiceList(shill::kServiceWatchListProperty));
    502   callback.Run(DBUS_METHOD_CALL_SUCCESS, *stub_properties);
    503 }
    504 
    505 void FakeShillManagerClient::PassStubGeoNetworks(
    506     const DictionaryValueCallback& callback) const {
    507   callback.Run(DBUS_METHOD_CALL_SUCCESS, stub_geo_networks_);
    508 }
    509 
    510 void FakeShillManagerClient::CallNotifyObserversPropertyChanged(
    511     const std::string& property,
    512     int delay_ms) {
    513   // Avoid unnecessary delayed task if we have no observers (e.g. during
    514   // initial setup).
    515   if (!observer_list_.might_have_observers())
    516     return;
    517   if (!CommandLine::ForCurrentProcess()->HasSwitch(
    518           chromeos::switches::kEnableStubInteractive)) {
    519     delay_ms = 0;
    520   }
    521   base::MessageLoop::current()->PostDelayedTask(
    522       FROM_HERE,
    523       base::Bind(&FakeShillManagerClient::NotifyObserversPropertyChanged,
    524                  weak_ptr_factory_.GetWeakPtr(),
    525                  property),
    526                  base::TimeDelta::FromMilliseconds(delay_ms));
    527 }
    528 
    529 void FakeShillManagerClient::NotifyObserversPropertyChanged(
    530     const std::string& property) {
    531   if (property == shill::kServicesProperty ||
    532       property == shill::kServiceWatchListProperty) {
    533     scoped_ptr<base::ListValue> services(GetEnabledServiceList(property));
    534     FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
    535                       observer_list_,
    536                       OnPropertyChanged(property, *(services.get())));
    537     return;
    538   }
    539   base::Value* value = NULL;
    540   if (!stub_properties_.GetWithoutPathExpansion(property, &value)) {
    541     LOG(ERROR) << "Notify for unknown property: " << property;
    542     return;
    543   }
    544   FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
    545                     observer_list_,
    546                     OnPropertyChanged(property, *value));
    547 }
    548 
    549 base::ListValue* FakeShillManagerClient::GetListProperty(
    550     const std::string& property) {
    551   base::ListValue* list_property = NULL;
    552   if (!stub_properties_.GetListWithoutPathExpansion(
    553       property, &list_property)) {
    554     list_property = new base::ListValue;
    555     stub_properties_.SetWithoutPathExpansion(property, list_property);
    556   }
    557   return list_property;
    558 }
    559 
    560 bool FakeShillManagerClient::TechnologyEnabled(const std::string& type) const {
    561   if (type == shill::kTypeVPN)
    562     return true;  // VPN is always "enabled" since there is no associated device
    563   bool enabled = false;
    564   const base::ListValue* technologies;
    565   if (stub_properties_.GetListWithoutPathExpansion(
    566           shill::kEnabledTechnologiesProperty, &technologies)) {
    567     base::StringValue type_value(type);
    568     if (technologies->Find(type_value) != technologies->end())
    569       enabled = true;
    570   }
    571   return enabled;
    572 }
    573 
    574 void FakeShillManagerClient::SetTechnologyEnabled(
    575     const std::string& type,
    576     const base::Closure& callback,
    577     bool enabled) {
    578   base::ListValue* enabled_list = NULL;
    579   stub_properties_.GetListWithoutPathExpansion(
    580       shill::kEnabledTechnologiesProperty, &enabled_list);
    581   DCHECK(enabled_list);
    582   if (enabled)
    583     enabled_list->AppendIfNotPresent(new base::StringValue(type));
    584   else
    585     enabled_list->Remove(base::StringValue(type), NULL);
    586   CallNotifyObserversPropertyChanged(
    587       shill::kEnabledTechnologiesProperty, 0 /* already delayed */);
    588   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
    589   // May affect available services
    590   CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
    591   CallNotifyObserversPropertyChanged(shill::kServiceWatchListProperty, 0);
    592 }
    593 
    594 base::ListValue* FakeShillManagerClient::GetEnabledServiceList(
    595     const std::string& property) const {
    596   base::ListValue* new_service_list = new base::ListValue;
    597   const base::ListValue* service_list;
    598   if (stub_properties_.GetListWithoutPathExpansion(property, &service_list)) {
    599     ShillServiceClient::TestInterface* service_client =
    600         DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
    601     for (base::ListValue::const_iterator iter = service_list->begin();
    602          iter != service_list->end(); ++iter) {
    603       std::string service_path;
    604       if (!(*iter)->GetAsString(&service_path))
    605         continue;
    606       const base::DictionaryValue* properties =
    607           service_client->GetServiceProperties(service_path);
    608       if (!properties) {
    609         LOG(ERROR) << "Properties not found for service: " << service_path;
    610         continue;
    611       }
    612       std::string name;
    613       properties->GetString(shill::kNameProperty, &name);
    614       std::string type;
    615       properties->GetString(shill::kTypeProperty, &type);
    616       if (TechnologyEnabled(type))
    617         new_service_list->Append((*iter)->DeepCopy());
    618     }
    619   }
    620   return new_service_list;
    621 }
    622 
    623 void FakeShillManagerClient::ScanCompleted(const std::string& device_path,
    624                                            const base::Closure& callback) {
    625   if (!device_path.empty()) {
    626     DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface()->
    627         SetDeviceProperty(device_path,
    628                           shill::kScanningProperty,
    629                           base::FundamentalValue(false));
    630   }
    631   CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
    632   CallNotifyObserversPropertyChanged(shill::kServiceWatchListProperty, 0);
    633   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
    634 }
    635 
    636 }  // namespace chromeos
    637