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

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: comments updated 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_.insert(std::make_pair(
65 absolute_method_name, method_call_callback)).second == false) {
66 LOG(ERROR) << absolute_method_name << "is already exported";
67 return false;
68 }
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 const bool success = bus_->UnregisterObjectPath(object_path_);
95 CHECK(success) << "Unable to allocate memory";
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_->has_dbus_thread()) {
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 base::AutoLock auto_lock(method_is_called_lock_);
195 while (!method_is_called_)
196 on_method_is_called_.Wait();
197 }
198 response = response_from_method_;
199 } else {
200 // If the D-Bus thread is not use, just call the method directly. We
201 // don't need the complicated logic to wait for the method call to be
202 // complete.
203 response = iter->second.Run(method_call.get());
204 }
205
206 if (!response) {
207 // Something bad happend in the method call.
208 scoped_ptr<dbus::ErrorResponse> error_response(
209 ErrorResponse::FromMethodCall(method_call.get(),
210 DBUS_ERROR_FAILED,
211 "error occurred in " + member));
212 dbus_connection_send(connection, error_response->raw_message(), NULL);
213 return DBUS_HANDLER_RESULT_HANDLED;
214 }
215
216 // The method call was successful.
217 dbus_connection_send(connection, response->raw_message(), NULL);
218 delete response;
219
220 return DBUS_HANDLER_RESULT_HANDLED;
221 }
222
223 void ExportedObject::RunMethod(MethodCallCallback method_call_callback,
224 MethodCall* method_call) {
225 bus_->AssertOnOriginThread();
226
227 base::AutoLock auto_lock(method_is_called_lock_);
228 response_from_method_ = method_call_callback.Run(method_call);
229 method_is_called_ = true;
230 on_method_is_called_.Signal();
231 }
232
233 void ExportedObject::OnUnregistered(DBusConnection* connection) {
234 }
235
236 DBusHandlerResult ExportedObject::HandleMessageThunk(
237 DBusConnection* connection,
238 DBusMessage* raw_message,
239 void* user_data) {
240 ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
241 return self->HandleMessage(connection, raw_message);
242 }
243
244 void ExportedObject::OnUnregisteredThunk(DBusConnection *connection,
245 void* user_data) {
246 ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
247 return self->OnUnregistered(connection);
248 }
249
250 } // namespace dbus
OLDNEW
« dbus/bus.cc ('K') | « dbus/exported_object.h ('k') | dbus/object_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698