Home | History | Annotate | Download | only in test-rpc-proxy
      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