| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "dbus/bus.h" | 5 #include "dbus/bus.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/metrics/histogram.h" |
| 10 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
| 11 #include "base/threading/thread.h" | 12 #include "base/threading/thread.h" |
| 12 #include "base/threading/thread_restrictions.h" | 13 #include "base/threading/thread_restrictions.h" |
| 13 #include "dbus/message.h" | 14 #include "dbus/message.h" |
| 14 #include "dbus/object_proxy.h" | 15 #include "dbus/object_proxy.h" |
| 15 #include "dbus/scoped_dbus_error.h" | 16 #include "dbus/scoped_dbus_error.h" |
| 16 | 17 |
| 17 namespace { | 18 namespace { |
| 18 | 19 |
| 20 // Used for success ratio histograms. 1 for success, 0 for failure. |
| 21 const int kSuccessRatioHistogramMaxValue = 2; |
| 22 |
| 19 // Gets the absolute signal name by concatenating the interface name and | 23 // Gets the absolute signal name by concatenating the interface name and |
| 20 // the signal name. Used for building keys for method_table_ in | 24 // the signal name. Used for building keys for method_table_ in |
| 21 // ObjectProxy. | 25 // ObjectProxy. |
| 22 std::string GetAbsoluteSignalName( | 26 std::string GetAbsoluteSignalName( |
| 23 const std::string& interface_name, | 27 const std::string& interface_name, |
| 24 const std::string& signal_name) { | 28 const std::string& signal_name) { |
| 25 return interface_name + "." + signal_name; | 29 return interface_name + "." + signal_name; |
| 26 } | 30 } |
| 27 | 31 |
| 28 } // namespace | 32 } // namespace |
| (...skipping 22 matching lines...) Expand all Loading... |
| 51 if (!bus_->Connect()) | 55 if (!bus_->Connect()) |
| 52 return NULL; | 56 return NULL; |
| 53 | 57 |
| 54 method_call->SetDestination(service_name_); | 58 method_call->SetDestination(service_name_); |
| 55 method_call->SetPath(object_path_); | 59 method_call->SetPath(object_path_); |
| 56 DBusMessage* request_message = method_call->raw_message(); | 60 DBusMessage* request_message = method_call->raw_message(); |
| 57 | 61 |
| 58 ScopedDBusError error; | 62 ScopedDBusError error; |
| 59 | 63 |
| 60 // Send the message synchronously. | 64 // Send the message synchronously. |
| 65 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 61 DBusMessage* response_message = | 66 DBusMessage* response_message = |
| 62 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error.get()); | 67 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error.get()); |
| 68 // Record if the method call is successful, or not. 1 if successful. |
| 69 UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess", |
| 70 response_message ? 1 : 0, |
| 71 kSuccessRatioHistogramMaxValue); |
| 63 | 72 |
| 64 if (!response_message) { | 73 if (!response_message) { |
| 65 LOG(ERROR) << "Failed to call method: " | 74 LOG(ERROR) << "Failed to call method: " |
| 66 << (error.is_set() ? error.message() : ""); | 75 << (error.is_set() ? error.message() : ""); |
| 67 return NULL; | 76 return NULL; |
| 68 } | 77 } |
| 78 // Record time spent for the method call. Don't include failures. |
| 79 UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime", |
| 80 base::TimeTicks::Now() - start_time); |
| 69 | 81 |
| 70 return Response::FromRawMessage(response_message); | 82 return Response::FromRawMessage(response_message); |
| 71 } | 83 } |
| 72 | 84 |
| 73 void ObjectProxy::CallMethod(MethodCall* method_call, | 85 void ObjectProxy::CallMethod(MethodCall* method_call, |
| 74 int timeout_ms, | 86 int timeout_ms, |
| 75 ResponseCallback callback) { | 87 ResponseCallback callback) { |
| 76 bus_->AssertOnOriginThread(); | 88 bus_->AssertOnOriginThread(); |
| 77 | 89 |
| 78 method_call->SetDestination(service_name_); | 90 method_call->SetDestination(service_name_); |
| 79 method_call->SetPath(object_path_); | 91 method_call->SetPath(object_path_); |
| 80 // Increment the reference count so we can safely reference the | 92 // Increment the reference count so we can safely reference the |
| 81 // underlying request message until the method call is complete. This | 93 // underlying request message until the method call is complete. This |
| 82 // will be unref'ed in StartAsyncMethodCall(). | 94 // will be unref'ed in StartAsyncMethodCall(). |
| 83 DBusMessage* request_message = method_call->raw_message(); | 95 DBusMessage* request_message = method_call->raw_message(); |
| 84 dbus_message_ref(request_message); | 96 dbus_message_ref(request_message); |
| 85 | 97 |
| 86 // Bind() won't compile if we pass request_message as-is since | 98 // Bind() won't compile if we pass request_message as-is since |
| 87 // DBusMessage is an opaque struct which Bind() cannot handle. | 99 // DBusMessage is an opaque struct which Bind() cannot handle. |
| 88 // Hence we cast it to void* to workaround the issue. | 100 // Hence we cast it to void* to workaround the issue. |
| 101 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 89 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall, | 102 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall, |
| 90 this, | 103 this, |
| 91 timeout_ms, | 104 timeout_ms, |
| 92 static_cast<void*>(request_message), | 105 static_cast<void*>(request_message), |
| 93 callback); | 106 callback, |
| 107 start_time); |
| 94 // Wait for the response in the D-Bus thread. | 108 // Wait for the response in the D-Bus thread. |
| 95 bus_->PostTaskToDBusThread(FROM_HERE, task); | 109 bus_->PostTaskToDBusThread(FROM_HERE, task); |
| 96 } | 110 } |
| 97 | 111 |
| 98 void ObjectProxy::ConnectToSignal(const std::string& interface_name, | 112 void ObjectProxy::ConnectToSignal(const std::string& interface_name, |
| 99 const std::string& signal_name, | 113 const std::string& signal_name, |
| 100 SignalCallback signal_callback, | 114 SignalCallback signal_callback, |
| 101 OnConnectedCallback on_connected_callback) { | 115 OnConnectedCallback on_connected_callback) { |
| 102 bus_->AssertOnOriginThread(); | 116 bus_->AssertOnOriginThread(); |
| 103 | 117 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 121 bus_->RemoveMatch(match_rules_[i], error.get()); | 135 bus_->RemoveMatch(match_rules_[i], error.get()); |
| 122 if (error.is_set()) { | 136 if (error.is_set()) { |
| 123 // There is nothing we can do to recover, so just print the error. | 137 // There is nothing we can do to recover, so just print the error. |
| 124 LOG(ERROR) << "Failed to remove match rule: " << match_rules_[i]; | 138 LOG(ERROR) << "Failed to remove match rule: " << match_rules_[i]; |
| 125 } | 139 } |
| 126 } | 140 } |
| 127 } | 141 } |
| 128 | 142 |
| 129 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData( | 143 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData( |
| 130 ObjectProxy* in_object_proxy, | 144 ObjectProxy* in_object_proxy, |
| 131 ResponseCallback in_response_callback) | 145 ResponseCallback in_response_callback, |
| 146 base::TimeTicks in_start_time) |
| 132 : object_proxy(in_object_proxy), | 147 : object_proxy(in_object_proxy), |
| 133 response_callback(in_response_callback) { | 148 response_callback(in_response_callback), |
| 149 start_time(in_start_time) { |
| 134 } | 150 } |
| 135 | 151 |
| 136 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() { | 152 ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() { |
| 137 } | 153 } |
| 138 | 154 |
| 139 void ObjectProxy::StartAsyncMethodCall(int timeout_ms, | 155 void ObjectProxy::StartAsyncMethodCall(int timeout_ms, |
| 140 void* in_request_message, | 156 void* in_request_message, |
| 141 ResponseCallback response_callback) { | 157 ResponseCallback response_callback, |
| 158 base::TimeTicks start_time) { |
| 142 bus_->AssertOnDBusThread(); | 159 bus_->AssertOnDBusThread(); |
| 143 | 160 |
| 144 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) { | 161 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) { |
| 145 // In case of a failure, run the callback with NULL response, that | 162 // In case of a failure, run the callback with NULL response, that |
| 146 // indicates a failure. | 163 // indicates a failure. |
| 147 Response* response = NULL; | 164 Response* response = NULL; |
| 148 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, | 165 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, |
| 149 this, | 166 this, |
| 150 response_callback, | 167 response_callback, |
| 168 start_time, |
| 151 response); | 169 response); |
| 152 bus_->PostTaskToOriginThread(FROM_HERE, task); | 170 bus_->PostTaskToOriginThread(FROM_HERE, task); |
| 153 return; | 171 return; |
| 154 } | 172 } |
| 155 | 173 |
| 156 DBusMessage* request_message = | 174 DBusMessage* request_message = |
| 157 static_cast<DBusMessage*>(in_request_message); | 175 static_cast<DBusMessage*>(in_request_message); |
| 158 DBusPendingCall* pending_call = NULL; | 176 DBusPendingCall* pending_call = NULL; |
| 159 | 177 |
| 160 bus_->SendWithReply(request_message, &pending_call, timeout_ms); | 178 bus_->SendWithReply(request_message, &pending_call, timeout_ms); |
| 161 | 179 |
| 162 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk(). | 180 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk(). |
| 163 // The data will be deleted in OnPendingCallIsCompleteThunk(). | 181 // The data will be deleted in OnPendingCallIsCompleteThunk(). |
| 164 OnPendingCallIsCompleteData* data = | 182 OnPendingCallIsCompleteData* data = |
| 165 new OnPendingCallIsCompleteData(this, response_callback); | 183 new OnPendingCallIsCompleteData(this, response_callback, start_time); |
| 166 | 184 |
| 167 // This returns false only when unable to allocate memory. | 185 // This returns false only when unable to allocate memory. |
| 168 const bool success = dbus_pending_call_set_notify( | 186 const bool success = dbus_pending_call_set_notify( |
| 169 pending_call, | 187 pending_call, |
| 170 &ObjectProxy::OnPendingCallIsCompleteThunk, | 188 &ObjectProxy::OnPendingCallIsCompleteThunk, |
| 171 data, | 189 data, |
| 172 NULL); | 190 NULL); |
| 173 CHECK(success) << "Unable to allocate memory"; | 191 CHECK(success) << "Unable to allocate memory"; |
| 174 dbus_pending_call_unref(pending_call); | 192 dbus_pending_call_unref(pending_call); |
| 175 | 193 |
| 176 // It's now safe to unref the request message. | 194 // It's now safe to unref the request message. |
| 177 dbus_message_unref(request_message); | 195 dbus_message_unref(request_message); |
| 178 } | 196 } |
| 179 | 197 |
| 180 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call, | 198 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call, |
| 181 ResponseCallback response_callback) { | 199 ResponseCallback response_callback, |
| 200 base::TimeTicks start_time) { |
| 182 bus_->AssertOnDBusThread(); | 201 bus_->AssertOnDBusThread(); |
| 183 | 202 |
| 184 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call); | 203 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call); |
| 185 // |response_message| will be unref'ed in RunResponseCallback(). | 204 // |response_message| will be unref'ed in RunResponseCallback(). |
| 186 // Bind() won't compile if we pass response_message as-is. | 205 // Bind() won't compile if we pass response_message as-is. |
| 187 // See CallMethod() for details. | 206 // See CallMethod() for details. |
| 188 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, | 207 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, |
| 189 this, | 208 this, |
| 190 response_callback, | 209 response_callback, |
| 210 start_time, |
| 191 static_cast<void*>(response_message)); | 211 static_cast<void*>(response_message)); |
| 192 bus_->PostTaskToOriginThread(FROM_HERE, task); | 212 bus_->PostTaskToOriginThread(FROM_HERE, task); |
| 193 } | 213 } |
| 194 | 214 |
| 195 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback, | 215 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback, |
| 216 base::TimeTicks start_time, |
| 196 void* in_response_message) { | 217 void* in_response_message) { |
| 197 bus_->AssertOnOriginThread(); | 218 bus_->AssertOnOriginThread(); |
| 198 DBusMessage* response_message = | 219 DBusMessage* response_message = |
| 199 static_cast<DBusMessage*>(in_response_message); | 220 static_cast<DBusMessage*>(in_response_message); |
| 200 | 221 |
| 222 bool response_callback_called = false; |
| 201 if (!response_message) { | 223 if (!response_message) { |
| 202 // The response is not received. | 224 // The response is not received. |
| 203 response_callback.Run(NULL); | 225 response_callback.Run(NULL); |
| 204 } else if (dbus_message_get_type(response_message) == | 226 } else if (dbus_message_get_type(response_message) == |
| 205 DBUS_MESSAGE_TYPE_ERROR) { | 227 DBUS_MESSAGE_TYPE_ERROR) { |
| 206 // This will take |response_message| and release (unref) it. | 228 // This will take |response_message| and release (unref) it. |
| 207 scoped_ptr<dbus::ErrorResponse> error_response( | 229 scoped_ptr<dbus::ErrorResponse> error_response( |
| 208 dbus::ErrorResponse::FromRawMessage(response_message)); | 230 dbus::ErrorResponse::FromRawMessage(response_message)); |
| 209 // Error message may contain the error message as string. | 231 // Error message may contain the error message as string. |
| 210 dbus::MessageReader reader(error_response.get()); | 232 dbus::MessageReader reader(error_response.get()); |
| 211 std::string error_message; | 233 std::string error_message; |
| 212 reader.PopString(&error_message); | 234 reader.PopString(&error_message); |
| 213 LOG(ERROR) << "Failed to call method: " << error_response->GetErrorName() | 235 LOG(ERROR) << "Failed to call method: " << error_response->GetErrorName() |
| 214 << ": " << error_message; | 236 << ": " << error_message; |
| 215 // We don't give the error message to the callback. | 237 // We don't give the error message to the callback. |
| 216 response_callback.Run(NULL); | 238 response_callback.Run(NULL); |
| 217 } else { | 239 } else { |
| 218 // This will take |response_message| and release (unref) it. | 240 // This will take |response_message| and release (unref) it. |
| 219 scoped_ptr<dbus::Response> response( | 241 scoped_ptr<dbus::Response> response( |
| 220 dbus::Response::FromRawMessage(response_message)); | 242 dbus::Response::FromRawMessage(response_message)); |
| 221 // The response is successfully received. | 243 // The response is successfully received. |
| 222 response_callback.Run(response.get()); | 244 response_callback.Run(response.get()); |
| 245 response_callback_called = true; |
| 246 // Record time spent for the method call. Don't include failures. |
| 247 UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime", |
| 248 base::TimeTicks::Now() - start_time); |
| 223 } | 249 } |
| 250 // Record if the method call is successful, or not. 1 if successful. |
| 251 UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess", |
| 252 response_callback_called, |
| 253 kSuccessRatioHistogramMaxValue); |
| 224 } | 254 } |
| 225 | 255 |
| 226 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call, | 256 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call, |
| 227 void* user_data) { | 257 void* user_data) { |
| 228 OnPendingCallIsCompleteData* data = | 258 OnPendingCallIsCompleteData* data = |
| 229 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data); | 259 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data); |
| 230 ObjectProxy* self = data->object_proxy; | 260 ObjectProxy* self = data->object_proxy; |
| 231 self->OnPendingCallIsComplete(pending_call, | 261 self->OnPendingCallIsComplete(pending_call, |
| 232 data->response_callback); | 262 data->response_callback, |
| 263 data->start_time); |
| 233 delete data; | 264 delete data; |
| 234 } | 265 } |
| 235 | 266 |
| 236 void ObjectProxy::ConnectToSignalInternal( | 267 void ObjectProxy::ConnectToSignalInternal( |
| 237 const std::string& interface_name, | 268 const std::string& interface_name, |
| 238 const std::string& signal_name, | 269 const std::string& signal_name, |
| 239 SignalCallback signal_callback, | 270 SignalCallback signal_callback, |
| 240 OnConnectedCallback on_connected_callback) { | 271 OnConnectedCallback on_connected_callback) { |
| 241 bus_->AssertOnDBusThread(); | 272 bus_->AssertOnDBusThread(); |
| 242 | 273 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 scoped_ptr<Signal> signal( | 341 scoped_ptr<Signal> signal( |
| 311 Signal::FromRawMessage(raw_message)); | 342 Signal::FromRawMessage(raw_message)); |
| 312 | 343 |
| 313 // The signal is not coming from the remote object we are attaching to. | 344 // The signal is not coming from the remote object we are attaching to. |
| 314 if (signal->GetPath() != object_path_) | 345 if (signal->GetPath() != object_path_) |
| 315 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 346 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| 316 | 347 |
| 317 const std::string interface = signal->GetInterface(); | 348 const std::string interface = signal->GetInterface(); |
| 318 const std::string member = signal->GetMember(); | 349 const std::string member = signal->GetMember(); |
| 319 | 350 |
| 320 // Check if we know about the method. | 351 // Check if we know about the signal. |
| 321 const std::string absolute_signal_name = GetAbsoluteSignalName( | 352 const std::string absolute_signal_name = GetAbsoluteSignalName( |
| 322 interface, member); | 353 interface, member); |
| 323 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name); | 354 MethodTable::const_iterator iter = method_table_.find(absolute_signal_name); |
| 324 if (iter == method_table_.end()) { | 355 if (iter == method_table_.end()) { |
| 325 // Don't know about the method. | 356 // Don't know about the signal. |
| 326 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 357 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| 327 } | 358 } |
| 328 | 359 |
| 360 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 329 if (bus_->HasDBusThread()) { | 361 if (bus_->HasDBusThread()) { |
| 330 // Post a task to run the method in the origin thread. | 362 // Post a task to run the method in the origin thread. |
| 331 // Transfer the ownership of |signal| to RunMethod(). | 363 // Transfer the ownership of |signal| to RunMethod(). |
| 332 // |released_signal| will be deleted in RunMethod(). | 364 // |released_signal| will be deleted in RunMethod(). |
| 333 Signal* released_signal = signal.release(); | 365 Signal* released_signal = signal.release(); |
| 334 bus_->PostTaskToOriginThread(FROM_HERE, | 366 bus_->PostTaskToOriginThread(FROM_HERE, |
| 335 base::Bind(&ObjectProxy::RunMethod, | 367 base::Bind(&ObjectProxy::RunMethod, |
| 336 this, | 368 this, |
| 369 start_time, |
| 337 iter->second, | 370 iter->second, |
| 338 released_signal)); | 371 released_signal)); |
| 339 } else { | 372 } else { |
| 340 // If the D-Bus thread is not used, just call the method directly. We | 373 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 341 // don't need the complicated logic to wait for the method call to be | 374 // If the D-Bus thread is not used, just call the callback on the |
| 342 // complete. | 375 // current thread. Transfer the ownership of |signal| to RunMethod(). |
| 343 iter->second.Run(signal.get()); | 376 Signal* released_signal = signal.release(); |
| 377 RunMethod(start_time, iter->second, released_signal); |
| 344 } | 378 } |
| 345 | 379 |
| 346 return DBUS_HANDLER_RESULT_HANDLED; | 380 return DBUS_HANDLER_RESULT_HANDLED; |
| 347 } | 381 } |
| 348 | 382 |
| 349 void ObjectProxy::RunMethod(SignalCallback signal_callback, | 383 void ObjectProxy::RunMethod(base::TimeTicks start_time, |
| 384 SignalCallback signal_callback, |
| 350 Signal* signal) { | 385 Signal* signal) { |
| 351 bus_->AssertOnOriginThread(); | 386 bus_->AssertOnOriginThread(); |
| 352 | 387 |
| 353 signal_callback.Run(signal); | 388 signal_callback.Run(signal); |
| 354 delete signal; | 389 delete signal; |
| 390 // Record time spent for handling the signal. |
| 391 UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime", |
| 392 base::TimeTicks::Now() - start_time); |
| 355 } | 393 } |
| 356 | 394 |
| 357 DBusHandlerResult ObjectProxy::HandleMessageThunk( | 395 DBusHandlerResult ObjectProxy::HandleMessageThunk( |
| 358 DBusConnection* connection, | 396 DBusConnection* connection, |
| 359 DBusMessage* raw_message, | 397 DBusMessage* raw_message, |
| 360 void* user_data) { | 398 void* user_data) { |
| 361 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data); | 399 ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data); |
| 362 return self->HandleMessage(connection, raw_message); | 400 return self->HandleMessage(connection, raw_message); |
| 363 } | 401 } |
| 364 | 402 |
| 365 } // namespace dbus | 403 } // namespace dbus |
| OLD | NEW |