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