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