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 {
GetPropertyValueFromProxy(Proxy * proxy,const std::string & property_name,brillo::Any * property_value)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 
IsProxyPropertyValueIn(Proxy * proxy,const std::string & property_name,const std::vector<brillo::Any> & expected_values,base::Time wait_start_time,bool * is_success,brillo::Any * final_value,long * elapsed_time_milliseconds)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.
PropertyChangedSignalCallback(const std::string & watched_property_name,const std::vector<brillo::Any> & expected_values,const std::string & changed_property_name,const brillo::Any & new_property_value)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.
PropertyChangedOnConnectedCallback(const std::string &,const std::string &,const std::string &,bool success)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>
HelpRegisterPropertyChangedSignalHandler(Proxy * proxy,dbus::ObjectProxy::OnConnectedCallback on_connected_callback,const DbusPropertyChangeCallback & signal_callback)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>
WaitForCondition(base::Callback<void (base::Time,bool *,OutValueType *,long *)> condition_termination_checker,base::Callback<ConditionChangeCallbackType> condition_change_callback,base::Callback<void (const base::Callback<ConditionChangeCallbackType> &)> condition_change_callback_registrar,long timeout_milliseconds,bool * is_success,OutValueType * out_value,long * elapsed_time_milliseconds)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 
ProxyDbusClient(scoped_refptr<dbus::Bus> bus)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 
SetLogging(Technology tech)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 
GetDeviceProxies()181 std::vector<std::unique_ptr<DeviceProxy>> ProxyDbusClient::GetDeviceProxies() {
182   return GetProxies<DeviceProxy>(shill::kDevicesProperty);
183 }
184 
GetServiceProxies()185 std::vector<std::unique_ptr<ServiceProxy>> ProxyDbusClient::GetServiceProxies() {
186   return GetProxies<ServiceProxy>(shill::kServicesProperty);
187 }
188 
GetProfileProxies()189 std::vector<std::unique_ptr<ProfileProxy>> ProxyDbusClient::GetProfileProxies() {
190   return GetProxies<ProfileProxy>(shill::kProfilesProperty);
191 }
192 
GetMatchingDeviceProxy(const brillo::VariantDictionary & expected_properties)193 std::unique_ptr<DeviceProxy> ProxyDbusClient::GetMatchingDeviceProxy(
194     const brillo::VariantDictionary& expected_properties) {
195   return GetMatchingProxy<DeviceProxy>(shill::kDevicesProperty, expected_properties);
196 }
197 
GetMatchingServiceProxy(const brillo::VariantDictionary & expected_properties)198 std::unique_ptr<ServiceProxy> ProxyDbusClient::GetMatchingServiceProxy(
199     const brillo::VariantDictionary& expected_properties) {
200   return GetMatchingProxy<ServiceProxy>(shill::kServicesProperty, expected_properties);
201 }
202 
GetMatchingProfileProxy(const brillo::VariantDictionary & expected_properties)203 std::unique_ptr<ProfileProxy> ProxyDbusClient::GetMatchingProfileProxy(
204     const brillo::VariantDictionary& expected_properties) {
205   return GetMatchingProxy<ProfileProxy>(shill::kProfilesProperty, expected_properties);
206 }
207 
GetPropertyValueFromDeviceProxy(DeviceProxy * proxy,const std::string & property_name,brillo::Any * property_value)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 
GetPropertyValueFromServiceProxy(ServiceProxy * proxy,const std::string & property_name,brillo::Any * property_value)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 
GetPropertyValueFromProfileProxy(ProfileProxy * proxy,const std::string & property_name,brillo::Any * property_value)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 
WaitForDeviceProxyPropertyValueIn(const dbus::ObjectPath & object_path,const std::string & property_name,const std::vector<brillo::Any> & expected_values,long timeout_milliseconds,brillo::Any * final_value,long * elapsed_time_milliseconds)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 
WaitForServiceProxyPropertyValueIn(const dbus::ObjectPath & object_path,const std::string & property_name,const std::vector<brillo::Any> & expected_values,long timeout_milliseconds,brillo::Any * final_value,long * elapsed_time_milliseconds)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 
WaitForProfileProxyPropertyValueIn(const dbus::ObjectPath & object_path,const std::string & property_name,const std::vector<brillo::Any> & expected_values,long timeout_milliseconds,brillo::Any * final_value,long * elapsed_time_milliseconds)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 
GetServiceProxy(const brillo::VariantDictionary & expected_properties)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 
GetActiveProfileProxy()280 std::unique_ptr<ProfileProxy> ProxyDbusClient::GetActiveProfileProxy() {
281   return GetProxyForObjectPath<ProfileProxy>(GetObjectPathForActiveProfile());
282 }
283 
WaitForMatchingServiceProxy(const brillo::VariantDictionary & service_properties,const std::string & service_type,long timeout_milliseconds,int rescan_interval_milliseconds,long * elapsed_time_milliseconds)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 
ConfigureService(const brillo::VariantDictionary & config_params)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 
ConfigureServiceByGuid(const std::string & guid,const brillo::VariantDictionary & config_params)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 
ConnectService(const dbus::ObjectPath & object_path,long timeout_milliseconds)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 
DisconnectService(const dbus::ObjectPath & object_path,long timeout_milliseconds)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 
CreateProfile(const std::string & profile_name)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 
RemoveProfile(const std::string & profile_name)371 bool ProxyDbusClient::RemoveProfile(const std::string& profile_name) {
372   brillo::ErrorPtr error;
373   return shill_manager_proxy_.RemoveProfile(profile_name, &error);
374 }
375 
PushProfile(const std::string & profile_name)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 
PopProfile(const std::string & profile_name)383 bool ProxyDbusClient::PopProfile(const std::string& profile_name) {
384   brillo::ErrorPtr error;
385   return shill_manager_proxy_.PopProfile(profile_name, &error);
386 }
387 
PopAnyProfile()388 bool ProxyDbusClient::PopAnyProfile() {
389   brillo::ErrorPtr error;
390   return shill_manager_proxy_.PopAnyProfile(&error);
391 }
392 
RequestServiceScan(const std::string & service_type)393 bool ProxyDbusClient::RequestServiceScan(const std::string& service_type) {
394   brillo::ErrorPtr error;
395   return shill_manager_proxy_.RequestScan(service_type, &error);
396 }
397 
GetServiceOrder(std::string * order)398 bool ProxyDbusClient::GetServiceOrder(std::string* order) {
399   brillo::ErrorPtr error;
400   return shill_manager_proxy_.GetServiceOrder(order, &error);
401 }
402 
SetServiceOrder(const std::string & order)403 bool ProxyDbusClient::SetServiceOrder(const std::string& order) {
404   brillo::ErrorPtr error;
405   return shill_manager_proxy_.SetServiceOrder(order, &error);
406 }
407 
SetSchedScan(bool enable)408 bool ProxyDbusClient::SetSchedScan(bool enable) {
409   brillo::ErrorPtr error;
410   return shill_manager_proxy_.SetSchedScan(enable, &error);
411 }
412 
GetPropertyValueFromManager(const std::string & property_name,brillo::Any * property_value)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 
GetObjectPathForActiveProfile()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 
SetLoggingInternal(int level,const std::string & tags)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>
GetProxyForObjectPath(const dbus::ObjectPath & object_path)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>
GetProxies(const std::string & object_paths_property_name)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>
GetMatchingProxy(const std::string & object_paths_property_name,const brillo::VariantDictionary & expected_properties)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>
WaitForProxyPropertyValueIn(const dbus::ObjectPath & object_path,const std::string & property_name,const std::vector<brillo::Any> & expected_values,long timeout_milliseconds,brillo::Any * final_value,long * elapsed_time_milliseconds)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 
IsMatchingServicePresent(const brillo::VariantDictionary & service_properties,base::Time wait_start_time,bool * is_success,std::unique_ptr<ServiceProxy> * service_proxy_out,long * elapsed_time_milliseconds)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 
FindServiceOrRestartScan(const brillo::VariantDictionary & service_properties,const std::string & service_type)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 
InitiateScanForService(base::TimeDelta rescan_interval,const std::string & service_type,const base::Closure & timer_callback)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 
RestartScanForService(const std::string & service_type)563 void ProxyDbusClient::RestartScanForService(
564     const std::string& service_type) {
565   RequestServiceScan(service_type);
566   wait_for_service_timer_->Reset();
567 }
568