Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: dbus/exported_object.cc

Issue 7491029: Implement Bus and ObjectProxy classes for our D-Bus library. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: another clang challenge Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « dbus/exported_object.h ('k') | dbus/object_proxy.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "dbus/exported_object.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/message_loop.h"
11 #include "base/threading/thread_restrictions.h"
12 #include "base/time.h"
13 #include "dbus/bus.h"
14 #include "dbus/message.h"
15 #include "dbus/scoped_dbus_error.h"
16
17 namespace dbus {
18
19 namespace {
20
21 // Gets the absolute method name by concatenating the interface name and
22 // the method name. Used for building keys for method_table_ in
23 // ExportedObject.
24 std::string GetAbsoluteMethodName(
25 const std::string& interface_name,
26 const std::string& method_name) {
27 return interface_name + "." + method_name;
28 }
29
30 } // namespace
31
32 ExportedObject::ExportedObject(Bus* bus,
33 const std::string& service_name,
34 const std::string& object_path)
35 : bus_(bus),
36 service_name_(service_name),
37 object_path_(object_path),
38 object_is_registered_(false),
39 method_is_called_(false),
40 response_from_method_(NULL),
41 on_method_is_called_(&method_is_called_lock_) {
42 }
43
44 ExportedObject::~ExportedObject() {
45 DCHECK(!object_is_registered_);
46 }
47
48 bool ExportedObject::ExportMethodAndBlock(
49 const std::string& interface_name,
50 const std::string& method_name,
51 MethodCallCallback method_call_callback) {
52 bus_->AssertOnDBusThread();
53
54 if (!bus_->Connect())
55 return false;
56 if (!bus_->SetUpAsyncOperations())
57 return false;
58 if (!bus_->RequestOwnership(service_name_))
59 return false;
60 if (!Register())
61 return false;
62
63 const std::string absolute_method_name =
64 GetAbsoluteMethodName(interface_name, method_name);
65 if (method_table_.find(absolute_method_name) != method_table_.end()) {
66 LOG(ERROR) << absolute_method_name << " is already exported";
67 return false;
68 }
69 method_table_[absolute_method_name] = method_call_callback;
70
71 return true;
72 }
73
74 void ExportedObject::ExportMethod(const std::string& interface_name,
75 const std::string& method_name,
76 MethodCallCallback method_call_callback,
77 OnExportedCallback on_exported_calback) {
78 bus_->AssertOnOriginThread();
79
80 base::Closure task = base::Bind(&ExportedObject::ExportMethodInternal,
81 this,
82 interface_name,
83 method_name,
84 method_call_callback,
85 on_exported_calback);
86 bus_->PostTaskToDBusThread(FROM_HERE, task);
87 }
88
89 void ExportedObject::Unregister() {
90 bus_->AssertOnDBusThread();
91
92 if (!object_is_registered_)
93 return;
94
95 bus_->UnregisterObjectPath(object_path_);
96 object_is_registered_ = false;
97 }
98
99 void ExportedObject::ExportMethodInternal(
100 const std::string& interface_name,
101 const std::string& method_name,
102 MethodCallCallback method_call_callback,
103 OnExportedCallback on_exported_calback) {
104 bus_->AssertOnDBusThread();
105
106 const bool success = ExportMethodAndBlock(interface_name,
107 method_name,
108 method_call_callback);
109 bus_->PostTaskToOriginThread(FROM_HERE,
110 base::Bind(&ExportedObject::OnExported,
111 this,
112 on_exported_calback,
113 interface_name,
114 method_name,
115 success));
116 }
117
118 void ExportedObject::OnExported(OnExportedCallback on_exported_callback,
119 const std::string& interface_name,
120 const std::string& method_name,
121 bool success) {
122 bus_->AssertOnOriginThread();
123
124 on_exported_callback.Run(interface_name, method_name, success);
125 }
126
127 bool ExportedObject::Register() {
128 bus_->AssertOnDBusThread();
129
130 if (object_is_registered_)
131 return true;
132
133 ScopedDBusError error;
134
135 DBusObjectPathVTable vtable = {};
136 vtable.message_function = &ExportedObject::HandleMessageThunk;
137 vtable.unregister_function = &ExportedObject::OnUnregisteredThunk;
138 const bool success = bus_->TryRegisterObjectPath(object_path_,
139 &vtable,
140 this,
141 error.get());
142 if (!success) {
143 LOG(ERROR) << "Failed to regiser the object: " << object_path_ << ": "
144 << (error.is_set() ? error.message() : "");
145 return false;
146 }
147
148 object_is_registered_ = true;
149 return true;
150 }
151
152 DBusHandlerResult ExportedObject::HandleMessage(
153 DBusConnection* connection,
154 DBusMessage* raw_message) {
155 bus_->AssertOnDBusThread();
156 DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_CALL, dbus_message_get_type(raw_message));
157
158 // raw_message will be unrefed on exit of the function. Increment the
159 // reference so we can use it in MethodCall.
160 dbus_message_ref(raw_message);
161 scoped_ptr<MethodCall> method_call(
162 MethodCall::FromRawMessage(raw_message));
163 const std::string interface = method_call->GetInterface();
164 const std::string member = method_call->GetMember();
165
166 if (interface.empty()) {
167 // We don't support method calls without interface.
168 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
169 }
170
171 // Check if we know about the method.
172 const std::string absolute_method_name = GetAbsoluteMethodName(
173 interface, member);
174 MethodTable::const_iterator iter = method_table_.find(absolute_method_name);
175 if (iter == method_table_.end()) {
176 // Don't know about the method.
177 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
178 }
179
180 Response* response = NULL;
181 if (bus_->HasDBusThread()) {
182 response_from_method_ = NULL;
183 method_is_called_ = false;
184 // Post a task to run the method in the origin thread.
185 bus_->PostTaskToOriginThread(FROM_HERE,
186 base::Bind(&ExportedObject::RunMethod,
187 this,
188 iter->second,
189 method_call.get()));
190 // Wait until the method call is done. Blocking is not desirable but we
191 // should return the response to the dbus-daemon in the function, so we
192 // don't have a choice. We wait in the D-Bus thread, so it should be ok.
193 {
194 // We need a timeout here in case the method gets stuck.
195 const int kTimeoutSecs = 10;
196 const base::TimeDelta timeout(
197 base::TimeDelta::FromSeconds(kTimeoutSecs));
198 const base::Time start_time = base::Time::Now();
199
200 base::AutoLock auto_lock(method_is_called_lock_);
201 while (!method_is_called_) {
202 on_method_is_called_.TimedWait(timeout);
203 CHECK(base::Time::Now() - start_time < timeout)
204 << "Method " << absolute_method_name << " timed out";
205 }
206 }
207 response = response_from_method_;
208 } else {
209 // If the D-Bus thread is not used, just call the method directly. We
210 // don't need the complicated logic to wait for the method call to be
211 // complete.
212 response = iter->second.Run(method_call.get());
213 }
214
215 if (!response) {
216 // Something bad happend in the method call.
217 scoped_ptr<dbus::ErrorResponse> error_response(
218 ErrorResponse::FromMethodCall(method_call.get(),
219 DBUS_ERROR_FAILED,
220 "error occurred in " + member));
221 dbus_connection_send(connection, error_response->raw_message(), NULL);
222 return DBUS_HANDLER_RESULT_HANDLED;
223 }
224
225 // The method call was successful.
226 dbus_connection_send(connection, response->raw_message(), NULL);
227 delete response;
228
229 return DBUS_HANDLER_RESULT_HANDLED;
230 }
231
232 void ExportedObject::RunMethod(MethodCallCallback method_call_callback,
233 MethodCall* method_call) {
234 bus_->AssertOnOriginThread();
235
236 base::AutoLock auto_lock(method_is_called_lock_);
237 response_from_method_ = method_call_callback.Run(method_call);
238 method_is_called_ = true;
239 on_method_is_called_.Signal();
240 }
241
242 void ExportedObject::OnUnregistered(DBusConnection* connection) {
243 }
244
245 DBusHandlerResult ExportedObject::HandleMessageThunk(
246 DBusConnection* connection,
247 DBusMessage* raw_message,
248 void* user_data) {
249 ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
250 return self->HandleMessage(connection, raw_message);
251 }
252
253 void ExportedObject::OnUnregisteredThunk(DBusConnection *connection,
254 void* user_data) {
255 ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
256 return self->OnUnregistered(connection);
257 }
258
259 } // namespace dbus
OLDNEW
« no previous file with comments | « dbus/exported_object.h ('k') | dbus/object_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698