diff options
author | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-02 07:53:09 +0000 |
---|---|---|
committer | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-02 07:53:09 +0000 |
commit | 118090c51632bd1f19578a3240e79d1c44f1a52b (patch) | |
tree | 248b36b3e07135fdab94c51609a8c2a2b1de0519 /dbus | |
parent | cc8533326529a64e4aa7db0081025844665cbe40 (diff) | |
download | chromium_src-118090c51632bd1f19578a3240e79d1c44f1a52b.zip chromium_src-118090c51632bd1f19578a3240e79d1c44f1a52b.tar.gz chromium_src-118090c51632bd1f19578a3240e79d1c44f1a52b.tar.bz2 |
dbus: Add ObjectProxy::WaitForServiceToBeAvailable()
Split ConnectToNameOwnerChangedSignal() from ConnectToSignalInternal().
Add WaitForServiceToBeAvailable()
Add test.
BUG=141009
TEST=dbus_unittests
R=satorux@chromium.org
Review URL: https://codereview.chromium.org/25488002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226428 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'dbus')
-rw-r--r-- | dbus/dbus.gyp | 1 | ||||
-rw-r--r-- | dbus/object_proxy.cc | 86 | ||||
-rw-r--r-- | dbus/object_proxy.h | 21 | ||||
-rw-r--r-- | dbus/object_proxy_unittest.cc | 76 |
4 files changed, 170 insertions, 14 deletions
diff --git a/dbus/dbus.gyp b/dbus/dbus.gyp index 847e7d97..7225845 100644 --- a/dbus/dbus.gyp +++ b/dbus/dbus.gyp @@ -103,6 +103,7 @@ 'message_unittest.cc', 'mock_unittest.cc', 'object_manager_unittest.cc', + 'object_proxy_unittest.cc', 'property_unittest.cc', 'signal_sender_verification_unittest.cc', 'string_util_unittest.cc', diff --git a/dbus/object_proxy.cc b/dbus/object_proxy.cc index f2c4ebd..d506392 100644 --- a/dbus/object_proxy.cc +++ b/dbus/object_proxy.cc @@ -192,6 +192,16 @@ void ObjectProxy::SetNameOwnerChangedCallback( name_owner_changed_callback_ = callback; } +void ObjectProxy::WaitForServiceToBeAvailable( + WaitForServiceToBeAvailableCallback callback) { + bus_->AssertOnOriginThread(); + + wait_for_service_to_be_available_callbacks_.push_back(callback); + bus_->GetDBusTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this)); +} + void ObjectProxy::Detach() { bus_->AssertOnDBusThread(); @@ -364,14 +374,9 @@ void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call, delete data; } -bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name, - const std::string& signal_name, - SignalCallback signal_callback) { +bool ObjectProxy::ConnectToNameOwnerChangedSignal() { bus_->AssertOnDBusThread(); - const std::string absolute_signal_name = - GetAbsoluteSignalName(interface_name, signal_name); - if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) return false; @@ -384,11 +389,6 @@ bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name, LOG(ERROR) << "Failed to add filter function"; } } - // Add a match rule so the signal goes through HandleMessage(). - const std::string match_rule = - base::StringPrintf("type='signal', interface='%s', path='%s'", - interface_name.c_str(), - object_path_.value().c_str()); // Add a match_rule listening NameOwnerChanged for the well-known name // |service_name_|. const std::string name_owner_changed_match_rule = @@ -399,9 +399,6 @@ bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name, service_name_.c_str()); const bool success = - AddMatchRuleWithCallback(match_rule, - absolute_signal_name, - signal_callback) && AddMatchRuleWithoutCallback(name_owner_changed_match_rule, "org.freedesktop.DBus.NameOwnerChanged"); @@ -414,6 +411,49 @@ bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name, return success; } +bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name, + const std::string& signal_name, + SignalCallback signal_callback) { + bus_->AssertOnDBusThread(); + + if (!ConnectToNameOwnerChangedSignal()) + return false; + + const std::string absolute_signal_name = + GetAbsoluteSignalName(interface_name, signal_name); + + // Add a match rule so the signal goes through HandleMessage(). + const std::string match_rule = + base::StringPrintf("type='signal', interface='%s', path='%s'", + interface_name.c_str(), + object_path_.value().c_str()); + return AddMatchRuleWithCallback(match_rule, + absolute_signal_name, + signal_callback); +} + +void ObjectProxy::WaitForServiceToBeAvailableInternal() { + bus_->AssertOnDBusThread(); + + if (!ConnectToNameOwnerChangedSignal()) { // Failed to connect to the signal. + const bool service_is_ready = false; + bus_->GetOriginTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks, + this, service_is_ready)); + return; + } + + const bool service_is_available = !service_name_owner_.empty(); + if (service_is_available) { // Service is already available. + bus_->GetOriginTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks, + this, service_is_available)); + return; + } +} + DBusHandlerResult ObjectProxy::HandleMessage( DBusConnection* connection, DBusMessage* raw_message) { @@ -625,6 +665,14 @@ DBusHandlerResult ObjectProxy::HandleNameOwnerChanged( FROM_HERE, base::Bind(&ObjectProxy::RunNameOwnerChangedCallback, this, old_owner, new_owner)); + + const bool service_is_available = !service_name_owner_.empty(); + if (service_is_available) { + bus_->GetOriginTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks, + this, service_is_available)); + } } } @@ -640,4 +688,14 @@ void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner, name_owner_changed_callback_.Run(old_owner, new_owner); } +void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks( + bool service_is_available) { + bus_->AssertOnOriginThread(); + + std::vector<WaitForServiceToBeAvailableCallback> callbacks; + callbacks.swap(wait_for_service_to_be_available_callbacks_); + for (size_t i = 0; i < callbacks.size(); ++i) + callbacks[i].Run(service_is_available); +} + } // namespace dbus diff --git a/dbus/object_proxy.h b/dbus/object_proxy.h index e618d5d..b183be2 100644 --- a/dbus/object_proxy.h +++ b/dbus/object_proxy.h @@ -77,6 +77,10 @@ class CHROME_DBUS_EXPORT ObjectProxy const std::string& old_owner, const std::string& new_owner)> NameOwnerChangedCallback; + // Called when the service becomes available. + typedef base::Callback<void( + bool service_is_available)> WaitForServiceToBeAvailableCallback; + // Called when the object proxy is connected to the signal. // Parameters: // - the interface name. @@ -152,6 +156,10 @@ class CHROME_DBUS_EXPORT ObjectProxy // represented by |service_name_|. virtual void SetNameOwnerChangedCallback(NameOwnerChangedCallback callback); + // Runs the callback as soon as the service becomes available. + virtual void WaitForServiceToBeAvailable( + WaitForServiceToBeAvailableCallback callback); + // Detaches from the remote object. The Bus object will take care of // detaching so you don't have to do this manually. // @@ -208,11 +216,17 @@ class CHROME_DBUS_EXPORT ObjectProxy static void OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call, void* user_data); + // Connects to NameOwnerChanged signal. + bool ConnectToNameOwnerChangedSignal(); + // Helper function for ConnectToSignal(). bool ConnectToSignalInternal(const std::string& interface_name, const std::string& signal_name, SignalCallback signal_callback); + // Helper function for WaitForServiceToBeAvailable(). + void WaitForServiceToBeAvailableInternal(); + // Handles the incoming request messages and dispatches to the signal // callbacks. DBusHandlerResult HandleMessage(DBusConnection* connection, @@ -262,6 +276,9 @@ class CHROME_DBUS_EXPORT ObjectProxy void RunNameOwnerChangedCallback(const std::string& old_owner, const std::string& new_owner); + // Runs |wait_for_service_to_be_available_callbacks_|. + void RunWaitForServiceToBeAvailableCallbacks(bool service_is_available); + scoped_refptr<Bus> bus_; std::string service_name_; ObjectPath object_path_; @@ -277,6 +294,10 @@ class CHROME_DBUS_EXPORT ObjectProxy // The callback called when NameOwnerChanged signal is received. NameOwnerChangedCallback name_owner_changed_callback_; + // Called when the service becomes available. + std::vector<WaitForServiceToBeAvailableCallback> + wait_for_service_to_be_available_callbacks_; + std::set<std::string> match_rules_; const bool ignore_service_unknown_errors_; diff --git a/dbus/object_proxy_unittest.cc b/dbus/object_proxy_unittest.cc new file mode 100644 index 0000000..1cf667c --- /dev/null +++ b/dbus/object_proxy_unittest.cc @@ -0,0 +1,76 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind.h" +#include "base/memory/ref_counted.h" +#include "base/run_loop.h" +#include "dbus/bus.h" +#include "dbus/object_proxy.h" +#include "dbus/test_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace dbus { +namespace { + +class ObjectProxyTest : public testing::Test { + protected: + virtual void SetUp() OVERRIDE { + Bus::Options bus_options; + bus_options.bus_type = Bus::SESSION; + bus_options.connection_type = Bus::PRIVATE; + bus_ = new Bus(bus_options); + + object_proxy_ = bus_->GetObjectProxy( + "org.chromium.TestService", ObjectPath("/org/chromium/TestObject")); + } + + virtual void TearDown() OVERRIDE { + bus_->ShutdownAndBlock(); + } + + base::MessageLoopForIO message_loop_; + scoped_refptr<Bus> bus_; + ObjectProxy* object_proxy_; +}; + +// Used as a WaitForServiceToBeAvailableCallback. +void OnServiceIsAvailable(scoped_ptr<base::RunLoop>* run_loop, + bool service_is_available) { + EXPECT_TRUE(service_is_available); + ASSERT_TRUE(*run_loop); + (*run_loop)->Quit(); +} + +TEST_F(ObjectProxyTest, WaitForServiceToBeAvailable) { + scoped_ptr<base::RunLoop> run_loop; + + // Callback is not yet called because the service is not available. + object_proxy_->WaitForServiceToBeAvailable( + base::Bind(&OnServiceIsAvailable, &run_loop)); + base::RunLoop().RunUntilIdle(); + + // Start the service. + TestService::Options options; + TestService test_service(options); + ASSERT_TRUE(test_service.StartService()); + ASSERT_TRUE(test_service.WaitUntilServiceIsStarted()); + ASSERT_TRUE(test_service.has_ownership()); + + // Callback is called beacuse the service became available. + run_loop.reset(new base::RunLoop); + run_loop->Run(); + + // Callback is called because the service is already available. + run_loop.reset(new base::RunLoop); + object_proxy_->WaitForServiceToBeAvailable( + base::Bind(&OnServiceIsAvailable, &run_loop)); + run_loop->Run(); + + // Shut down the service. + test_service.ShutdownAndBlock(); + test_service.Stop(); +} + +} // namespace +} // namespace dbus |