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