1 // Copyright 2014 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 "content/renderer/bluetooth/bluetooth_dispatcher.h"
7 #include "base/lazy_instance.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "content/child/thread_safe_sender.h"
12 #include "content/common/bluetooth/bluetooth_messages.h"
13 #include "device/bluetooth/bluetooth_uuid.h"
14 #include "third_party/WebKit/public/platform/WebPassOwnPtr.h"
15 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h"
16 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h"
17 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTCharacteristic.h"
18 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h"
19 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTService.h"
20 #include "third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h"
22 using blink::WebBluetoothConnectGATTCallbacks
;
23 using blink::WebBluetoothDevice
;
24 using blink::WebBluetoothError
;
25 using blink::WebBluetoothGATTCharacteristic
;
26 using blink::WebBluetoothGATTRemoteServer
;
27 using blink::WebBluetoothGATTService
;
28 using blink::WebBluetoothReadValueCallbacks
;
29 using blink::WebBluetoothRequestDeviceCallbacks
;
30 using blink::WebBluetoothScanFilter
;
31 using blink::WebRequestDeviceOptions
;
32 using blink::WebString
;
33 using blink::WebVector
;
35 struct BluetoothPrimaryServiceRequest
{
36 BluetoothPrimaryServiceRequest(
37 blink::WebString device_instance_id
,
38 blink::WebString service_uuid
,
39 blink::WebBluetoothGetPrimaryServiceCallbacks
* callbacks
)
40 : device_instance_id(device_instance_id
),
41 service_uuid(service_uuid
),
42 callbacks(callbacks
) {}
43 ~BluetoothPrimaryServiceRequest() {}
45 blink::WebString device_instance_id
;
46 blink::WebString service_uuid
;
47 scoped_ptr
<blink::WebBluetoothGetPrimaryServiceCallbacks
> callbacks
;
50 struct BluetoothCharacteristicRequest
{
51 BluetoothCharacteristicRequest(
52 blink::WebString service_instance_id
,
53 blink::WebString characteristic_uuid
,
54 blink::WebBluetoothGetCharacteristicCallbacks
* callbacks
)
55 : service_instance_id(service_instance_id
),
56 characteristic_uuid(characteristic_uuid
),
57 callbacks(callbacks
) {}
58 ~BluetoothCharacteristicRequest() {}
60 blink::WebString service_instance_id
;
61 blink::WebString characteristic_uuid
;
62 scoped_ptr
<blink::WebBluetoothGetCharacteristicCallbacks
> callbacks
;
69 base::LazyInstance
<base::ThreadLocalPointer
<void>>::Leaky g_dispatcher_tls
=
70 LAZY_INSTANCE_INITIALIZER
;
72 void* const kHasBeenDeleted
= reinterpret_cast<void*>(0x1);
74 int CurrentWorkerId() {
75 return WorkerThread::GetCurrentId();
78 WebBluetoothDevice::VendorIDSource
GetWebVendorIdSource(
79 device::BluetoothDevice::VendorIDSource vendor_id_source
) {
80 switch (vendor_id_source
) {
81 case device::BluetoothDevice::VENDOR_ID_UNKNOWN
:
82 return WebBluetoothDevice::VendorIDSource::Unknown
;
83 case device::BluetoothDevice::VENDOR_ID_BLUETOOTH
:
84 return WebBluetoothDevice::VendorIDSource::Bluetooth
;
85 case device::BluetoothDevice::VENDOR_ID_USB
:
86 return WebBluetoothDevice::VendorIDSource::USB
;
89 return WebBluetoothDevice::VendorIDSource::Unknown
;
94 BluetoothDispatcher::BluetoothDispatcher(ThreadSafeSender
* sender
)
95 : thread_safe_sender_(sender
) {
96 g_dispatcher_tls
.Pointer()->Set(static_cast<void*>(this));
99 BluetoothDispatcher::~BluetoothDispatcher() {
100 g_dispatcher_tls
.Pointer()->Set(kHasBeenDeleted
);
103 BluetoothDispatcher
* BluetoothDispatcher::GetOrCreateThreadSpecificInstance(
104 ThreadSafeSender
* thread_safe_sender
) {
105 if (g_dispatcher_tls
.Pointer()->Get() == kHasBeenDeleted
) {
106 NOTREACHED() << "Re-instantiating TLS BluetoothDispatcher.";
107 g_dispatcher_tls
.Pointer()->Set(NULL
);
109 if (g_dispatcher_tls
.Pointer()->Get())
110 return static_cast<BluetoothDispatcher
*>(g_dispatcher_tls
.Pointer()->Get());
112 BluetoothDispatcher
* dispatcher
= new BluetoothDispatcher(thread_safe_sender
);
113 if (CurrentWorkerId())
114 WorkerThread::AddObserver(dispatcher
);
118 bool BluetoothDispatcher::Send(IPC::Message
* msg
) {
119 return thread_safe_sender_
->Send(msg
);
122 void BluetoothDispatcher::OnMessageReceived(const IPC::Message
& msg
) {
124 IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcher
, msg
)
125 IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceSuccess
,
126 OnRequestDeviceSuccess
);
127 IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceError
, OnRequestDeviceError
);
128 IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTSuccess
, OnConnectGATTSuccess
);
129 IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTError
, OnConnectGATTError
);
130 IPC_MESSAGE_HANDLER(BluetoothMsg_GetPrimaryServiceSuccess
,
131 OnGetPrimaryServiceSuccess
);
132 IPC_MESSAGE_HANDLER(BluetoothMsg_GetPrimaryServiceError
,
133 OnGetPrimaryServiceError
);
134 IPC_MESSAGE_HANDLER(BluetoothMsg_GetCharacteristicSuccess
,
135 OnGetCharacteristicSuccess
);
136 IPC_MESSAGE_HANDLER(BluetoothMsg_GetCharacteristicError
,
137 OnGetCharacteristicError
);
138 IPC_MESSAGE_HANDLER(BluetoothMsg_ReadCharacteristicValueSuccess
,
140 IPC_MESSAGE_HANDLER(BluetoothMsg_ReadCharacteristicValueError
,
142 IPC_MESSAGE_HANDLER(BluetoothMsg_WriteCharacteristicValueSuccess
,
143 OnWriteValueSuccess
);
144 IPC_MESSAGE_HANDLER(BluetoothMsg_WriteCharacteristicValueError
,
146 IPC_MESSAGE_UNHANDLED(handled
= false)
147 IPC_END_MESSAGE_MAP()
148 DCHECK(handled
) << "Unhandled message:" << msg
.type();
151 void BluetoothDispatcher::requestDevice(
152 int frame_routing_id
,
153 const WebRequestDeviceOptions
& options
,
154 blink::WebBluetoothRequestDeviceCallbacks
* callbacks
) {
155 int request_id
= pending_requests_
.Add(callbacks
);
157 // Convert |options| to its IPC form.
158 std::vector
<content::BluetoothScanFilter
> filters(options
.filters
.size());
159 for (size_t i
= 0; i
< options
.filters
.size(); ++i
) {
160 const WebBluetoothScanFilter
& web_filter
= options
.filters
[i
];
161 BluetoothScanFilter
& filter
= filters
[i
];
162 filter
.services
.reserve(web_filter
.services
.size());
163 for (const WebString
& service
: web_filter
.services
) {
164 filter
.services
.push_back(device::BluetoothUUID(service
.utf8()));
167 std::vector
<device::BluetoothUUID
> optional_services
;
168 optional_services
.reserve(options
.optionalServices
.size());
169 for (const WebString
& optional_service
: options
.optionalServices
) {
170 optional_services
.push_back(device::BluetoothUUID(optional_service
.utf8()));
173 Send(new BluetoothHostMsg_RequestDevice(CurrentWorkerId(), request_id
,
174 frame_routing_id
, filters
,
178 void BluetoothDispatcher::connectGATT(
179 const blink::WebString
& device_instance_id
,
180 blink::WebBluetoothConnectGATTCallbacks
* callbacks
) {
181 int request_id
= pending_connect_requests_
.Add(callbacks
);
182 Send(new BluetoothHostMsg_ConnectGATT(CurrentWorkerId(), request_id
,
183 device_instance_id
.utf8()));
186 void BluetoothDispatcher::getPrimaryService(
187 const blink::WebString
& device_instance_id
,
188 const blink::WebString
& service_uuid
,
189 blink::WebBluetoothGetPrimaryServiceCallbacks
* callbacks
) {
191 pending_primary_service_requests_
.Add(new BluetoothPrimaryServiceRequest(
192 device_instance_id
, service_uuid
, callbacks
));
193 Send(new BluetoothHostMsg_GetPrimaryService(CurrentWorkerId(), request_id
,
194 device_instance_id
.utf8(),
195 service_uuid
.utf8()));
198 void BluetoothDispatcher::getCharacteristic(
199 const blink::WebString
& service_instance_id
,
200 const blink::WebString
& characteristic_uuid
,
201 blink::WebBluetoothGetCharacteristicCallbacks
* callbacks
) {
203 pending_characteristic_requests_
.Add(new BluetoothCharacteristicRequest(
204 service_instance_id
, characteristic_uuid
, callbacks
));
205 Send(new BluetoothHostMsg_GetCharacteristic(CurrentWorkerId(), request_id
,
206 service_instance_id
.utf8(),
207 characteristic_uuid
.utf8()));
210 void BluetoothDispatcher::readValue(
211 const blink::WebString
& characteristic_instance_id
,
212 blink::WebBluetoothReadValueCallbacks
* callbacks
) {
213 int request_id
= pending_read_value_requests_
.Add(callbacks
);
214 Send(new BluetoothHostMsg_ReadValue(CurrentWorkerId(), request_id
,
215 characteristic_instance_id
.utf8()));
218 void BluetoothDispatcher::writeValue(
219 const blink::WebString
& characteristic_instance_id
,
220 const std::vector
<uint8_t>& value
,
221 blink::WebBluetoothWriteValueCallbacks
* callbacks
) {
222 int request_id
= pending_write_value_requests_
.Add(callbacks
);
224 Send(new BluetoothHostMsg_WriteValue(
225 CurrentWorkerId(), request_id
, characteristic_instance_id
.utf8(), value
));
228 void BluetoothDispatcher::WillStopCurrentWorkerThread() {
232 void BluetoothDispatcher::OnRequestDeviceSuccess(
235 const BluetoothDevice
& device
) {
236 DCHECK(pending_requests_
.Lookup(request_id
)) << request_id
;
238 WebVector
<WebString
> uuids(device
.uuids
.size());
239 for (size_t i
= 0; i
< device
.uuids
.size(); ++i
)
240 uuids
[i
] = WebString::fromUTF8(device
.uuids
[i
].c_str());
242 pending_requests_
.Lookup(request_id
)
243 ->onSuccess(blink::adoptWebPtr(new WebBluetoothDevice(
244 WebString::fromUTF8(device
.instance_id
), WebString(device
.name
),
245 device
.device_class
, GetWebVendorIdSource(device
.vendor_id_source
),
246 device
.vendor_id
, device
.product_id
, device
.product_version
,
247 device
.paired
, uuids
)));
248 pending_requests_
.Remove(request_id
);
251 void BluetoothDispatcher::OnRequestDeviceError(int thread_id
,
253 WebBluetoothError error
) {
254 DCHECK(pending_requests_
.Lookup(request_id
)) << request_id
;
255 pending_requests_
.Lookup(request_id
)->onError(WebBluetoothError(error
));
256 pending_requests_
.Remove(request_id
);
259 void BluetoothDispatcher::OnConnectGATTSuccess(
262 const std::string
& device_instance_id
) {
263 DCHECK(pending_connect_requests_
.Lookup(request_id
)) << request_id
;
264 pending_connect_requests_
.Lookup(request_id
)
265 ->onSuccess(blink::adoptWebPtr(new WebBluetoothGATTRemoteServer(
266 WebString::fromUTF8(device_instance_id
), true /* connected */)));
267 pending_connect_requests_
.Remove(request_id
);
270 void BluetoothDispatcher::OnConnectGATTError(int thread_id
,
272 WebBluetoothError error
) {
273 DCHECK(pending_connect_requests_
.Lookup(request_id
)) << request_id
;
274 pending_connect_requests_
.Lookup(request_id
)
275 ->onError(WebBluetoothError(error
));
276 pending_connect_requests_
.Remove(request_id
);
279 void BluetoothDispatcher::OnGetPrimaryServiceSuccess(
282 const std::string
& service_instance_id
) {
283 DCHECK(pending_primary_service_requests_
.Lookup(request_id
)) << request_id
;
284 BluetoothPrimaryServiceRequest
* request
=
285 pending_primary_service_requests_
.Lookup(request_id
);
286 request
->callbacks
->onSuccess(blink::adoptWebPtr(new WebBluetoothGATTService(
287 WebString::fromUTF8(service_instance_id
), request
->service_uuid
,
288 true /* isPrimary */, request
->device_instance_id
)));
289 pending_primary_service_requests_
.Remove(request_id
);
292 void BluetoothDispatcher::OnGetPrimaryServiceError(int thread_id
,
294 WebBluetoothError error
) {
295 DCHECK(pending_primary_service_requests_
.Lookup(request_id
)) << request_id
;
297 // Since we couldn't find the service return null. See Step 3 of
298 // getPrimaryService algorithm:
299 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattremoteserver-getprimaryservice
300 if (error
== WebBluetoothError::ServiceNotFound
) {
301 pending_primary_service_requests_
.Lookup(request_id
)
302 ->callbacks
->onSuccess(nullptr);
303 pending_primary_service_requests_
.Remove(request_id
);
307 pending_primary_service_requests_
.Lookup(request_id
)
308 ->callbacks
->onError(WebBluetoothError(error
));
309 pending_primary_service_requests_
.Remove(request_id
);
312 void BluetoothDispatcher::OnGetCharacteristicSuccess(
315 const std::string
& characteristic_instance_id
) {
316 DCHECK(pending_characteristic_requests_
.Lookup(request_id
)) << request_id
;
318 BluetoothCharacteristicRequest
* request
=
319 pending_characteristic_requests_
.Lookup(request_id
);
320 request
->callbacks
->onSuccess(
321 blink::adoptWebPtr(new WebBluetoothGATTCharacteristic(
322 WebString::fromUTF8(characteristic_instance_id
),
323 request
->service_instance_id
, request
->characteristic_uuid
)));
325 pending_characteristic_requests_
.Remove(request_id
);
328 void BluetoothDispatcher::OnGetCharacteristicError(int thread_id
,
330 WebBluetoothError error
) {
331 DCHECK(pending_characteristic_requests_
.Lookup(request_id
)) << request_id
;
333 // Since we couldn't find the characteristic return null. See Step 3 of
334 // getCharacteristic algorithm:
335 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattservice-getcharacteristic
336 if (error
== WebBluetoothError::CharacteristicNotFound
) {
337 pending_characteristic_requests_
.Lookup(request_id
)
338 ->callbacks
->onSuccess(nullptr);
340 pending_characteristic_requests_
.Lookup(request_id
)
341 ->callbacks
->onError(WebBluetoothError(error
));
343 pending_characteristic_requests_
.Remove(request_id
);
346 void BluetoothDispatcher::OnReadValueSuccess(
349 const std::vector
<uint8_t>& value
) {
350 DCHECK(pending_read_value_requests_
.Lookup(request_id
)) << request_id
;
352 // WebArrayBuffer is not accessible from Source/modules so we pass a
353 // WebVector instead.
354 pending_read_value_requests_
.Lookup(request_id
)->onSuccess(value
);
356 pending_read_value_requests_
.Remove(request_id
);
359 void BluetoothDispatcher::OnReadValueError(int thread_id
,
361 WebBluetoothError error
) {
362 DCHECK(pending_read_value_requests_
.Lookup(request_id
)) << request_id
;
364 pending_read_value_requests_
.Lookup(request_id
)
365 ->onError(WebBluetoothError(error
));
367 pending_read_value_requests_
.Remove(request_id
);
370 void BluetoothDispatcher::OnWriteValueSuccess(int thread_id
, int request_id
) {
371 DCHECK(pending_write_value_requests_
.Lookup(request_id
)) << request_id
;
373 pending_write_value_requests_
.Lookup(request_id
)->onSuccess();
375 pending_write_value_requests_
.Remove(request_id
);
378 void BluetoothDispatcher::OnWriteValueError(int thread_id
,
380 WebBluetoothError error
) {
381 DCHECK(pending_write_value_requests_
.Lookup(request_id
)) << request_id
;
383 pending_write_value_requests_
.Lookup(request_id
)
384 ->onError(WebBluetoothError(error
));
386 pending_write_value_requests_
.Remove(request_id
);
389 } // namespace content