summaryrefslogtreecommitdiffstats
path: root/dbus
diff options
context:
space:
mode:
authorhashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-02 07:53:09 +0000
committerhashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-02 07:53:09 +0000
commit118090c51632bd1f19578a3240e79d1c44f1a52b (patch)
tree248b36b3e07135fdab94c51609a8c2a2b1de0519 /dbus
parentcc8533326529a64e4aa7db0081025844665cbe40 (diff)
downloadchromium_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.gyp1
-rw-r--r--dbus/object_proxy.cc86
-rw-r--r--dbus/object_proxy.h21
-rw-r--r--dbus/object_proxy_unittest.cc76
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