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

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: Fix wrong comments 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
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 "dbus/bus.h"
13 #include "dbus/error.h"
14 #include "dbus/message.h"
15
16 namespace dbus {
17
18 namespace {
19
20 // Gets the absolute method name by concatenating the interface name and
21 // the method name. Used for building keys for method_table_ in
22 // ExportedObject.
23 std::string GetAbsoluteMethodName(
24 const std::string& interface_name,
25 const std::string& method_name) {
26 return interface_name + "." + method_name;
27 }
28
29 } // namespace
30
31 ExportedObject::ExportedObject(Bus* bus,
32 const std::string& service_name,
33 const std::string& object_path)
34 : bus_(bus),
35 service_name_(service_name),
36 object_path_(object_path),
37 object_is_registered_(false),
38 method_is_called_(false),
39 response_from_method_(NULL),
40 on_method_is_called_(&method_is_called_lock_) {
41 }
42
43 ExportedObject::~ExportedObject() {
44 DCHECK(!object_is_registered_);
45 }
46
47 bool ExportedObject::ExportMethodAndBlock(
48 const std::string& interface_name,
49 const std::string& method_name,
50 MethodCallCallback method_call_callback) {
51 bus_->AssertOnDBusThread();
52
53 if (!bus_->Connect())
54 return false;
55 if (!bus_->SetUpAsyncOperations())
56 return false;
57 if (!bus_->RequestOwnership(service_name_))
58 return false;
59 if (!Register())
60 return false;
61
62 const std::string absolute_method_name =
63 GetAbsoluteMethodName(interface_name, method_name);
64 if (method_table_.find(absolute_method_name) != method_table_.end()) {
65 LOG(ERROR) << absolute_method_name << " is already exported";
stevenjb 2011/08/15 21:42:04 Should we do this check earlier, i.e. before Regis
satorux1 2011/08/16 22:25:37 I think it's slightly easier to read to keep this
stevenjb 2011/08/16 22:53:29 OK, it looks like Register() just returns true if
66 return false;
67 }
68 method_table_[absolute_method_name] = method_call_callback;
69
70 return true;
71 }
72
73 void ExportedObject::ExportMethod(const std::string& interface_name,
74 const std::string& method_name,
75 MethodCallCallback method_call_callback,
76 OnExportedCallback on_exported_calback) {
77 bus_->AssertOnOriginThread();
78
79 base::Closure task = base::Bind(&ExportedObject::ExportMethodInternal,
80 this,
81 interface_name,
82 method_name,
83 method_call_callback,
84 on_exported_calback);
85 bus_->PostTaskToDBusThread(FROM_HERE, task);
86 }
87
88 void ExportedObject::Unregister() {
89 bus_->AssertOnDBusThread();
90
91 if (!object_is_registered_)
92 return;
93
94 bus_->UnregisterObjectPath(object_path_);
95 object_is_registered_ = false;
96 }
97
98 void ExportedObject::ExportMethodInternal(
99 const std::string& interface_name,
100 const std::string& method_name,
101 MethodCallCallback method_call_callback,
102 OnExportedCallback on_exported_calback) {
103 bus_->AssertOnDBusThread();
104
105 const bool success = ExportMethodAndBlock(interface_name,
106 method_name,
107 method_call_callback);
108 bus_->PostTaskToOriginThread(FROM_HERE,
109 base::Bind(&ExportedObject::OnExported,
110 this,
111 on_exported_calback,
112 interface_name,
113 method_name,
114 success));
115 }
116
117 void ExportedObject::OnExported(OnExportedCallback on_exported_callback,
118 const std::string& interface_name,
119 const std::string& method_name,
120 bool success) {
121 bus_->AssertOnOriginThread();
122
123 on_exported_callback.Run(interface_name, method_name, success);
124 }
125
126 bool ExportedObject::Register() {
127 bus_->AssertOnDBusThread();
128
129 if (object_is_registered_)
130 return true;
131
132 ScopedDBusError error;
133
134 DBusObjectPathVTable vtable = {};
135 vtable.message_function = &ExportedObject::HandleMessageThunk;
136 vtable.unregister_function = &ExportedObject::OnUnregisteredThunk;
137 const bool success = bus_->TryRegisterObjectPath(object_path_,
138 &vtable,
139 this,
140 error.get());
141 if (!success) {
142 LOG(ERROR) << "Failed to regiser the object: " << object_path_ << ": "
143 << (error.is_set() ? error.message() : "");
144 return false;
145 }
146
147 object_is_registered_ = true;
148 return true;
149 }
150
151 DBusHandlerResult ExportedObject::HandleMessage(
152 DBusConnection* connection,
153 DBusMessage* raw_message) {
154 bus_->AssertOnDBusThread();
155 DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_CALL, dbus_message_get_type(raw_message));
156
157 // raw_message will be unrefed on exit of the function. Increment the
158 // reference so we can use it in MethodCall.
159 dbus_message_ref(raw_message);
160 scoped_ptr<MethodCall> method_call(
161 MethodCall::FromRawMessage(raw_message));
162 const std::string interface = method_call->GetInterface();
163 const std::string member = method_call->GetMember();
164
165 if (interface.empty()) {
166 // We don't support method calls without interface.
167 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
168 }
169
170 // Check if we know about the method.
171 const std::string absolute_method_name = GetAbsoluteMethodName(
172 interface, member);
173 MethodTable::const_iterator iter = method_table_.find(absolute_method_name);
174 if (iter == method_table_.end()) {
175 // Don't know about the method.
176 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
177 }
178
179 Response* response = NULL;
180 if (bus_->has_dbus_thread()) {
181 response_from_method_ = NULL;
182 method_is_called_ = false;
183 // Post a task to run the method in the origin thread.
184 bus_->PostTaskToOriginThread(FROM_HERE,
185 base::Bind(&ExportedObject::RunMethod,
186 this,
187 iter->second,
188 method_call.get()));
189 // Wait until the method call is done. Blocking is not desirable but we
190 // should return the response to the dbus-daemon in the function, so we
191 // don't have a choice. We wait in the D-Bus thread, so it should be ok.
192 {
193 base::AutoLock auto_lock(method_is_called_lock_);
194 while (!method_is_called_)
195 on_method_is_called_.Wait();
stevenjb 2011/08/15 21:42:04 Does this have a built-in timeout? If not, should
stevenjb 2011/08/16 22:53:29 Looking at this more closely, if the callback (ite
satorux1 2011/08/16 23:19:40 My bad, I missed the original comment. You are abs
196 }
197 response = response_from_method_;
198 } else {
199 // If the D-Bus thread is not used, just call the method directly. We
200 // don't need the complicated logic to wait for the method call to be
201 // complete.
202 response = iter->second.Run(method_call.get());
203 }
204
205 if (!response) {
206 // Something bad happend in the method call.
207 scoped_ptr<dbus::ErrorResponse> error_response(
208 ErrorResponse::FromMethodCall(method_call.get(),
209 DBUS_ERROR_FAILED,
210 "error occurred in " + member));
211 dbus_connection_send(connection, error_response->raw_message(), NULL);
212 return DBUS_HANDLER_RESULT_HANDLED;
213 }
214
215 // The method call was successful.
216 dbus_connection_send(connection, response->raw_message(), NULL);
217 delete response;
218
219 return DBUS_HANDLER_RESULT_HANDLED;
220 }
221
222 void ExportedObject::RunMethod(MethodCallCallback method_call_callback,
223 MethodCall* method_call) {
224 bus_->AssertOnOriginThread();
225
226 base::AutoLock auto_lock(method_is_called_lock_);
227 response_from_method_ = method_call_callback.Run(method_call);
228 method_is_called_ = true;
229 on_method_is_called_.Signal();
230 }
231
232 void ExportedObject::OnUnregistered(DBusConnection* connection) {
233 }
234
235 DBusHandlerResult ExportedObject::HandleMessageThunk(
236 DBusConnection* connection,
237 DBusMessage* raw_message,
238 void* user_data) {
239 ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
240 return self->HandleMessage(connection, raw_message);
241 }
242
243 void ExportedObject::OnUnregisteredThunk(DBusConnection *connection,
244 void* user_data) {
245 ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
246 return self->OnUnregistered(connection);
247 }
248
249 } // namespace dbus
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698