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_profile_service_provider.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/chromeos/chromeos_version.h" 11 #include "base/logging.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/threading/platform_thread.h" 14 #include "chromeos/dbus/fake_bluetooth_profile_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 BluetoothProfileServiceProvider implementation used in production. 24 class BluetoothProfileServiceProviderImpl 25 : public BluetoothProfileServiceProvider { 26 public: 27 BluetoothProfileServiceProviderImpl(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 Profile: " << object_path_.value(); 36 37 exported_object_ = bus_->GetExportedObject(object_path_); 38 39 exported_object_->ExportMethod( 40 bluetooth_profile::kBluetoothProfileInterface, 41 bluetooth_profile::kRelease, 42 base::Bind(&BluetoothProfileServiceProviderImpl::Release, 43 weak_ptr_factory_.GetWeakPtr()), 44 base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, 45 weak_ptr_factory_.GetWeakPtr())); 46 47 exported_object_->ExportMethod( 48 bluetooth_profile::kBluetoothProfileInterface, 49 bluetooth_profile::kNewConnection, 50 base::Bind(&BluetoothProfileServiceProviderImpl::NewConnection, 51 weak_ptr_factory_.GetWeakPtr()), 52 base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, 53 weak_ptr_factory_.GetWeakPtr())); 54 55 exported_object_->ExportMethod( 56 bluetooth_profile::kBluetoothProfileInterface, 57 bluetooth_profile::kRequestDisconnection, 58 base::Bind(&BluetoothProfileServiceProviderImpl::RequestDisconnection, 59 weak_ptr_factory_.GetWeakPtr()), 60 base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, 61 weak_ptr_factory_.GetWeakPtr())); 62 63 exported_object_->ExportMethod( 64 bluetooth_profile::kBluetoothProfileInterface, 65 bluetooth_profile::kCancel, 66 base::Bind(&BluetoothProfileServiceProviderImpl::Cancel, 67 weak_ptr_factory_.GetWeakPtr()), 68 base::Bind(&BluetoothProfileServiceProviderImpl::OnExported, 69 weak_ptr_factory_.GetWeakPtr())); 70 } 71 72 virtual ~BluetoothProfileServiceProviderImpl() { 73 VLOG(1) << "Cleaning up Bluetooth Profile: " << object_path_.value(); 74 75 // Unregister the object path so we can reuse with a new agent. 76 bus_->UnregisterExportedObject(object_path_); 77 } 78 79 private: 80 // Returns true if the current thread is on the origin thread. 81 bool OnOriginThread() { 82 return base::PlatformThread::CurrentId() == origin_thread_id_; 83 } 84 85 // Called by dbus:: when the profile is unregistered from the Bluetooth 86 // daemon, generally by our request. 87 void Release(dbus::MethodCall* method_call, 88 dbus::ExportedObject::ResponseSender response_sender) { 89 DCHECK(OnOriginThread()); 90 DCHECK(delegate_); 91 92 delegate_->Release(); 93 94 response_sender.Run(dbus::Response::FromMethodCall(method_call)); 95 } 96 97 // Called by dbus:: when the Bluetooth daemon establishes a new connection 98 // to the profile. 99 void NewConnection(dbus::MethodCall* method_call, 100 dbus::ExportedObject::ResponseSender response_sender) { 101 DCHECK(OnOriginThread()); 102 DCHECK(delegate_); 103 104 dbus::MessageReader reader(method_call); 105 dbus::ObjectPath device_path; 106 scoped_ptr<dbus::FileDescriptor> fd(new dbus::FileDescriptor()); 107 dbus::MessageReader array_reader(NULL); 108 if (!reader.PopObjectPath(&device_path) || 109 !reader.PopFileDescriptor(fd.get()) || 110 !reader.PopArray(&array_reader)) { 111 LOG(WARNING) << "NewConnection called with incorrect paramters: " 112 << method_call->ToString(); 113 return; 114 } 115 116 Delegate::Options options; 117 while (array_reader.HasMoreData()) { 118 dbus::MessageReader dict_entry_reader(NULL); 119 std::string key; 120 if (!array_reader.PopDictEntry(&dict_entry_reader) || 121 !dict_entry_reader.PopString(&key)) { 122 LOG(WARNING) << "NewConnection called with incorrect paramters: " 123 << method_call->ToString(); 124 } else { 125 if (key == bluetooth_profile::kVersionProperty) 126 dict_entry_reader.PopVariantOfUint16(&options.version); 127 else if (key == bluetooth_profile::kFeaturesProperty) 128 dict_entry_reader.PopVariantOfUint16(&options.features); 129 } 130 } 131 132 Delegate::ConfirmationCallback callback = base::Bind( 133 &BluetoothProfileServiceProviderImpl::OnConfirmation, 134 weak_ptr_factory_.GetWeakPtr(), 135 method_call, 136 response_sender); 137 138 delegate_->NewConnection(device_path, fd.Pass(), options, callback); 139 } 140 141 // Called by dbus:: when the Bluetooth daemon is about to disconnect the 142 // profile. 143 void RequestDisconnection( 144 dbus::MethodCall* method_call, 145 dbus::ExportedObject::ResponseSender response_sender) { 146 DCHECK(OnOriginThread()); 147 DCHECK(delegate_); 148 149 dbus::MessageReader reader(method_call); 150 dbus::ObjectPath device_path; 151 if (!reader.PopObjectPath(&device_path)) { 152 LOG(WARNING) << "RequestDisconnection called with incorrect paramters: " 153 << method_call->ToString(); 154 return; 155 } 156 157 Delegate::ConfirmationCallback callback = base::Bind( 158 &BluetoothProfileServiceProviderImpl::OnConfirmation, 159 weak_ptr_factory_.GetWeakPtr(), 160 method_call, 161 response_sender); 162 163 delegate_->RequestDisconnection(device_path, callback); 164 } 165 166 // Called by dbus:: when the request failed before a reply was returned 167 // from the device. 168 void Cancel(dbus::MethodCall* method_call, 169 dbus::ExportedObject::ResponseSender response_sender) { 170 DCHECK(OnOriginThread()); 171 DCHECK(delegate_); 172 173 delegate_->Cancel(); 174 175 response_sender.Run(dbus::Response::FromMethodCall(method_call)); 176 } 177 178 // Called by dbus:: when a method is exported. 179 void OnExported(const std::string& interface_name, 180 const std::string& method_name, 181 bool success) { 182 LOG_IF(WARNING, !success) << "Failed to export " 183 << interface_name << "." << method_name; 184 } 185 186 // Called by the Delegate in response to a method requiring confirmation. 187 void OnConfirmation(dbus::MethodCall* method_call, 188 dbus::ExportedObject::ResponseSender response_sender, 189 Delegate::Status status) { 190 DCHECK(OnOriginThread()); 191 192 switch (status) { 193 case Delegate::SUCCESS: { 194 response_sender.Run(dbus::Response::FromMethodCall(method_call)); 195 break; 196 } 197 case Delegate::REJECTED: { 198 response_sender.Run( 199 dbus::ErrorResponse::FromMethodCall( 200 method_call, bluetooth_profile::kErrorRejected, "rejected") 201 .PassAs<dbus::Response>()); 202 break; 203 } 204 case Delegate::CANCELLED: { 205 response_sender.Run( 206 dbus::ErrorResponse::FromMethodCall( 207 method_call, bluetooth_profile::kErrorCanceled, "canceled") 208 .PassAs<dbus::Response>()); 209 break; 210 } 211 default: 212 NOTREACHED() << "Unexpected status code from delegate: " << status; 213 } 214 } 215 216 // Origin thread (i.e. the UI thread in production). 217 base::PlatformThreadId origin_thread_id_; 218 219 // D-Bus bus object is exported on, not owned by this object and must 220 // outlive it. 221 dbus::Bus* bus_; 222 223 // All incoming method calls are passed on to the Delegate and a callback 224 // passed to generate the reply. |delegate_| is generally the object that 225 // owns this one, and must outlive it. 226 Delegate* delegate_; 227 228 // D-Bus object path of object we are exporting, kept so we can unregister 229 // again in our destructor. 230 dbus::ObjectPath object_path_; 231 232 // D-Bus object we are exporting, owned by this object. 233 scoped_refptr<dbus::ExportedObject> exported_object_; 234 235 // Weak pointer factory for generating 'this' pointers that might live longer 236 // than we do. 237 // Note: This should remain the last member so it'll be destroyed and 238 // invalidate its weak pointers before any other members are destroyed. 239 base::WeakPtrFactory<BluetoothProfileServiceProviderImpl> weak_ptr_factory_; 240 241 DISALLOW_COPY_AND_ASSIGN(BluetoothProfileServiceProviderImpl); 242 }; 243 244 BluetoothProfileServiceProvider::BluetoothProfileServiceProvider() { 245 } 246 247 BluetoothProfileServiceProvider::~BluetoothProfileServiceProvider() { 248 } 249 250 // static 251 BluetoothProfileServiceProvider* BluetoothProfileServiceProvider::Create( 252 dbus::Bus* bus, 253 const dbus::ObjectPath& object_path, 254 Delegate* delegate) { 255 if (base::chromeos::IsRunningOnChromeOS()) { 256 return new BluetoothProfileServiceProviderImpl(bus, object_path, delegate); 257 } else { 258 return new FakeBluetoothProfileServiceProvider(object_path, delegate); 259 } 260 } 261 262 } // namespace chromeos 263