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