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