| 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/exported_object.h" | 5 #include "dbus/exported_object.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/memory/ref_counted.h" | 9 #include "base/memory/ref_counted.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "base/metrics/histogram.h" |
| 11 #include "base/threading/thread_restrictions.h" | 12 #include "base/threading/thread_restrictions.h" |
| 12 #include "base/time.h" | 13 #include "base/time.h" |
| 13 #include "dbus/bus.h" | 14 #include "dbus/bus.h" |
| 14 #include "dbus/message.h" | 15 #include "dbus/message.h" |
| 15 #include "dbus/scoped_dbus_error.h" | 16 #include "dbus/scoped_dbus_error.h" |
| 16 | 17 |
| 17 namespace dbus { | 18 namespace dbus { |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| 22 // Used for success ratio histograms. 1 for success, 0 for failure. |
| 23 const int kSuccessRatioHistogramMaxValue = 2; |
| 24 |
| 21 // Gets the absolute method name by concatenating the interface name and | 25 // Gets the absolute method name by concatenating the interface name and |
| 22 // the method name. Used for building keys for method_table_ in | 26 // the method name. Used for building keys for method_table_ in |
| 23 // ExportedObject. | 27 // ExportedObject. |
| 24 std::string GetAbsoluteMethodName( | 28 std::string GetAbsoluteMethodName( |
| 25 const std::string& interface_name, | 29 const std::string& interface_name, |
| 26 const std::string& method_name) { | 30 const std::string& method_name) { |
| 27 return interface_name + "." + method_name; | 31 return interface_name + "." + method_name; |
| 28 } | 32 } |
| 29 | 33 |
| 30 } // namespace | 34 } // namespace |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 // For signals, the object path should be set to the path to the sender | 97 // For signals, the object path should be set to the path to the sender |
| 94 // object, which is this exported object here. | 98 // object, which is this exported object here. |
| 95 signal->SetPath(object_path_); | 99 signal->SetPath(object_path_); |
| 96 | 100 |
| 97 // Increment the reference count so we can safely reference the | 101 // Increment the reference count so we can safely reference the |
| 98 // underlying signal message until the signal sending is complete. This | 102 // underlying signal message until the signal sending is complete. This |
| 99 // will be unref'ed in SendSignalInternal(). | 103 // will be unref'ed in SendSignalInternal(). |
| 100 DBusMessage* signal_message = signal->raw_message(); | 104 DBusMessage* signal_message = signal->raw_message(); |
| 101 dbus_message_ref(signal_message); | 105 dbus_message_ref(signal_message); |
| 102 | 106 |
| 107 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 103 // Bind() won't compile if we pass signal_message. See the comment at | 108 // Bind() won't compile if we pass signal_message. See the comment at |
| 104 // ObjectProxy::CallMethod() for details. | 109 // ObjectProxy::CallMethod() for details. |
| 105 bus_->PostTaskToDBusThread(FROM_HERE, | 110 bus_->PostTaskToDBusThread(FROM_HERE, |
| 106 base::Bind(&ExportedObject::SendSignalInternal, | 111 base::Bind(&ExportedObject::SendSignalInternal, |
| 107 this, | 112 this, |
| 113 start_time, |
| 108 static_cast<void*>(signal_message))); | 114 static_cast<void*>(signal_message))); |
| 109 } | 115 } |
| 110 | 116 |
| 111 void ExportedObject::Unregister() { | 117 void ExportedObject::Unregister() { |
| 112 bus_->AssertOnDBusThread(); | 118 bus_->AssertOnDBusThread(); |
| 113 | 119 |
| 114 if (!object_is_registered_) | 120 if (!object_is_registered_) |
| 115 return; | 121 return; |
| 116 | 122 |
| 117 bus_->UnregisterObjectPath(object_path_); | 123 bus_->UnregisterObjectPath(object_path_); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 139 | 145 |
| 140 void ExportedObject::OnExported(OnExportedCallback on_exported_callback, | 146 void ExportedObject::OnExported(OnExportedCallback on_exported_callback, |
| 141 const std::string& interface_name, | 147 const std::string& interface_name, |
| 142 const std::string& method_name, | 148 const std::string& method_name, |
| 143 bool success) { | 149 bool success) { |
| 144 bus_->AssertOnOriginThread(); | 150 bus_->AssertOnOriginThread(); |
| 145 | 151 |
| 146 on_exported_callback.Run(interface_name, method_name, success); | 152 on_exported_callback.Run(interface_name, method_name, success); |
| 147 } | 153 } |
| 148 | 154 |
| 149 void ExportedObject::SendSignalInternal(void* in_signal_message) { | 155 void ExportedObject::SendSignalInternal(base::TimeTicks start_time, |
| 156 void* in_signal_message) { |
| 150 DBusMessage* signal_message = | 157 DBusMessage* signal_message = |
| 151 static_cast<DBusMessage*>(in_signal_message); | 158 static_cast<DBusMessage*>(in_signal_message); |
| 152 uint32 serial = 0; | 159 uint32 serial = 0; |
| 153 bus_->Send(signal_message, &serial); | 160 bus_->Send(signal_message, &serial); |
| 154 dbus_message_unref(signal_message); | 161 dbus_message_unref(signal_message); |
| 162 // Record time spent to send the the signal. This is not accurate as the |
| 163 // signal will actually be sent from the next run of the message loop, |
| 164 // but we can at least tell the number of signals sent. |
| 165 UMA_HISTOGRAM_TIMES("DBus.SignalSendTime", |
| 166 base::TimeTicks::Now() - start_time); |
| 155 } | 167 } |
| 156 | 168 |
| 157 bool ExportedObject::Register() { | 169 bool ExportedObject::Register() { |
| 158 bus_->AssertOnDBusThread(); | 170 bus_->AssertOnDBusThread(); |
| 159 | 171 |
| 160 if (object_is_registered_) | 172 if (object_is_registered_) |
| 161 return true; | 173 return true; |
| 162 | 174 |
| 163 ScopedDBusError error; | 175 ScopedDBusError error; |
| 164 | 176 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 188 // raw_message will be unrefed on exit of the function. Increment the | 200 // raw_message will be unrefed on exit of the function. Increment the |
| 189 // reference so we can use it in MethodCall. | 201 // reference so we can use it in MethodCall. |
| 190 dbus_message_ref(raw_message); | 202 dbus_message_ref(raw_message); |
| 191 scoped_ptr<MethodCall> method_call( | 203 scoped_ptr<MethodCall> method_call( |
| 192 MethodCall::FromRawMessage(raw_message)); | 204 MethodCall::FromRawMessage(raw_message)); |
| 193 const std::string interface = method_call->GetInterface(); | 205 const std::string interface = method_call->GetInterface(); |
| 194 const std::string member = method_call->GetMember(); | 206 const std::string member = method_call->GetMember(); |
| 195 | 207 |
| 196 if (interface.empty()) { | 208 if (interface.empty()) { |
| 197 // We don't support method calls without interface. | 209 // We don't support method calls without interface. |
| 210 LOG(WARNING) << "Interface is missing: " << method_call->ToString(); |
| 198 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 211 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| 199 } | 212 } |
| 200 | 213 |
| 201 // Check if we know about the method. | 214 // Check if we know about the method. |
| 202 const std::string absolute_method_name = GetAbsoluteMethodName( | 215 const std::string absolute_method_name = GetAbsoluteMethodName( |
| 203 interface, member); | 216 interface, member); |
| 204 MethodTable::const_iterator iter = method_table_.find(absolute_method_name); | 217 MethodTable::const_iterator iter = method_table_.find(absolute_method_name); |
| 205 if (iter == method_table_.end()) { | 218 if (iter == method_table_.end()) { |
| 206 // Don't know about the method. | 219 // Don't know about the method. |
| 220 LOG(WARNING) << "Unknown method: " << method_call->ToString(); |
| 207 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 221 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| 208 } | 222 } |
| 209 | 223 |
| 224 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 210 Response* response = NULL; | 225 Response* response = NULL; |
| 211 if (bus_->HasDBusThread()) { | 226 if (bus_->HasDBusThread()) { |
| 212 response_from_method_ = NULL; | 227 response_from_method_ = NULL; |
| 213 // Post a task to run the method in the origin thread. | 228 // Post a task to run the method in the origin thread. |
| 214 bus_->PostTaskToOriginThread(FROM_HERE, | 229 bus_->PostTaskToOriginThread(FROM_HERE, |
| 215 base::Bind(&ExportedObject::RunMethod, | 230 base::Bind(&ExportedObject::RunMethod, |
| 216 this, | 231 this, |
| 217 iter->second, | 232 iter->second, |
| 218 method_call.get())); | 233 method_call.get())); |
| 219 // Wait until the method call is done. Blocking is not desirable but we | 234 // Wait until the method call is done. Blocking is not desirable but we |
| (...skipping 10 matching lines...) Expand all Loading... |
| 230 // infinitely in the origin thread. No way to stop it from here. | 245 // infinitely in the origin thread. No way to stop it from here. |
| 231 CHECK(signaled) << "Method " << absolute_method_name << " not called"; | 246 CHECK(signaled) << "Method " << absolute_method_name << " not called"; |
| 232 } | 247 } |
| 233 response = response_from_method_; | 248 response = response_from_method_; |
| 234 } else { | 249 } else { |
| 235 // If the D-Bus thread is not used, just call the method directly. We | 250 // If the D-Bus thread is not used, just call the method directly. We |
| 236 // don't need the complicated logic to wait for the method call to be | 251 // don't need the complicated logic to wait for the method call to be |
| 237 // complete. | 252 // complete. |
| 238 response = iter->second.Run(method_call.get()); | 253 response = iter->second.Run(method_call.get()); |
| 239 } | 254 } |
| 255 // Record if the method call is successful, or not. 1 if successful. |
| 256 UMA_HISTOGRAM_ENUMERATION("DBus.ExportedMethodHandleSuccess", |
| 257 response ? 1 : 0, |
| 258 kSuccessRatioHistogramMaxValue); |
| 240 | 259 |
| 241 if (!response) { | 260 if (!response) { |
| 242 // Something bad happened in the method call. | 261 // Something bad happened in the method call. |
| 243 scoped_ptr<dbus::ErrorResponse> error_response( | 262 scoped_ptr<dbus::ErrorResponse> error_response( |
| 244 ErrorResponse::FromMethodCall(method_call.get(), | 263 ErrorResponse::FromMethodCall(method_call.get(), |
| 245 DBUS_ERROR_FAILED, | 264 DBUS_ERROR_FAILED, |
| 246 "error occurred in " + member)); | 265 "error occurred in " + member)); |
| 247 dbus_connection_send(connection, error_response->raw_message(), NULL); | 266 dbus_connection_send(connection, error_response->raw_message(), NULL); |
| 248 return DBUS_HANDLER_RESULT_HANDLED; | 267 return DBUS_HANDLER_RESULT_HANDLED; |
| 249 } | 268 } |
| 250 | 269 |
| 251 // The method call was successful. | 270 // The method call was successful. |
| 252 dbus_connection_send(connection, response->raw_message(), NULL); | 271 dbus_connection_send(connection, response->raw_message(), NULL); |
| 253 delete response; | 272 delete response; |
| 273 // Record time spent to handle the the method call. Don't include failures. |
| 274 UMA_HISTOGRAM_TIMES("DBus.ExportedMethodHandleTime", |
| 275 base::TimeTicks::Now() - start_time); |
| 254 | 276 |
| 255 return DBUS_HANDLER_RESULT_HANDLED; | 277 return DBUS_HANDLER_RESULT_HANDLED; |
| 256 } | 278 } |
| 257 | 279 |
| 258 void ExportedObject::RunMethod(MethodCallCallback method_call_callback, | 280 void ExportedObject::RunMethod(MethodCallCallback method_call_callback, |
| 259 MethodCall* method_call) { | 281 MethodCall* method_call) { |
| 260 bus_->AssertOnOriginThread(); | 282 bus_->AssertOnOriginThread(); |
| 261 | 283 |
| 262 response_from_method_ = method_call_callback.Run(method_call); | 284 response_from_method_ = method_call_callback.Run(method_call); |
| 263 on_method_is_called_.Signal(); | 285 on_method_is_called_.Signal(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 274 return self->HandleMessage(connection, raw_message); | 296 return self->HandleMessage(connection, raw_message); |
| 275 } | 297 } |
| 276 | 298 |
| 277 void ExportedObject::OnUnregisteredThunk(DBusConnection *connection, | 299 void ExportedObject::OnUnregisteredThunk(DBusConnection *connection, |
| 278 void* user_data) { | 300 void* user_data) { |
| 279 ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data); | 301 ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data); |
| 280 return self->OnUnregistered(connection); | 302 return self->OnUnregistered(connection); |
| 281 } | 303 } |
| 282 | 304 |
| 283 } // namespace dbus | 305 } // namespace dbus |
| OLD | NEW |