1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/bluetooth/bluetooth_api.h"
9 #include "base/lazy_instance.h"
10 #include "base/memory/ref_counted.h"
11 #include "chrome/browser/extensions/api/bluetooth/bluetooth_api_utils.h"
12 #include "chrome/browser/extensions/api/bluetooth/bluetooth_event_router.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/common/extensions/api/bluetooth.h"
15 #include "chrome/common/extensions/api/bluetooth/bluetooth_manifest_data.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "device/bluetooth/bluetooth_adapter.h"
18 #include "device/bluetooth/bluetooth_device.h"
19 #include "device/bluetooth/bluetooth_out_of_band_pairing_data.h"
20 #include "device/bluetooth/bluetooth_profile.h"
21 #include "device/bluetooth/bluetooth_service_record.h"
22 #include "device/bluetooth/bluetooth_socket.h"
23 #include "extensions/browser/event_router.h"
24 #include "extensions/common/permissions/permissions_data.h"
25 #include "net/base/io_buffer.h"
27 using content::BrowserContext
;
28 using content::BrowserThread
;
30 using device::BluetoothAdapter
;
31 using device::BluetoothDevice
;
32 using device::BluetoothProfile
;
33 using device::BluetoothServiceRecord
;
34 using device::BluetoothSocket
;
36 using extensions::BluetoothApiSocket
;
38 namespace AddProfile
= extensions::api::bluetooth::AddProfile
;
39 namespace bluetooth
= extensions::api::bluetooth
;
40 namespace Connect
= extensions::api::bluetooth::Connect
;
41 namespace Disconnect
= extensions::api::bluetooth::Disconnect
;
42 namespace GetDevice
= extensions::api::bluetooth::GetDevice
;
43 namespace GetDevices
= extensions::api::bluetooth::GetDevices
;
44 namespace RemoveProfile
= extensions::api::bluetooth::RemoveProfile
;
45 namespace SetOutOfBandPairingData
=
46 extensions::api::bluetooth::SetOutOfBandPairingData
;
47 namespace Send
= extensions::api::bluetooth::Send
;
51 const char kCouldNotGetLocalOutOfBandPairingData
[] =
52 "Could not get local Out Of Band Pairing Data";
53 const char kCouldNotSetOutOfBandPairingData
[] =
54 "Could not set Out Of Band Pairing Data";
55 const char kInvalidDevice
[] = "Invalid device";
56 const char kInvalidUuid
[] = "Invalid UUID";
57 const char kPermissionDenied
[] = "Permission to add profile denied.";
58 const char kProfileAlreadyRegistered
[] =
59 "This profile has already been registered";
60 const char kProfileNotFound
[] = "Profile not found: invalid uuid";
61 const char kProfileRegistrationFailed
[] = "Profile registration failed";
62 const char kStartDiscoveryFailed
[] = "Starting discovery failed";
63 const char kStopDiscoveryFailed
[] = "Failed to stop discovery";
65 extensions::BluetoothEventRouter
* GetEventRouter(BrowserContext
* context
) {
66 // Note: |context| is valid on UI thread only.
67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
68 return extensions::BluetoothAPI::Get(context
)->event_router();
71 static void DispatchConnectionEventWorker(
72 void* browser_context_id
,
73 const std::string
& extension_id
,
74 const device::BluetoothUUID
& profile_uuid
,
75 const device::BluetoothDevice
* device
,
76 scoped_refptr
<device::BluetoothSocket
> socket
) {
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
79 content::BrowserContext
* context
=
80 reinterpret_cast<content::BrowserContext
*>(browser_context_id
);
81 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context
))
84 extensions::BluetoothAPI
* bluetooth_api
=
85 extensions::BluetoothAPI::Get(context
);
89 bluetooth_api
->DispatchConnectionEvent(
90 extension_id
, profile_uuid
, device
, socket
);
95 namespace extensions
{
97 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<BluetoothAPI
> >
98 g_factory
= LAZY_INSTANCE_INITIALIZER
;
101 BrowserContextKeyedAPIFactory
<BluetoothAPI
>*
102 BluetoothAPI::GetFactoryInstance() {
103 return g_factory
.Pointer();
107 BluetoothAPI
* BluetoothAPI::Get(BrowserContext
* context
) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
109 return GetFactoryInstance()->Get(context
);
112 BluetoothAPI::ConnectionParams::ConnectionParams() {}
114 BluetoothAPI::ConnectionParams::~ConnectionParams() {}
116 BluetoothAPI::BluetoothAPI(content::BrowserContext
* context
)
117 : browser_context_(context
) {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
119 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
120 event_router
->RegisterObserver(this,
121 bluetooth::OnAdapterStateChanged::kEventName
);
122 event_router
->RegisterObserver(this, bluetooth::OnDeviceAdded::kEventName
);
123 event_router
->RegisterObserver(this, bluetooth::OnDeviceChanged::kEventName
);
124 event_router
->RegisterObserver(this, bluetooth::OnDeviceRemoved::kEventName
);
127 BluetoothAPI::~BluetoothAPI() {}
129 BluetoothEventRouter
* BluetoothAPI::event_router() {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
131 if (!event_router_
) {
132 event_router_
.reset(new BluetoothEventRouter(browser_context_
));
134 return event_router_
.get();
137 scoped_refptr
<BluetoothAPI::SocketData
> BluetoothAPI::socket_data() {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
140 ApiResourceManager
<BluetoothApiSocket
>* socket_manager
=
141 ApiResourceManager
<BluetoothApiSocket
>::Get(browser_context_
);
142 DCHECK(socket_manager
)
143 << "There is no socket manager. "
144 "If this assertion is failing during a test, then it is likely that "
145 "TestExtensionSystem is failing to provide an instance of "
146 "ApiResourceManager<BluetoothApiSocket>.";
148 socket_data_
= socket_manager
->data_
;
153 void BluetoothAPI::Shutdown() {
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
155 EventRouter::Get(browser_context_
)->UnregisterObserver(this);
158 void BluetoothAPI::OnListenerAdded(const EventListenerInfo
& details
) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
160 if (event_router()->IsBluetoothSupported())
161 event_router()->OnListenerAdded();
164 void BluetoothAPI::OnListenerRemoved(const EventListenerInfo
& details
) {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
166 if (event_router()->IsBluetoothSupported())
167 event_router()->OnListenerRemoved();
170 void BluetoothAPI::DispatchConnectionEvent(
171 const std::string
& extension_id
,
172 const device::BluetoothUUID
& uuid
,
173 const device::BluetoothDevice
* device
,
174 scoped_refptr
<device::BluetoothSocket
> socket
) {
175 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
177 if (!event_router()->HasProfile(uuid
))
180 extensions::BluetoothAPI::ConnectionParams params
;
181 params
.browser_context_id
= browser_context_
;
182 params
.thread_id
= BluetoothApiSocket::kThreadId
;
183 params
.extension_id
= extension_id
;
185 params
.device_address
= device
->GetAddress();
186 params
.socket
= socket
;
187 params
.socket_data
= socket_data();
188 BrowserThread::PostTask(
189 params
.thread_id
, FROM_HERE
, base::Bind(&RegisterSocket
, params
));
193 void BluetoothAPI::RegisterSocket(
194 const BluetoothAPI::ConnectionParams
& params
) {
195 DCHECK(BrowserThread::CurrentlyOn(params
.thread_id
));
197 BluetoothApiSocket
* api_socket
= new BluetoothApiSocket(
198 params
.extension_id
, params
.socket
, params
.device_address
, params
.uuid
);
199 int socket_id
= params
.socket_data
->Add(api_socket
);
201 BrowserThread::PostTask(BrowserThread::UI
,
203 base::Bind(&RegisterSocketUI
, params
, socket_id
));
207 void BluetoothAPI::RegisterSocketUI(const ConnectionParams
& params
,
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
211 content::BrowserContext
* context
=
212 reinterpret_cast<content::BrowserContext
*>(params
.browser_context_id
);
213 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context
))
216 BluetoothAPI::Get(context
)->event_router()->GetAdapter(
217 base::Bind(&RegisterSocketWithAdapterUI
, params
, socket_id
));
220 void BluetoothAPI::RegisterSocketWithAdapterUI(
221 const ConnectionParams
& params
,
223 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
226 content::BrowserContext
* context
=
227 reinterpret_cast<content::BrowserContext
*>(params
.browser_context_id
);
228 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(context
))
231 BluetoothDevice
* device
= adapter
->GetDevice(params
.device_address
);
235 api::bluetooth::Socket result_socket
;
236 bluetooth::BluetoothDeviceToApiDevice(*device
, &result_socket
.device
);
237 result_socket
.uuid
= params
.uuid
.canonical_value();
238 result_socket
.id
= socket_id
;
240 scoped_ptr
<base::ListValue
> args
=
241 bluetooth::OnConnection::Create(result_socket
);
242 scoped_ptr
<Event
> event(
243 new Event(bluetooth::OnConnection::kEventName
, args
.Pass()));
245 EventRouter
* router
= EventRouter::Get(context
);
247 router
->DispatchEventToExtension(params
.extension_id
, event
.Pass());
252 BluetoothGetAdapterStateFunction::~BluetoothGetAdapterStateFunction() {}
254 bool BluetoothGetAdapterStateFunction::DoWork(
255 scoped_refptr
<BluetoothAdapter
> adapter
) {
256 bluetooth::AdapterState state
;
257 PopulateAdapterState(*adapter
.get(), &state
);
258 results_
= bluetooth::GetAdapterState::Results::Create(state
);
263 BluetoothGetDevicesFunction::~BluetoothGetDevicesFunction() {}
265 bool BluetoothGetDevicesFunction::DoWork(
266 scoped_refptr
<BluetoothAdapter
> adapter
) {
267 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
269 base::ListValue
* device_list
= new base::ListValue
;
270 SetResult(device_list
);
272 BluetoothAdapter::DeviceList devices
= adapter
->GetDevices();
273 for (BluetoothAdapter::DeviceList::const_iterator iter
= devices
.begin();
274 iter
!= devices
.end();
276 const BluetoothDevice
* device
= *iter
;
279 bluetooth::Device extension_device
;
280 bluetooth::BluetoothDeviceToApiDevice(*device
, &extension_device
);
282 device_list
->Append(extension_device
.ToValue().release());
290 BluetoothGetDeviceFunction::~BluetoothGetDeviceFunction() {}
292 bool BluetoothGetDeviceFunction::DoWork(
293 scoped_refptr
<BluetoothAdapter
> adapter
) {
294 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
296 scoped_ptr
<GetDevice::Params
> params(GetDevice::Params::Create(*args_
));
297 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
298 const std::string
& device_address
= params
->device_address
;
300 BluetoothDevice
* device
= adapter
->GetDevice(device_address
);
302 bluetooth::Device extension_device
;
303 bluetooth::BluetoothDeviceToApiDevice(*device
, &extension_device
);
304 SetResult(extension_device
.ToValue().release());
307 SetError(kInvalidDevice
);
314 BluetoothAddProfileFunction::BluetoothAddProfileFunction() {}
316 BluetoothAddProfileFunction::~BluetoothAddProfileFunction() {}
318 bool BluetoothAddProfileFunction::RunImpl() {
319 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
320 scoped_ptr
<AddProfile::Params
> params(AddProfile::Params::Create(*args_
));
321 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
323 device::BluetoothUUID
uuid(params
->profile
.uuid
);
325 if (!uuid
.IsValid()) {
326 SetError(kInvalidUuid
);
330 BluetoothPermissionRequest
param(params
->profile
.uuid
);
331 if (!BluetoothManifestData::CheckRequest(GetExtension(), param
)) {
332 error_
= kPermissionDenied
;
338 if (GetEventRouter(browser_context())->HasProfile(uuid_
)) {
339 SetError(kProfileAlreadyRegistered
);
343 BluetoothProfile::Options options
;
344 if (params
->profile
.name
.get())
345 options
.name
= *params
->profile
.name
.get();
346 if (params
->profile
.channel
.get())
347 options
.channel
= *params
->profile
.channel
.get();
348 if (params
->profile
.psm
.get())
349 options
.psm
= *params
->profile
.psm
.get();
350 if (params
->profile
.require_authentication
.get()) {
351 options
.require_authentication
=
352 *params
->profile
.require_authentication
.get();
354 if (params
->profile
.require_authorization
.get()) {
355 options
.require_authorization
=
356 *params
->profile
.require_authorization
.get();
358 if (params
->profile
.auto_connect
.get())
359 options
.auto_connect
= *params
->profile
.auto_connect
.get();
360 if (params
->profile
.version
.get())
361 options
.version
= *params
->profile
.version
.get();
362 if (params
->profile
.features
.get())
363 options
.features
= *params
->profile
.features
.get();
367 base::Bind(&BluetoothAddProfileFunction::OnProfileRegistered
, this));
372 void BluetoothAddProfileFunction::RegisterProfile(
373 const BluetoothProfile::Options
& options
,
374 const BluetoothProfile::ProfileCallback
& callback
) {
375 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
376 BluetoothProfile::Register(uuid_
, options
, callback
);
379 void BluetoothAddProfileFunction::OnProfileRegistered(
380 BluetoothProfile
* bluetooth_profile
) {
381 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
382 if (!bluetooth_profile
) {
383 SetError(kProfileRegistrationFailed
);
388 if (GetEventRouter(browser_context())->HasProfile(uuid_
)) {
389 bluetooth_profile
->Unregister();
390 SetError(kProfileAlreadyRegistered
);
395 bluetooth_profile
->SetConnectionCallback(
396 base::Bind(&DispatchConnectionEventWorker
,
400 GetEventRouter(browser_context())
401 ->AddProfile(uuid_
, extension_id(), bluetooth_profile
);
405 BluetoothRemoveProfileFunction::~BluetoothRemoveProfileFunction() {}
407 bool BluetoothRemoveProfileFunction::RunSync() {
408 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
409 scoped_ptr
<RemoveProfile::Params
> params(
410 RemoveProfile::Params::Create(*args_
));
412 device::BluetoothUUID
uuid(params
->profile
.uuid
);
414 if (!uuid
.IsValid()) {
415 SetError(kInvalidUuid
);
419 if (!GetEventRouter(browser_context())->HasProfile(uuid
)) {
420 SetError(kProfileNotFound
);
424 GetEventRouter(browser_context())->RemoveProfile(uuid
);
428 BluetoothConnectFunction::~BluetoothConnectFunction() {}
430 bool BluetoothConnectFunction::DoWork(scoped_refptr
<BluetoothAdapter
> adapter
) {
431 scoped_ptr
<Connect::Params
> params(Connect::Params::Create(*args_
));
432 EXTENSION_FUNCTION_VALIDATE(params
.get() != NULL
);
433 const bluetooth::ConnectOptions
& options
= params
->options
;
435 device::BluetoothUUID
uuid(options
.profile
.uuid
);
437 if (!uuid
.IsValid()) {
438 SetError(kInvalidUuid
);
443 BluetoothDevice
* device
= adapter
->GetDevice(options
.device
.address
);
445 SetError(kInvalidDevice
);
450 BluetoothProfile
* bluetooth_profile
=
451 GetEventRouter(browser_context())->GetProfile(uuid
);
452 if (!bluetooth_profile
) {
453 SetError(kProfileNotFound
);
458 device
->ConnectToProfile(
460 base::Bind(&BluetoothConnectFunction::OnSuccessCallback
, this),
461 base::Bind(&BluetoothConnectFunction::OnErrorCallback
, this));
466 void BluetoothConnectFunction::OnSuccessCallback() {
467 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
471 void BluetoothConnectFunction::OnErrorCallback(const std::string
& error
) {
472 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
477 bool BluetoothDisconnectFunction::RunImpl() {
478 // TODO(keybuk): Remove.
479 SetError("Removed. Use chrome.bluetoothSocket.disconnect() instead.");
483 bool BluetoothSendFunction::RunImpl() {
484 // TODO(keybuk): Remove.
485 SetError("Removed. Use chrome.bluetoothSocket.send() instead.");
489 bool BluetoothUpdateSocketFunction::RunImpl() {
490 // TODO(keybuk): Remove.
491 SetError("Removed. Use chrome.bluetoothSocket.update() instead.");
495 bool BluetoothSetSocketPausedFunction::RunImpl() {
496 // TODO(keybuk): Remove.
497 SetError("Removed. Use chrome.bluetoothSocket.setPaused() instead.");
501 bool BluetoothGetSocketFunction::RunImpl() {
502 // TODO(keybuk): Remove.
503 SetError("Removed. Use chrome.bluetoothSocket.getInfo() instead.");
507 bool BluetoothGetSocketsFunction::RunImpl() {
508 // TODO(keybuk): Remove.
509 SetError("Removed. Use chrome.bluetoothSocket.getSockets() instead.");
513 void BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback() {
517 void BluetoothSetOutOfBandPairingDataFunction::OnErrorCallback() {
518 SetError(kCouldNotSetOutOfBandPairingData
);
522 bool BluetoothSetOutOfBandPairingDataFunction::DoWork(
523 scoped_refptr
<BluetoothAdapter
> adapter
) {
524 // TODO(bryeung): update to new-style parameter passing when ArrayBuffer
526 base::DictionaryValue
* options
;
527 EXTENSION_FUNCTION_VALIDATE(args_
->GetDictionary(0, &options
));
529 EXTENSION_FUNCTION_VALIDATE(options
->GetString("deviceAddress", &address
));
531 BluetoothDevice
* device
= adapter
->GetDevice(address
);
533 SetError(kInvalidDevice
);
538 if (options
->HasKey("data")) {
539 base::DictionaryValue
* data_in
;
540 EXTENSION_FUNCTION_VALIDATE(options
->GetDictionary("data", &data_in
));
542 device::BluetoothOutOfBandPairingData data_out
;
544 base::BinaryValue
* tmp_data
;
545 EXTENSION_FUNCTION_VALIDATE(data_in
->GetBinary("hash", &tmp_data
));
546 EXTENSION_FUNCTION_VALIDATE(
547 tmp_data
->GetSize() == device::kBluetoothOutOfBandPairingDataSize
);
548 memcpy(data_out
.hash
,
549 reinterpret_cast<uint8_t*>(tmp_data
->GetBuffer()),
550 device::kBluetoothOutOfBandPairingDataSize
);
552 EXTENSION_FUNCTION_VALIDATE(data_in
->GetBinary("randomizer", &tmp_data
));
553 EXTENSION_FUNCTION_VALIDATE(
554 tmp_data
->GetSize() == device::kBluetoothOutOfBandPairingDataSize
);
555 memcpy(data_out
.randomizer
,
556 reinterpret_cast<uint8_t*>(tmp_data
->GetBuffer()),
557 device::kBluetoothOutOfBandPairingDataSize
);
559 device
->SetOutOfBandPairingData(
561 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback
,
563 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnErrorCallback
,
566 device
->ClearOutOfBandPairingData(
567 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnSuccessCallback
,
569 base::Bind(&BluetoothSetOutOfBandPairingDataFunction::OnErrorCallback
,
576 void BluetoothGetLocalOutOfBandPairingDataFunction::ReadCallback(
577 const device::BluetoothOutOfBandPairingData
& data
) {
578 base::BinaryValue
* hash
= base::BinaryValue::CreateWithCopiedBuffer(
579 reinterpret_cast<const char*>(data
.hash
),
580 device::kBluetoothOutOfBandPairingDataSize
);
581 base::BinaryValue
* randomizer
= base::BinaryValue::CreateWithCopiedBuffer(
582 reinterpret_cast<const char*>(data
.randomizer
),
583 device::kBluetoothOutOfBandPairingDataSize
);
585 // TODO(bryeung): convert to bluetooth::OutOfBandPairingData
586 // when ArrayBuffer support within objects is completed.
587 base::DictionaryValue
* result
= new base::DictionaryValue();
588 result
->Set("hash", hash
);
589 result
->Set("randomizer", randomizer
);
596 void BluetoothGetLocalOutOfBandPairingDataFunction::ErrorCallback() {
597 SetError(kCouldNotGetLocalOutOfBandPairingData
);
601 bool BluetoothGetLocalOutOfBandPairingDataFunction::DoWork(
602 scoped_refptr
<BluetoothAdapter
> adapter
) {
603 adapter
->ReadLocalOutOfBandPairingData(
604 base::Bind(&BluetoothGetLocalOutOfBandPairingDataFunction::ReadCallback
,
606 base::Bind(&BluetoothGetLocalOutOfBandPairingDataFunction::ErrorCallback
,
612 void BluetoothStartDiscoveryFunction::OnSuccessCallback() {
616 void BluetoothStartDiscoveryFunction::OnErrorCallback() {
617 SetError(kStartDiscoveryFailed
);
621 bool BluetoothStartDiscoveryFunction::DoWork(
622 scoped_refptr
<BluetoothAdapter
> adapter
) {
623 GetEventRouter(browser_context())->StartDiscoverySession(
626 base::Bind(&BluetoothStartDiscoveryFunction::OnSuccessCallback
, this),
627 base::Bind(&BluetoothStartDiscoveryFunction::OnErrorCallback
, this));
632 void BluetoothStopDiscoveryFunction::OnSuccessCallback() {
636 void BluetoothStopDiscoveryFunction::OnErrorCallback() {
637 SetError(kStopDiscoveryFailed
);
641 bool BluetoothStopDiscoveryFunction::DoWork(
642 scoped_refptr
<BluetoothAdapter
> adapter
) {
643 GetEventRouter(browser_context())->StopDiscoverySession(
646 base::Bind(&BluetoothStopDiscoveryFunction::OnSuccessCallback
, this),
647 base::Bind(&BluetoothStopDiscoveryFunction::OnErrorCallback
, this));
653 } // namespace extensions