1 // Copyright 2013 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 "chromeos/dbus/bluetooth_agent_service_provider.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "base/memory/ref_counted.h" 12 #include "base/sys_info.h" 13 #include "base/threading/platform_thread.h" 14 #include "chromeos/dbus/fake_bluetooth_agent_service_provider.h" 15 #include "dbus/bus.h" 16 #include "dbus/exported_object.h" 17 #include "dbus/message.h" 18 #include "dbus/object_path.h" 19 #include "third_party/cros_system_api/dbus/service_constants.h" 20 21 namespace chromeos { 22 23 // The BluetoothAgentServiceProvider implementation used in production. 24 class BluetoothAgentServiceProviderImpl 25 : public BluetoothAgentServiceProvider { 26 public: 27 BluetoothAgentServiceProviderImpl(dbus::Bus* bus, 28 const dbus::ObjectPath& object_path, 29 Delegate* delegate) 30 : origin_thread_id_(base::PlatformThread::CurrentId()), 31 bus_(bus), 32 delegate_(delegate), 33 object_path_(object_path), 34 weak_ptr_factory_(this) { 35 VLOG(1) << "Creating Bluetooth Agent: " << object_path_.value(); 36 37 exported_object_ = bus_->GetExportedObject(object_path_); 38 39 exported_object_->ExportMethod( 40 bluetooth_agent::kBluetoothAgentInterface, 41 bluetooth_agent::kRelease, 42 base::Bind(&BluetoothAgentServiceProviderImpl::Release, 43 weak_ptr_factory_.GetWeakPtr()), 44 base::Bind(&BluetoothAgentServiceProviderImpl::OnExported, 45 weak_ptr_factory_.GetWeakPtr())); 46 47 exported_object_->ExportMethod( 48 bluetooth_agent::kBluetoothAgentInterface, 49 bluetooth_agent::kRequestPinCode, 50 base::Bind(&BluetoothAgentServiceProviderImpl::RequestPinCode, 51 weak_ptr_factory_.GetWeakPtr()), 52 base::Bind(&BluetoothAgentServiceProviderImpl::OnExported, 53 weak_ptr_factory_.GetWeakPtr())); 54 55 exported_object_->ExportMethod( 56 bluetooth_agent::kBluetoothAgentInterface, 57 bluetooth_agent::kDisplayPinCode, 58 base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPinCode, 59 weak_ptr_factory_.GetWeakPtr()), 60 base::Bind(&BluetoothAgentServiceProviderImpl::OnExported, 61 weak_ptr_factory_.GetWeakPtr())); 62 63 exported_object_->ExportMethod( 64 bluetooth_agent::kBluetoothAgentInterface, 65 bluetooth_agent::kRequestPasskey, 66 base::Bind(&BluetoothAgentServiceProviderImpl::RequestPasskey, 67 weak_ptr_factory_.GetWeakPtr()), 68 base::Bind(&BluetoothAgentServiceProviderImpl::OnExported, 69 weak_ptr_factory_.GetWeakPtr())); 70 71 exported_object_->ExportMethod( 72 bluetooth_agent::kBluetoothAgentInterface, 73 bluetooth_agent::kDisplayPasskey, 74 base::Bind(&BluetoothAgentServiceProviderImpl::DisplayPasskey, 75 weak_ptr_factory_.GetWeakPtr()), 76 base::Bind(&BluetoothAgentServiceProviderImpl::OnExported, 77 weak_ptr_factory_.GetWeakPtr())); 78 79 exported_object_->ExportMethod( 80 bluetooth_agent::kBluetoothAgentInterface, 81 bluetooth_agent::kRequestConfirmation, 82 base::Bind(&BluetoothAgentServiceProviderImpl::RequestConfirmation, 83 weak_ptr_factory_.GetWeakPtr()), 84 base::Bind(&BluetoothAgentServiceProviderImpl::OnExported, 85 weak_ptr_factory_.GetWeakPtr())); 86 87 exported_object_->ExportMethod( 88 bluetooth_agent::kBluetoothAgentInterface, 89 bluetooth_agent::kRequestAuthorization, 90 base::Bind(&BluetoothAgentServiceProviderImpl::RequestAuthorization, 91 weak_ptr_factory_.GetWeakPtr()), 92 base::Bind(&BluetoothAgentServiceProviderImpl::OnExported, 93 weak_ptr_factory_.GetWeakPtr())); 94 95 exported_object_->ExportMethod( 96 bluetooth_agent::kBluetoothAgentInterface, 97 bluetooth_agent::kAuthorizeService, 98 base::Bind(&BluetoothAgentServiceProviderImpl::AuthorizeService, 99 weak_ptr_factory_.GetWeakPtr()), 100 base::Bind(&BluetoothAgentServiceProviderImpl::OnExported, 101 weak_ptr_factory_.GetWeakPtr())); 102 103 exported_object_->ExportMethod( 104 bluetooth_agent::kBluetoothAgentInterface, 105 bluetooth_agent::kCancel, 106 base::Bind(&BluetoothAgentServiceProviderImpl::Cancel, 107 weak_ptr_factory_.GetWeakPtr()), 108 base::Bind(&BluetoothAgentServiceProviderImpl::OnExported, 109 weak_ptr_factory_.GetWeakPtr())); 110 } 111 112 virtual ~BluetoothAgentServiceProviderImpl() { 113 VLOG(1) << "Cleaning up Bluetooth Agent: " << object_path_.value(); 114 115 // Unregister the object path so we can reuse with a new agent. 116 bus_->UnregisterExportedObject(object_path_); 117 } 118 119 private: 120 // Returns true if the current thread is on the origin thread. 121 bool OnOriginThread() { 122 return base::PlatformThread::CurrentId() == origin_thread_id_; 123 } 124 125 // Called by dbus:: when the agent is unregistered from the Bluetooth 126 // daemon, generally at the end of a pairing request. 127 void Release(dbus::MethodCall* method_call, 128 dbus::ExportedObject::ResponseSender response_sender) { 129 DCHECK(OnOriginThread()); 130 DCHECK(delegate_); 131 132 delegate_->Released(); 133 134 response_sender.Run(dbus::Response::FromMethodCall(method_call)); 135 } 136 137 // Called by dbus:: when the Bluetooth daemon requires a PIN Code for 138 // device authentication. 139 void RequestPinCode(dbus::MethodCall* method_call, 140 dbus::ExportedObject::ResponseSender response_sender) { 141 DCHECK(OnOriginThread()); 142 DCHECK(delegate_); 143 144 dbus::MessageReader reader(method_call); 145 dbus::ObjectPath device_path; 146 if (!reader.PopObjectPath(&device_path)) { 147 LOG(WARNING) << "RequestPinCode called with incorrect paramters: " 148 << method_call->ToString(); 149 return; 150 } 151 152 Delegate::PinCodeCallback callback = base::Bind( 153 &BluetoothAgentServiceProviderImpl::OnPinCode, 154 weak_ptr_factory_.GetWeakPtr(), 155 method_call, 156 response_sender); 157 158 delegate_->RequestPinCode(device_path, callback); 159 } 160 161 // Called by dbus:: when the Bluetooth daemon requires that the user 162 // enter a PIN Code into the remote device so that it may be 163 // authenticated. 164 void DisplayPinCode(dbus::MethodCall* method_call, 165 dbus::ExportedObject::ResponseSender response_sender) { 166 DCHECK(OnOriginThread()); 167 DCHECK(delegate_); 168 169 dbus::MessageReader reader(method_call); 170 dbus::ObjectPath device_path; 171 std::string pincode; 172 if (!reader.PopObjectPath(&device_path) || 173 !reader.PopString(&pincode)) { 174 LOG(WARNING) << "DisplayPinCode called with incorrect paramters: " 175 << method_call->ToString(); 176 return; 177 } 178 179 delegate_->DisplayPinCode(device_path, pincode); 180 181 response_sender.Run(dbus::Response::FromMethodCall(method_call)); 182 } 183 184 // Called by dbus:: when the Bluetooth daemon requires a Passkey for 185 // device authentication. 186 void RequestPasskey(dbus::MethodCall* method_call, 187 dbus::ExportedObject::ResponseSender response_sender) { 188 DCHECK(OnOriginThread()); 189 DCHECK(delegate_); 190 191 dbus::MessageReader reader(method_call); 192 dbus::ObjectPath device_path; 193 if (!reader.PopObjectPath(&device_path)) { 194 LOG(WARNING) << "RequestPasskey called with incorrect paramters: " 195 << method_call->ToString(); 196 return; 197 } 198 199 Delegate::PasskeyCallback callback = base::Bind( 200 &BluetoothAgentServiceProviderImpl::OnPasskey, 201 weak_ptr_factory_.GetWeakPtr(), 202 method_call, 203 response_sender); 204 205 delegate_->RequestPasskey(device_path, callback); 206 } 207 208 // Called by dbus:: when the Bluetooth daemon requires that the user 209 // enter a Passkey into the remote device so that it may be 210 // authenticated. 211 void DisplayPasskey(dbus::MethodCall* method_call, 212 dbus::ExportedObject::ResponseSender response_sender) { 213 DCHECK(OnOriginThread()); 214 DCHECK(delegate_); 215 216 dbus::MessageReader reader(method_call); 217 dbus::ObjectPath device_path; 218 uint32 passkey; 219 uint16 entered; 220 if (!reader.PopObjectPath(&device_path) || 221 !reader.PopUint32(&passkey) || 222 !reader.PopUint16(&entered)) { 223 LOG(WARNING) << "DisplayPasskey called with incorrect paramters: " 224 << method_call->ToString(); 225 return; 226 } 227 228 delegate_->DisplayPasskey(device_path, passkey, entered); 229 230 response_sender.Run(dbus::Response::FromMethodCall(method_call)); 231 } 232 233 // Called by dbus:: when the Bluetooth daemon requires that the user 234 // confirm that a Passkey is displayed on the screen of the remote 235 // device so that it may be authenticated. 236 void RequestConfirmation( 237 dbus::MethodCall* method_call, 238 dbus::ExportedObject::ResponseSender response_sender) { 239 DCHECK(OnOriginThread()); 240 DCHECK(delegate_); 241 242 dbus::MessageReader reader(method_call); 243 dbus::ObjectPath device_path; 244 uint32 passkey; 245 if (!reader.PopObjectPath(&device_path) || 246 !reader.PopUint32(&passkey)) { 247 LOG(WARNING) << "RequestConfirmation called with incorrect paramters: " 248 << method_call->ToString(); 249 return; 250 } 251 252 Delegate::ConfirmationCallback callback = base::Bind( 253 &BluetoothAgentServiceProviderImpl::OnConfirmation, 254 weak_ptr_factory_.GetWeakPtr(), 255 method_call, 256 response_sender); 257 258 delegate_->RequestConfirmation(device_path, passkey, callback); 259 } 260 261 // Called by dbus:: when the Bluetooth daemon requires that the user 262 // confirm an incoming just-works pairing. 263 void RequestAuthorization( 264 dbus::MethodCall* method_call, 265 dbus::ExportedObject::ResponseSender response_sender) { 266 DCHECK(OnOriginThread()); 267 DCHECK(delegate_); 268 269 dbus::MessageReader reader(method_call); 270 dbus::ObjectPath device_path; 271 if (!reader.PopObjectPath(&device_path)) { 272 LOG(WARNING) << "RequestAuthorization called with incorrect paramters: " 273 << method_call->ToString(); 274 return; 275 } 276 277 Delegate::ConfirmationCallback callback = base::Bind( 278 &BluetoothAgentServiceProviderImpl::OnConfirmation, 279 weak_ptr_factory_.GetWeakPtr(), 280 method_call, 281 response_sender); 282 283 delegate_->RequestAuthorization(device_path, callback); 284 } 285 286 // Called by dbus:: when the Bluetooth daemon requires that the user 287 // confirm that that a remote device is authorized to connect to a service 288 // UUID. 289 void AuthorizeService(dbus::MethodCall* method_call, 290 dbus::ExportedObject::ResponseSender response_sender) { 291 DCHECK(OnOriginThread()); 292 DCHECK(delegate_); 293 294 dbus::MessageReader reader(method_call); 295 dbus::ObjectPath device_path; 296 std::string uuid; 297 if (!reader.PopObjectPath(&device_path) || 298 !reader.PopString(&uuid)) { 299 LOG(WARNING) << "AuthorizeService called with incorrect paramters: " 300 << method_call->ToString(); 301 return; 302 } 303 304 Delegate::ConfirmationCallback callback = base::Bind( 305 &BluetoothAgentServiceProviderImpl::OnConfirmation, 306 weak_ptr_factory_.GetWeakPtr(), 307 method_call, 308 response_sender); 309 310 delegate_->AuthorizeService(device_path, uuid, callback); 311 } 312 313 // Called by dbus:: when the request failed before a reply was returned 314 // from the device. 315 void Cancel(dbus::MethodCall* method_call, 316 dbus::ExportedObject::ResponseSender response_sender) { 317 DCHECK(OnOriginThread()); 318 DCHECK(delegate_); 319 320 delegate_->Cancel(); 321 322 response_sender.Run(dbus::Response::FromMethodCall(method_call)); 323 } 324 325 // Called by dbus:: when a method is exported. 326 void OnExported(const std::string& interface_name, 327 const std::string& method_name, 328 bool success) { 329 LOG_IF(WARNING, !success) << "Failed to export " 330 << interface_name << "." << method_name; 331 } 332 333 // Called by the Delegate to response to a method requesting a PIN code. 334 void OnPinCode(dbus::MethodCall* method_call, 335 dbus::ExportedObject::ResponseSender response_sender, 336 Delegate::Status status, 337 const std::string& pincode) { 338 DCHECK(OnOriginThread()); 339 340 switch (status) { 341 case Delegate::SUCCESS: { 342 scoped_ptr<dbus::Response> response( 343 dbus::Response::FromMethodCall(method_call)); 344 dbus::MessageWriter writer(response.get()); 345 writer.AppendString(pincode); 346 response_sender.Run(response.Pass()); 347 break; 348 } 349 case Delegate::REJECTED: { 350 response_sender.Run( 351 dbus::ErrorResponse::FromMethodCall( 352 method_call, bluetooth_agent::kErrorRejected, "rejected") 353 .PassAs<dbus::Response>()); 354 break; 355 } 356 case Delegate::CANCELLED: { 357 response_sender.Run( 358 dbus::ErrorResponse::FromMethodCall( 359 method_call, bluetooth_agent::kErrorCanceled, "canceled") 360 .PassAs<dbus::Response>()); 361 break; 362 } 363 default: 364 NOTREACHED() << "Unexpected status code from delegate: " << status; 365 } 366 } 367 368 // Called by the Delegate to response to a method requesting a Passkey. 369 void OnPasskey(dbus::MethodCall* method_call, 370 dbus::ExportedObject::ResponseSender response_sender, 371 Delegate::Status status, 372 uint32 passkey) { 373 DCHECK(OnOriginThread()); 374 375 switch (status) { 376 case Delegate::SUCCESS: { 377 scoped_ptr<dbus::Response> response( 378 dbus::Response::FromMethodCall(method_call)); 379 dbus::MessageWriter writer(response.get()); 380 writer.AppendUint32(passkey); 381 response_sender.Run(response.Pass()); 382 break; 383 } 384 case Delegate::REJECTED: { 385 response_sender.Run( 386 dbus::ErrorResponse::FromMethodCall( 387 method_call, bluetooth_agent::kErrorRejected, "rejected") 388 .PassAs<dbus::Response>()); 389 break; 390 } 391 case Delegate::CANCELLED: { 392 response_sender.Run( 393 dbus::ErrorResponse::FromMethodCall( 394 method_call, bluetooth_agent::kErrorCanceled, "canceled") 395 .PassAs<dbus::Response>()); 396 break; 397 } 398 default: 399 NOTREACHED() << "Unexpected status code from delegate: " << status; 400 } 401 } 402 403 // Called by the Delegate in response to a method requiring confirmation. 404 void OnConfirmation(dbus::MethodCall* method_call, 405 dbus::ExportedObject::ResponseSender response_sender, 406 Delegate::Status status) { 407 DCHECK(OnOriginThread()); 408 409 switch (status) { 410 case Delegate::SUCCESS: { 411 response_sender.Run(dbus::Response::FromMethodCall(method_call)); 412 break; 413 } 414 case Delegate::REJECTED: { 415 response_sender.Run( 416 dbus::ErrorResponse::FromMethodCall( 417 method_call, bluetooth_agent::kErrorRejected, "rejected") 418 .PassAs<dbus::Response>()); 419 break; 420 } 421 case Delegate::CANCELLED: { 422 response_sender.Run( 423 dbus::ErrorResponse::FromMethodCall( 424 method_call, bluetooth_agent::kErrorCanceled, "canceled") 425 .PassAs<dbus::Response>()); 426 break; 427 } 428 default: 429 NOTREACHED() << "Unexpected status code from delegate: " << status; 430 } 431 } 432 433 // Origin thread (i.e. the UI thread in production). 434 base::PlatformThreadId origin_thread_id_; 435 436 // D-Bus bus object is exported on, not owned by this object and must 437 // outlive it. 438 dbus::Bus* bus_; 439 440 // All incoming method calls are passed on to the Delegate and a callback 441 // passed to generate the reply. |delegate_| is generally the object that 442 // owns this one, and must outlive it. 443 Delegate* delegate_; 444 445 // D-Bus object path of object we are exporting, kept so we can unregister 446 // again in our destructor. 447 dbus::ObjectPath object_path_; 448 449 // D-Bus object we are exporting, owned by this object. 450 scoped_refptr<dbus::ExportedObject> exported_object_; 451 452 // Weak pointer factory for generating 'this' pointers that might live longer 453 // than we do. 454 // Note: This should remain the last member so it'll be destroyed and 455 // invalidate its weak pointers before any other members are destroyed. 456 base::WeakPtrFactory<BluetoothAgentServiceProviderImpl> weak_ptr_factory_; 457 458 DISALLOW_COPY_AND_ASSIGN(BluetoothAgentServiceProviderImpl); 459 }; 460 461 BluetoothAgentServiceProvider::BluetoothAgentServiceProvider() { 462 } 463 464 BluetoothAgentServiceProvider::~BluetoothAgentServiceProvider() { 465 } 466 467 // static 468 BluetoothAgentServiceProvider* BluetoothAgentServiceProvider::Create( 469 dbus::Bus* bus, 470 const dbus::ObjectPath& object_path, 471 Delegate* delegate) { 472 if (base::SysInfo::IsRunningOnChromeOS()) { 473 return new BluetoothAgentServiceProviderImpl(bus, object_path, delegate); 474 } else { 475 return new FakeBluetoothAgentServiceProvider(object_path, delegate); 476 } 477 } 478 479 } // namespace chromeos 480