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.
5 #include "chromeos/dbus/bluetooth_profile_service_provider.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_profile_service_provider.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"
23 // The BluetoothProfileServiceProvider implementation used in production.
24 class BluetoothProfileServiceProviderImpl
25 : public BluetoothProfileServiceProvider
{
27 BluetoothProfileServiceProviderImpl(dbus::Bus
* bus
,
28 const dbus::ObjectPath
& object_path
,
30 : origin_thread_id_(base::PlatformThread::CurrentId()),
33 object_path_(object_path
),
34 weak_ptr_factory_(this) {
35 VLOG(1) << "Creating Bluetooth Profile: " << object_path_
.value();
37 exported_object_
= bus_
->GetExportedObject(object_path_
);
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()));
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()));
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()));
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()));
72 virtual ~BluetoothProfileServiceProviderImpl() {
73 VLOG(1) << "Cleaning up Bluetooth Profile: " << object_path_
.value();
75 // Unregister the object path so we can reuse with a new agent.
76 bus_
->UnregisterExportedObject(object_path_
);
80 // Returns true if the current thread is on the origin thread.
81 bool OnOriginThread() {
82 return base::PlatformThread::CurrentId() == origin_thread_id_
;
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());
92 delegate_
->Released();
94 response_sender
.Run(dbus::Response::FromMethodCall(method_call
));
97 // Called by dbus:: when the Bluetooth daemon establishes a new connection
99 void NewConnection(dbus::MethodCall
* method_call
,
100 dbus::ExportedObject::ResponseSender response_sender
) {
101 DCHECK(OnOriginThread());
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();
116 Delegate::Options options
;
117 while (array_reader
.HasMoreData()) {
118 dbus::MessageReader
dict_entry_reader(NULL
);
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();
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
);
132 Delegate::ConfirmationCallback callback
= base::Bind(
133 &BluetoothProfileServiceProviderImpl::OnConfirmation
,
134 weak_ptr_factory_
.GetWeakPtr(),
138 delegate_
->NewConnection(device_path
, fd
.Pass(), options
, callback
);
141 // Called by dbus:: when the Bluetooth daemon is about to disconnect the
143 void RequestDisconnection(
144 dbus::MethodCall
* method_call
,
145 dbus::ExportedObject::ResponseSender response_sender
) {
146 DCHECK(OnOriginThread());
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();
157 Delegate::ConfirmationCallback callback
= base::Bind(
158 &BluetoothProfileServiceProviderImpl::OnConfirmation
,
159 weak_ptr_factory_
.GetWeakPtr(),
163 delegate_
->RequestDisconnection(device_path
, callback
);
166 // Called by dbus:: when the request failed before a reply was returned
168 void Cancel(dbus::MethodCall
* method_call
,
169 dbus::ExportedObject::ResponseSender response_sender
) {
170 DCHECK(OnOriginThread());
175 response_sender
.Run(dbus::Response::FromMethodCall(method_call
));
178 // Called by dbus:: when a method is exported.
179 void OnExported(const std::string
& interface_name
,
180 const std::string
& method_name
,
182 LOG_IF(WARNING
, !success
) << "Failed to export "
183 << interface_name
<< "." << method_name
;
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());
193 case Delegate::SUCCESS
: {
194 response_sender
.Run(dbus::Response::FromMethodCall(method_call
));
197 case Delegate::REJECTED
: {
199 dbus::ErrorResponse::FromMethodCall(
200 method_call
, bluetooth_profile::kErrorRejected
, "rejected")
201 .PassAs
<dbus::Response
>());
204 case Delegate::CANCELLED
: {
206 dbus::ErrorResponse::FromMethodCall(
207 method_call
, bluetooth_profile::kErrorCanceled
, "canceled")
208 .PassAs
<dbus::Response
>());
212 NOTREACHED() << "Unexpected status code from delegate: " << status
;
216 // Origin thread (i.e. the UI thread in production).
217 base::PlatformThreadId origin_thread_id_
;
219 // D-Bus bus object is exported on, not owned by this object and must
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.
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_
;
232 // D-Bus object we are exporting, owned by this object.
233 scoped_refptr
<dbus::ExportedObject
> exported_object_
;
235 // Weak pointer factory for generating 'this' pointers that might live longer
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_
;
241 DISALLOW_COPY_AND_ASSIGN(BluetoothProfileServiceProviderImpl
);
244 BluetoothProfileServiceProvider::BluetoothProfileServiceProvider() {
247 BluetoothProfileServiceProvider::~BluetoothProfileServiceProvider() {
251 BluetoothProfileServiceProvider
* BluetoothProfileServiceProvider::Create(
253 const dbus::ObjectPath
& object_path
,
254 Delegate
* delegate
) {
255 if (base::SysInfo::IsRunningOnChromeOS()) {
256 return new BluetoothProfileServiceProviderImpl(bus
, object_path
, delegate
);
258 return new FakeBluetoothProfileServiceProvider(object_path
, delegate
);
262 } // namespace chromeos