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"
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"
20 // The BluetoothProfileServiceProvider implementation used in production.
21 class BluetoothProfileServiceProviderImpl
22 : public BluetoothProfileServiceProvider
{
24 BluetoothProfileServiceProviderImpl(dbus::Bus
* bus
,
25 const dbus::ObjectPath
& object_path
,
27 : origin_thread_id_(base::PlatformThread::CurrentId()),
30 object_path_(object_path
),
31 weak_ptr_factory_(this) {
32 VLOG(1) << "Creating Bluetooth Profile: " << object_path_
.value();
34 exported_object_
= bus_
->GetExportedObject(object_path_
);
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()));
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()));
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()));
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()));
69 ~BluetoothProfileServiceProviderImpl() override
{
70 VLOG(1) << "Cleaning up Bluetooth Profile: " << object_path_
.value();
72 // Unregister the object path so we can reuse with a new agent.
73 bus_
->UnregisterExportedObject(object_path_
);
77 // Returns true if the current thread is on the origin thread.
78 bool OnOriginThread() {
79 return base::PlatformThread::CurrentId() == origin_thread_id_
;
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());
89 delegate_
->Released();
91 response_sender
.Run(dbus::Response::FromMethodCall(method_call
));
94 // Called by dbus:: when the Bluetooth daemon establishes a new connection
96 void NewConnection(dbus::MethodCall
* method_call
,
97 dbus::ExportedObject::ResponseSender response_sender
) {
98 DCHECK(OnOriginThread());
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();
113 Delegate::Options options
;
114 while (array_reader
.HasMoreData()) {
115 dbus::MessageReader
dict_entry_reader(NULL
);
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();
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
);
129 Delegate::ConfirmationCallback callback
= base::Bind(
130 &BluetoothProfileServiceProviderImpl::OnConfirmation
,
131 weak_ptr_factory_
.GetWeakPtr(),
135 delegate_
->NewConnection(device_path
, fd
.Pass(), options
, callback
);
138 // Called by dbus:: when the Bluetooth daemon is about to disconnect the
140 void RequestDisconnection(
141 dbus::MethodCall
* method_call
,
142 dbus::ExportedObject::ResponseSender response_sender
) {
143 DCHECK(OnOriginThread());
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();
154 Delegate::ConfirmationCallback callback
= base::Bind(
155 &BluetoothProfileServiceProviderImpl::OnConfirmation
,
156 weak_ptr_factory_
.GetWeakPtr(),
160 delegate_
->RequestDisconnection(device_path
, callback
);
163 // Called by dbus:: when the request failed before a reply was returned
165 void Cancel(dbus::MethodCall
* method_call
,
166 dbus::ExportedObject::ResponseSender response_sender
) {
167 DCHECK(OnOriginThread());
172 response_sender
.Run(dbus::Response::FromMethodCall(method_call
));
175 // Called by dbus:: when a method is exported.
176 void OnExported(const std::string
& interface_name
,
177 const std::string
& method_name
,
179 LOG_IF(WARNING
, !success
) << "Failed to export "
180 << interface_name
<< "." << method_name
;
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());
190 case Delegate::SUCCESS
: {
191 response_sender
.Run(dbus::Response::FromMethodCall(method_call
));
194 case Delegate::REJECTED
: {
195 response_sender
.Run(dbus::ErrorResponse::FromMethodCall(
196 method_call
, bluetooth_profile::kErrorRejected
, "rejected"));
199 case Delegate::CANCELLED
: {
200 response_sender
.Run(dbus::ErrorResponse::FromMethodCall(
201 method_call
, bluetooth_profile::kErrorCanceled
, "canceled"));
205 NOTREACHED() << "Unexpected status code from delegate: " << status
;
209 // Origin thread (i.e. the UI thread in production).
210 base::PlatformThreadId origin_thread_id_
;
212 // D-Bus bus object is exported on, not owned by this object and must
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.
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_
;
225 // D-Bus object we are exporting, owned by this object.
226 scoped_refptr
<dbus::ExportedObject
> exported_object_
;
228 // Weak pointer factory for generating 'this' pointers that might live longer
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_
;
234 DISALLOW_COPY_AND_ASSIGN(BluetoothProfileServiceProviderImpl
);
237 BluetoothProfileServiceProvider::BluetoothProfileServiceProvider() {
240 BluetoothProfileServiceProvider::~BluetoothProfileServiceProvider() {
244 BluetoothProfileServiceProvider
* BluetoothProfileServiceProvider::Create(
246 const dbus::ObjectPath
& object_path
,
247 Delegate
* delegate
) {
248 if (!DBusThreadManager::Get()->IsUsingStub(DBusClientBundle::BLUETOOTH
)) {
249 return new BluetoothProfileServiceProviderImpl(bus
, object_path
, delegate
);
251 return new FakeBluetoothProfileServiceProvider(object_path
, delegate
);
255 } // namespace chromeos