diff options
author | vlaviano@chromium.org <vlaviano@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-24 02:23:33 +0000 |
---|---|---|
committer | vlaviano@chromium.org <vlaviano@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-24 02:23:33 +0000 |
commit | f34dabdeb6ff9e25515bb68bac78af7f49ce6f3a (patch) | |
tree | fc6a84b0a3e496a0a7f52b2ad1559bd50f54908b /dbus | |
parent | 89539dec77e9c1625d6616c4060b474e0ebd46bd (diff) | |
download | chromium_src-f34dabdeb6ff9e25515bb68bac78af7f49ce6f3a.zip chromium_src-f34dabdeb6ff9e25515bb68bac78af7f49ce6f3a.tar.gz chromium_src-f34dabdeb6ff9e25515bb68bac78af7f49ce6f3a.tar.bz2 |
chrome: dbus: support asynchronous method replies
BUG=chromium-os:23241
TEST=Unit tests and manual testing on device.
Change-Id: I4d665897687030f4ab2379e4f6ddb9b3ebe02af4
Review URL: http://codereview.chromium.org/8637002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111479 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'dbus')
-rw-r--r-- | dbus/bus.h | 8 | ||||
-rw-r--r-- | dbus/end_to_end_async_unittest.cc | 18 | ||||
-rw-r--r-- | dbus/exported_object.cc | 40 | ||||
-rw-r--r-- | dbus/exported_object.h | 19 | ||||
-rw-r--r-- | dbus/test_service.cc | 48 | ||||
-rw-r--r-- | dbus/test_service.h | 16 |
6 files changed, 117 insertions, 32 deletions
@@ -100,11 +100,15 @@ class ObjectProxy; // // Exporting a method: // -// Response* Echo(dbus::MethodCall* method_call) { +// void Echo(dbus::MethodCall* method_call, +// dbus::ExportedObject::ResponseSender response_sender) { // // Do something with method_call. // Response* response = Response::FromMethodCall(method_call); // // Build response here. -// return response; +// // Can send an immediate response here to implement a synchronous service +// // or store the response_sender and send a response later to implement an +// // asynchronous service. +// response_sender.Run(response); // } // // void OnExported(const std::string& interface_name, diff --git a/dbus/end_to_end_async_unittest.cc b/dbus/end_to_end_async_unittest.cc index 2f486f4..5c98fe9 100644 --- a/dbus/end_to_end_async_unittest.cc +++ b/dbus/end_to_end_async_unittest.cc @@ -223,6 +223,24 @@ TEST_F(EndToEndAsyncTest, Timeout) { ASSERT_EQ("", response_strings_[0]); } +// Tests calling a method that sends its reply asynchronously. +TEST_F(EndToEndAsyncTest, AsyncEcho) { + const char* kHello = "hello"; + + // Create the method call. + dbus::MethodCall method_call("org.chromium.TestInterface", "AsyncEcho"); + dbus::MessageWriter writer(&method_call); + writer.AppendString(kHello); + + // Call the method. + const int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT; + CallMethod(&method_call, timeout_ms); + + // Check the response. + WaitForResponses(1); + EXPECT_EQ(kHello, response_strings_[0]); +} + TEST_F(EndToEndAsyncTest, NonexistentMethod) { dbus::MethodCall method_call("org.chromium.TestInterface", "Nonexistent"); diff --git a/dbus/exported_object.cc b/dbus/exported_object.cc index e4a1641..de25168 100644 --- a/dbus/exported_object.cc +++ b/dbus/exported_object.cc @@ -224,12 +224,13 @@ DBusHandlerResult ExportedObject::HandleMessage( method_call.release(), start_time)); } else { - // If the D-Bus thread is not used, just call the method directly. We - // don't need the complicated logic to wait for the method call to be - // complete. - // |response| will be deleted in OnMethodCompleted(). - Response* response = iter->second.Run(method_call.get()); - OnMethodCompleted(method_call.release(), response, start_time); + // If the D-Bus thread is not used, just call the method directly. + MethodCall* released_method_call = method_call.release(); + iter->second.Run(released_method_call, + base::Bind(&ExportedObject::SendResponse, + this, + start_time, + released_method_call)); } // It's valid to say HANDLED here, and send a method response at a later @@ -241,14 +242,27 @@ void ExportedObject::RunMethod(MethodCallCallback method_call_callback, MethodCall* method_call, base::TimeTicks start_time) { bus_->AssertOnOriginThread(); + method_call_callback.Run(method_call, + base::Bind(&ExportedObject::SendResponse, + this, + start_time, + method_call)); +} - Response* response = method_call_callback.Run(method_call); - bus_->PostTaskToDBusThread(FROM_HERE, - base::Bind(&ExportedObject::OnMethodCompleted, - this, - method_call, - response, - start_time)); +void ExportedObject::SendResponse(base::TimeTicks start_time, + MethodCall* method_call, + Response* response) { + DCHECK(method_call); + if (bus_->HasDBusThread()) { + bus_->PostTaskToDBusThread(FROM_HERE, + base::Bind(&ExportedObject::OnMethodCompleted, + this, + method_call, + response, + start_time)); + } else { + OnMethodCompleted(method_call, response, start_time); + } } void ExportedObject::OnMethodCompleted(MethodCall* method_call, diff --git a/dbus/exported_object.h b/dbus/exported_object.h index bc67bcd..7ac2f88 100644 --- a/dbus/exported_object.h +++ b/dbus/exported_object.h @@ -38,9 +38,15 @@ class ExportedObject : public base::RefCountedThreadSafe<ExportedObject> { const std::string& service_name, const std::string& object_path); + // Called to send a response from an exported method. Response* is the + // response message. Callers should pass a NULL Response* in the event + // of an error that prevents the sending of a response. + typedef base::Callback<void (Response*)> ResponseSender; + // Called when an exported method is called. MethodCall* is the request - // message. - typedef base::Callback<Response* (MethodCall*)> MethodCallCallback; + // message. ResponseSender is the callback that should be used to send a + // response. + typedef base::Callback<void (MethodCall*, ResponseSender)> MethodCallCallback; // Called when method exporting is done. // Parameters: @@ -124,7 +130,14 @@ class ExportedObject : public base::RefCountedThreadSafe<ExportedObject> { MethodCall* method_call, base::TimeTicks start_time); - // Called on completion of the method run from RunMethod(). + // Callback invoked by service provider to send a response to a method call. + // Can be called immediately from a MethodCallCallback to implement a + // synchronous service or called later to implement an asynchronous service. + void SendResponse(base::TimeTicks start_time, + MethodCall* method_call, + Response* response); + + // Called on completion of the method run from SendResponse(). // Takes ownership of |method_call| and |response|. void OnMethodCompleted(MethodCall* method_call, Response* response, diff --git a/dbus/test_service.cc b/dbus/test_service.cc index b0207b0..ea8e360 100644 --- a/dbus/test_service.cc +++ b/dbus/test_service.cc @@ -13,8 +13,8 @@ namespace dbus { -// Echo, SlowEcho, BrokenMethod. -const int TestService::kNumMethodsToExport = 3; +// Echo, SlowEcho, AsyncEcho, BrokenMethod. +const int TestService::kNumMethodsToExport = 4; TestService::Options::Options() { } @@ -148,6 +148,15 @@ void TestService::Run(MessageLoop* message_loop) { exported_object_->ExportMethod( "org.chromium.TestInterface", + "AsyncEcho", + base::Bind(&TestService::AsyncEcho, + base::Unretained(this)), + base::Bind(&TestService::OnExported, + base::Unretained(this))); + ++num_methods; + + exported_object_->ExportMethod( + "org.chromium.TestInterface", "BrokenMethod", base::Bind(&TestService::BrokenMethod, base::Unretained(this)), @@ -163,25 +172,44 @@ void TestService::Run(MessageLoop* message_loop) { message_loop->Run(); } -Response* TestService::Echo(MethodCall* method_call) { +void TestService::Echo(MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { MessageReader reader(method_call); std::string text_message; - if (!reader.PopString(&text_message)) - return NULL; + if (!reader.PopString(&text_message)) { + response_sender.Run(NULL); + return; + } Response* response = Response::FromMethodCall(method_call); MessageWriter writer(response); writer.AppendString(text_message); - return response; + response_sender.Run(response); } -Response* TestService::SlowEcho(MethodCall* method_call) { +void TestService::SlowEcho( + MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { base::PlatformThread::Sleep(TestTimeouts::tiny_timeout_ms()); - return Echo(method_call); + Echo(method_call, response_sender); +} + +void TestService::AsyncEcho( + MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + // Schedule a call to Echo() to send an asynchronous response after we return. + message_loop()->PostDelayedTask(FROM_HERE, + base::Bind(&TestService::Echo, + base::Unretained(this), + method_call, + response_sender), + TestTimeouts::tiny_timeout_ms()); } -Response* TestService::BrokenMethod(MethodCall* method_call) { - return NULL; +void TestService::BrokenMethod( + MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + response_sender.Run(NULL); } } // namespace dbus diff --git a/dbus/test_service.h b/dbus/test_service.h index 153613e..ea3e5ad 100644 --- a/dbus/test_service.h +++ b/dbus/test_service.h @@ -10,6 +10,7 @@ #include "base/memory/ref_counted.h" #include "base/threading/thread.h" #include "base/synchronization/waitable_event.h" +#include "dbus/exported_object.h" namespace base { class MessageLoopProxy; @@ -18,7 +19,6 @@ class MessageLoopProxy; namespace dbus { class Bus; -class ExportedObject; class MethodCall; class Response; @@ -89,14 +89,22 @@ class TestService : public base::Thread { // // Echos the text message received from the method call. - Response* Echo(MethodCall* method_call); + void Echo(MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender); // Echos the text message received from the method call, but sleeps for // TestTimeouts::tiny_timeout_ms() before returning the response. - Response* SlowEcho(MethodCall* method_call); + void SlowEcho(MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender); + + // Echos the text message received from the method call, but sends its + // response asynchronously after this callback has returned. + void AsyncEcho(MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender); // Returns NULL, instead of a valid Response. - Response* BrokenMethod(MethodCall* method_call); + void BrokenMethod(MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender); scoped_refptr<base::MessageLoopProxy> dbus_thread_message_loop_proxy_; base::WaitableEvent on_all_methods_exported_; |