1 // 2 // Copyright (C) 2015 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 #include <time.h> 17 18 #include <base/message_loop/message_loop.h> 19 20 #include "proxy_dbus_client.h" 21 22 const char ProxyDbusClient::kCommonLogScopes[] = 23 "connection+dbus+device+link+manager+portal+service"; 24 const int ProxyDbusClient::kLogLevel = -4; 25 const char ProxyDbusClient::kDbusErrorObjectUnknown[] = 26 "org.freedesktop.DBus.Error.UnknownObject"; 27 28 namespace { 29 template<typename Proxy> bool GetPropertyValueFromProxy( 30 Proxy* proxy, 31 const std::string& property_name, 32 brillo::Any* property_value) { 33 CHECK(property_value); 34 brillo::VariantDictionary proxy_properties; 35 brillo::ErrorPtr error; 36 CHECK(proxy->GetProperties(&proxy_properties, &error)); 37 if (proxy_properties.find(property_name) == proxy_properties.end()) { 38 return false; 39 } 40 *property_value = proxy_properties[property_name]; 41 return true; 42 } 43 44 template<typename Proxy> void IsProxyPropertyValueIn( 45 Proxy* proxy, 46 const std::string& property_name, 47 const std::vector<brillo::Any>& expected_values, 48 base::Time wait_start_time, 49 bool* is_success, 50 brillo::Any* final_value, 51 long* elapsed_time_milliseconds) { 52 brillo::Any property_value; 53 *is_success = false; 54 if ((GetPropertyValueFromProxy<Proxy>(proxy, property_name, &property_value)) && 55 (std::find(expected_values.begin(), expected_values.end(), 56 property_value) != expected_values.end())) { 57 *is_success = true; 58 } 59 if (final_value) { 60 *final_value = property_value; 61 } 62 if (elapsed_time_milliseconds) { 63 *elapsed_time_milliseconds = 64 (base::Time::Now() - wait_start_time).InMilliseconds(); 65 } 66 } 67 68 // This is invoked when the dbus detects a change in one of 69 // the properties of the proxy. We need to check if the property 70 // we're interested in has reached one of the expected values. 71 void PropertyChangedSignalCallback( 72 const std::string& watched_property_name, 73 const std::vector<brillo::Any>& expected_values, 74 const std::string& changed_property_name, 75 const brillo::Any& new_property_value) { 76 if ((watched_property_name == changed_property_name) && 77 (std::find(expected_values.begin(), expected_values.end(), 78 new_property_value) != expected_values.end())) { 79 // Unblock the waiting function by stopping the message loop. 80 base::MessageLoop::current()->QuitNow(); 81 } 82 } 83 84 // This is invoked to indicate whether dbus successfully connected our 85 // signal callback or not. 86 void PropertyChangedOnConnectedCallback( 87 const std::string& /* watched_property_name */, 88 const std::string& /* interface */, 89 const std::string& /* signal_name */, 90 bool success) { 91 CHECK(success); 92 } 93 94 template<typename Proxy> 95 void HelpRegisterPropertyChangedSignalHandler( 96 Proxy* proxy, 97 dbus::ObjectProxy::OnConnectedCallback on_connected_callback, 98 const DbusPropertyChangeCallback& signal_callback) { 99 // Re-order |on_connected_callback| and |signal_callback|, to meet 100 // the requirements of RegisterPropertyChangedSignalHandler(). 101 proxy->RegisterPropertyChangedSignalHandler( 102 signal_callback, on_connected_callback); 103 } 104 105 template<typename OutValueType, typename ConditionChangeCallbackType> 106 void WaitForCondition( 107 base::Callback<void(base::Time, bool*, OutValueType*, long*)> 108 condition_termination_checker, 109 base::Callback<ConditionChangeCallbackType> condition_change_callback, 110 base::Callback<void(const base::Callback<ConditionChangeCallbackType>&)> 111 condition_change_callback_registrar, 112 long timeout_milliseconds, 113 bool* is_success, 114 OutValueType* out_value, 115 long* elapsed_time_milliseconds) { 116 CHECK(is_success); 117 const base::Time wait_start_time(base::Time::Now()); 118 const base::TimeDelta timeout( 119 base::TimeDelta::FromMilliseconds(timeout_milliseconds)); 120 base::CancelableClosure wait_timeout_callback; 121 base::CancelableCallback<ConditionChangeCallbackType> change_callback; 122 123 condition_termination_checker.Run( 124 wait_start_time, is_success, out_value, elapsed_time_milliseconds); 125 if (*is_success) { 126 return; 127 } 128 129 wait_timeout_callback.Reset(base::MessageLoop::QuitWhenIdleClosure()); 130 change_callback.Reset(condition_change_callback); 131 132 condition_change_callback_registrar.Run(change_callback.callback()); 133 134 // Add timeout, in case we never hit the expected condition. 135 base::MessageLoop::current()->PostDelayedTask( 136 FROM_HERE, 137 wait_timeout_callback.callback(), 138 timeout); 139 140 // Wait for the condition to occur within |timeout_milliseconds|. 141 base::MessageLoop::current()->Run(); 142 143 wait_timeout_callback.Cancel(); 144 change_callback.Cancel(); 145 146 // We could have reached here either because we timed out or 147 // because we reached the condition. 148 condition_termination_checker.Run( 149 wait_start_time, is_success, out_value, elapsed_time_milliseconds); 150 } 151 } // namespace 152 153 ProxyDbusClient::ProxyDbusClient(scoped_refptr<dbus::Bus> bus) 154 : dbus_bus_(bus), 155 shill_manager_proxy_(dbus_bus_), 156 weak_ptr_factory_(this) { 157 } 158 159 void ProxyDbusClient::SetLogging(Technology tech) { 160 std::string log_scopes(kCommonLogScopes); 161 switch (tech) { 162 case TECHNOLOGY_CELLULAR: 163 log_scopes += "+cellular"; 164 break; 165 case TECHNOLOGY_ETHERNET: 166 log_scopes += "+ethernet"; 167 break; 168 case TECHNOLOGY_VPN: 169 log_scopes += "+vpn"; 170 break; 171 case TECHNOLOGY_WIFI: 172 log_scopes += "+wifi"; 173 break; 174 case TECHNOLOGY_WIMAX: 175 log_scopes += "+wimax"; 176 break; 177 } 178 SetLoggingInternal(kLogLevel, log_scopes); 179 } 180 181 std::vector<std::unique_ptr<DeviceProxy>> ProxyDbusClient::GetDeviceProxies() { 182 return GetProxies<DeviceProxy>(shill::kDevicesProperty); 183 } 184 185 std::vector<std::unique_ptr<ServiceProxy>> ProxyDbusClient::GetServiceProxies() { 186 return GetProxies<ServiceProxy>(shill::kServicesProperty); 187 } 188 189 std::vector<std::unique_ptr<ProfileProxy>> ProxyDbusClient::GetProfileProxies() { 190 return GetProxies<ProfileProxy>(shill::kProfilesProperty); 191 } 192 193 std::unique_ptr<DeviceProxy> ProxyDbusClient::GetMatchingDeviceProxy( 194 const brillo::VariantDictionary& expected_properties) { 195 return GetMatchingProxy<DeviceProxy>(shill::kDevicesProperty, expected_properties); 196 } 197 198 std::unique_ptr<ServiceProxy> ProxyDbusClient::GetMatchingServiceProxy( 199 const brillo::VariantDictionary& expected_properties) { 200 return GetMatchingProxy<ServiceProxy>(shill::kServicesProperty, expected_properties); 201 } 202 203 std::unique_ptr<ProfileProxy> ProxyDbusClient::GetMatchingProfileProxy( 204 const brillo::VariantDictionary& expected_properties) { 205 return GetMatchingProxy<ProfileProxy>(shill::kProfilesProperty, expected_properties); 206 } 207 208 bool ProxyDbusClient::GetPropertyValueFromDeviceProxy( 209 DeviceProxy* proxy, 210 const std::string& property_name, 211 brillo::Any* property_value) { 212 return GetPropertyValueFromProxy<DeviceProxy>( 213 proxy, property_name, property_value); 214 } 215 216 bool ProxyDbusClient::GetPropertyValueFromServiceProxy( 217 ServiceProxy* proxy, 218 const std::string& property_name, 219 brillo::Any* property_value) { 220 return GetPropertyValueFromProxy<ServiceProxy>( 221 proxy, property_name, property_value); 222 } 223 224 bool ProxyDbusClient::GetPropertyValueFromProfileProxy( 225 ProfileProxy* proxy, 226 const std::string& property_name, 227 brillo::Any* property_value) { 228 return GetPropertyValueFromProxy<ProfileProxy>( 229 proxy, property_name, property_value); 230 } 231 232 bool ProxyDbusClient::WaitForDeviceProxyPropertyValueIn( 233 const dbus::ObjectPath& object_path, 234 const std::string& property_name, 235 const std::vector<brillo::Any>& expected_values, 236 long timeout_milliseconds, 237 brillo::Any* final_value, 238 long* elapsed_time_milliseconds) { 239 return WaitForProxyPropertyValueIn<DeviceProxy>( 240 object_path, property_name, expected_values, timeout_milliseconds, 241 final_value, elapsed_time_milliseconds); 242 } 243 244 bool ProxyDbusClient::WaitForServiceProxyPropertyValueIn( 245 const dbus::ObjectPath& object_path, 246 const std::string& property_name, 247 const std::vector<brillo::Any>& expected_values, 248 long timeout_milliseconds, 249 brillo::Any* final_value, 250 long* elapsed_time_milliseconds) { 251 return WaitForProxyPropertyValueIn<ServiceProxy>( 252 object_path, property_name, expected_values, timeout_milliseconds, 253 final_value, elapsed_time_milliseconds); 254 } 255 256 bool ProxyDbusClient::WaitForProfileProxyPropertyValueIn( 257 const dbus::ObjectPath& object_path, 258 const std::string& property_name, 259 const std::vector<brillo::Any>& expected_values, 260 long timeout_milliseconds, 261 brillo::Any* final_value, 262 long* elapsed_time_milliseconds) { 263 return WaitForProxyPropertyValueIn<ProfileProxy>( 264 object_path, property_name, expected_values, timeout_milliseconds, 265 final_value, elapsed_time_milliseconds); 266 } 267 268 std::unique_ptr<ServiceProxy> ProxyDbusClient::GetServiceProxy( 269 const brillo::VariantDictionary& expected_properties) { 270 dbus::ObjectPath service_path; 271 brillo::ErrorPtr error; 272 if (!shill_manager_proxy_.GetService( 273 expected_properties, &service_path, &error)) { 274 return nullptr; 275 } 276 return std::unique_ptr<ServiceProxy>( 277 new ServiceProxy(dbus_bus_, service_path)); 278 } 279 280 std::unique_ptr<ProfileProxy> ProxyDbusClient::GetActiveProfileProxy() { 281 return GetProxyForObjectPath<ProfileProxy>(GetObjectPathForActiveProfile()); 282 } 283 284 std::unique_ptr<ServiceProxy> ProxyDbusClient::WaitForMatchingServiceProxy( 285 const brillo::VariantDictionary& service_properties, 286 const std::string& service_type, 287 long timeout_milliseconds, 288 int rescan_interval_milliseconds, 289 long* elapsed_time_milliseconds) { 290 auto condition_termination_checker = 291 base::Bind(&ProxyDbusClient::IsMatchingServicePresent, 292 weak_ptr_factory_.GetWeakPtr(), 293 service_properties); 294 auto condition_change_callback = 295 base::Bind(&ProxyDbusClient::FindServiceOrRestartScan, 296 weak_ptr_factory_.GetWeakPtr(), 297 service_properties, 298 service_type); 299 auto condition_change_callback_registrar = 300 base::Bind(&ProxyDbusClient::InitiateScanForService, 301 weak_ptr_factory_.GetWeakPtr(), 302 base::TimeDelta::FromMilliseconds(rescan_interval_milliseconds), 303 service_type); 304 305 std::unique_ptr<ServiceProxy> service_proxy; 306 bool is_success; 307 WaitForCondition( 308 condition_termination_checker, condition_change_callback, 309 condition_change_callback_registrar, 310 timeout_milliseconds, &is_success, &service_proxy, elapsed_time_milliseconds); 311 return service_proxy; 312 } 313 314 bool ProxyDbusClient::ConfigureService( 315 const brillo::VariantDictionary& config_params) { 316 dbus::ObjectPath service_path; 317 brillo::ErrorPtr error; 318 return shill_manager_proxy_.ConfigureService( 319 config_params, &service_path, &error); 320 } 321 322 bool ProxyDbusClient::ConfigureServiceByGuid( 323 const std::string& guid, 324 const brillo::VariantDictionary& config_params) { 325 dbus::ObjectPath service_path; 326 brillo::ErrorPtr error; 327 brillo::VariantDictionary guid_config_params(config_params); 328 guid_config_params[shill::kGuidProperty] = guid; 329 return shill_manager_proxy_.ConfigureService( 330 guid_config_params, &service_path, &error); 331 } 332 333 bool ProxyDbusClient::ConnectService( 334 const dbus::ObjectPath& object_path, 335 long timeout_milliseconds) { 336 auto proxy = GetProxyForObjectPath<ServiceProxy>(object_path); 337 brillo::ErrorPtr error; 338 if (!proxy->Connect(&error)) { 339 return false; 340 } 341 const std::vector<brillo::Any> expected_values = { 342 brillo::Any(std::string(shill::kStatePortal)), 343 brillo::Any(std::string(shill::kStateOnline)) }; 344 return WaitForProxyPropertyValueIn<ServiceProxy>( 345 object_path, shill::kStateProperty, expected_values, 346 timeout_milliseconds, nullptr, nullptr); 347 } 348 349 bool ProxyDbusClient::DisconnectService( 350 const dbus::ObjectPath& object_path, 351 long timeout_milliseconds) { 352 auto proxy = GetProxyForObjectPath<ServiceProxy>(object_path); 353 brillo::ErrorPtr error; 354 if (!proxy->Disconnect(&error)) { 355 return false; 356 } 357 const std::vector<brillo::Any> expected_values = { 358 brillo::Any(std::string(shill::kStateIdle)) }; 359 return WaitForProxyPropertyValueIn<ServiceProxy>( 360 object_path, shill::kStateProperty, expected_values, 361 timeout_milliseconds, nullptr, nullptr); 362 } 363 364 bool ProxyDbusClient::CreateProfile(const std::string& profile_name) { 365 dbus::ObjectPath profile_path; 366 brillo::ErrorPtr error; 367 return shill_manager_proxy_.CreateProfile( 368 profile_name, &profile_path, &error); 369 } 370 371 bool ProxyDbusClient::RemoveProfile(const std::string& profile_name) { 372 brillo::ErrorPtr error; 373 return shill_manager_proxy_.RemoveProfile(profile_name, &error); 374 } 375 376 bool ProxyDbusClient::PushProfile(const std::string& profile_name) { 377 dbus::ObjectPath profile_path; 378 brillo::ErrorPtr error; 379 return shill_manager_proxy_.PushProfile( 380 profile_name, &profile_path, &error); 381 } 382 383 bool ProxyDbusClient::PopProfile(const std::string& profile_name) { 384 brillo::ErrorPtr error; 385 return shill_manager_proxy_.PopProfile(profile_name, &error); 386 } 387 388 bool ProxyDbusClient::PopAnyProfile() { 389 brillo::ErrorPtr error; 390 return shill_manager_proxy_.PopAnyProfile(&error); 391 } 392 393 bool ProxyDbusClient::RequestServiceScan(const std::string& service_type) { 394 brillo::ErrorPtr error; 395 return shill_manager_proxy_.RequestScan(service_type, &error); 396 } 397 398 bool ProxyDbusClient::GetServiceOrder(std::string* order) { 399 brillo::ErrorPtr error; 400 return shill_manager_proxy_.GetServiceOrder(order, &error); 401 } 402 403 bool ProxyDbusClient::SetServiceOrder(const std::string& order) { 404 brillo::ErrorPtr error; 405 return shill_manager_proxy_.SetServiceOrder(order, &error); 406 } 407 408 bool ProxyDbusClient::SetSchedScan(bool enable) { 409 brillo::ErrorPtr error; 410 return shill_manager_proxy_.SetSchedScan(enable, &error); 411 } 412 413 bool ProxyDbusClient::GetPropertyValueFromManager( 414 const std::string& property_name, 415 brillo::Any* property_value) { 416 return GetPropertyValueFromProxy( 417 &shill_manager_proxy_, property_name, property_value); 418 } 419 420 dbus::ObjectPath ProxyDbusClient::GetObjectPathForActiveProfile() { 421 brillo::Any property_value; 422 if (!GetPropertyValueFromManager( 423 shill::kActiveProfileProperty, &property_value)) { 424 return dbus::ObjectPath(); 425 } 426 return dbus::ObjectPath(property_value.Get<std::string>()); 427 } 428 429 bool ProxyDbusClient::SetLoggingInternal(int level, const std::string& tags) { 430 bool is_success = true; 431 brillo::ErrorPtr error; 432 is_success &= shill_manager_proxy_.SetDebugLevel(level, &error); 433 is_success &= shill_manager_proxy_.SetDebugTags(tags, &error); 434 return is_success; 435 } 436 437 template<typename Proxy> 438 std::unique_ptr<Proxy> ProxyDbusClient::GetProxyForObjectPath( 439 const dbus::ObjectPath& object_path) { 440 return std::unique_ptr<Proxy>(new Proxy(dbus_bus_, object_path)); 441 } 442 443 // Templated functions to return the object path property_name based on 444 template<typename Proxy> 445 std::vector<std::unique_ptr<Proxy>> ProxyDbusClient::GetProxies( 446 const std::string& object_paths_property_name) { 447 brillo::Any object_paths; 448 if (!GetPropertyValueFromManager(object_paths_property_name, &object_paths)) { 449 return std::vector<std::unique_ptr<Proxy>>(); 450 } 451 std::vector<std::unique_ptr<Proxy>> proxies; 452 for (const auto& object_path : 453 object_paths.Get<std::vector<dbus::ObjectPath>>()) { 454 proxies.emplace_back(GetProxyForObjectPath<Proxy>(object_path)); 455 } 456 return proxies; 457 } 458 459 template<typename Proxy> 460 std::unique_ptr<Proxy> ProxyDbusClient::GetMatchingProxy( 461 const std::string& object_paths_property_name, 462 const brillo::VariantDictionary& expected_properties) { 463 for (auto& proxy : GetProxies<Proxy>(object_paths_property_name)) { 464 brillo::VariantDictionary proxy_properties; 465 brillo::ErrorPtr error; 466 if (!proxy->GetProperties(&proxy_properties, &error)) { 467 // Ignore unknown object path errors since we might be using some proxies 468 // for objects which may have been destroyed since. 469 CHECK(error->GetCode() == kDbusErrorObjectUnknown); 470 continue; 471 } 472 bool all_expected_properties_matched = true; 473 for (const auto& expected_property : expected_properties) { 474 if (proxy_properties[expected_property.first] != expected_property.second) { 475 all_expected_properties_matched = false; 476 break; 477 } 478 } 479 if (all_expected_properties_matched) { 480 return std::move(proxy); 481 } 482 } 483 return nullptr; 484 } 485 486 template<typename Proxy> 487 bool ProxyDbusClient::WaitForProxyPropertyValueIn( 488 const dbus::ObjectPath& object_path, 489 const std::string& property_name, 490 const std::vector<brillo::Any>& expected_values, 491 long timeout_milliseconds, 492 brillo::Any* final_value, 493 long* elapsed_time_milliseconds) { 494 // Creates a local proxy using |object_path| instead of accepting the proxy 495 // from the caller since we cannot deregister the signal property change 496 // callback associated. 497 auto proxy = GetProxyForObjectPath<Proxy>(object_path); 498 auto condition_termination_checker = 499 base::Bind(&IsProxyPropertyValueIn<Proxy>, 500 proxy.get(), 501 property_name, 502 expected_values); 503 auto condition_change_callback = 504 base::Bind(&PropertyChangedSignalCallback, 505 property_name, 506 expected_values); 507 auto condition_change_callback_registrar = 508 base::Bind(&HelpRegisterPropertyChangedSignalHandler<Proxy>, 509 base::Unretained(proxy.get()), 510 base::Bind(&PropertyChangedOnConnectedCallback, 511 property_name)); 512 bool is_success; 513 WaitForCondition( 514 condition_termination_checker, condition_change_callback, 515 condition_change_callback_registrar, 516 timeout_milliseconds, &is_success, final_value, elapsed_time_milliseconds); 517 return is_success; 518 } 519 520 void ProxyDbusClient::IsMatchingServicePresent( 521 const brillo::VariantDictionary& service_properties, 522 base::Time wait_start_time, 523 bool* is_success, 524 std::unique_ptr<ServiceProxy>* service_proxy_out, 525 long* elapsed_time_milliseconds) { 526 auto service_proxy = GetMatchingServiceProxy(service_properties); 527 *is_success = false; 528 if (service_proxy) { 529 *is_success = true; 530 } 531 if (service_proxy_out) { 532 *service_proxy_out = std::move(service_proxy); 533 } 534 if (elapsed_time_milliseconds) { 535 *elapsed_time_milliseconds = 536 (base::Time::Now() - wait_start_time).InMilliseconds(); 537 } 538 } 539 540 void ProxyDbusClient::FindServiceOrRestartScan( 541 const brillo::VariantDictionary& service_properties, 542 const std::string& service_type) { 543 if (GetMatchingServiceProxy(service_properties)) { 544 base::MessageLoop::current()->QuitNow(); 545 } else { 546 RestartScanForService(service_type); 547 } 548 } 549 550 void ProxyDbusClient::InitiateScanForService( 551 base::TimeDelta rescan_interval, 552 const std::string& service_type, 553 const base::Closure& timer_callback) { 554 // Create a new timer instance for repeatedly calling the provided 555 // |timer_callback|. |WaitForCondition| will cancel |timer_callback|'s 556 // enclosing CancelableCallback when it exits and hence we need to 557 // use the same reference when we repeatedly schedule |timer_callback|. 558 wait_for_service_timer_.reset( 559 new base::Timer(FROM_HERE, rescan_interval, timer_callback, false)); 560 RestartScanForService(service_type); 561 } 562 563 void ProxyDbusClient::RestartScanForService( 564 const std::string& service_type) { 565 RequestServiceScan(service_type); 566 wait_for_service_timer_->Reset(); 567 } 568