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/child/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/modules/bluetooth/WebBluetoothDevice.h"
15 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h"
16 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTCharacteristic.h"
17 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h"
18 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTService.h"
19 #include "third_party/WebKit/public/platform/modules/bluetooth/WebRequestDeviceOptions.h"
21 using blink::WebBluetoothConnectGATTCallbacks
;
22 using blink::WebBluetoothDevice
;
23 using blink::WebBluetoothError
;
24 using blink::WebBluetoothGATTCharacteristic
;
25 using blink::WebBluetoothGATTRemoteServer
;
26 using blink::WebBluetoothGATTService
;
27 using blink::WebBluetoothReadValueCallbacks
;
28 using blink::WebBluetoothRequestDeviceCallbacks
;
29 using blink::WebBluetoothScanFilter
;
30 using blink::WebRequestDeviceOptions
;
31 using blink::WebString
;
32 using blink::WebVector
;
34 struct BluetoothPrimaryServiceRequest
{
35 BluetoothPrimaryServiceRequest(
36 blink::WebString device_instance_id
,
37 blink::WebString service_uuid
,
38 blink::WebBluetoothGetPrimaryServiceCallbacks
* callbacks
)
39 : device_instance_id(device_instance_id
),
40 service_uuid(service_uuid
),
41 callbacks(callbacks
) {}
42 ~BluetoothPrimaryServiceRequest() {}
44 blink::WebString device_instance_id
;
45 blink::WebString service_uuid
;
46 scoped_ptr
<blink::WebBluetoothGetPrimaryServiceCallbacks
> callbacks
;
49 struct BluetoothCharacteristicRequest
{
50 BluetoothCharacteristicRequest(
51 blink::WebString service_instance_id
,
52 blink::WebString characteristic_uuid
,
53 blink::WebBluetoothGetCharacteristicCallbacks
* callbacks
)
54 : service_instance_id(service_instance_id
),
55 characteristic_uuid(characteristic_uuid
),
56 callbacks(callbacks
) {}
57 ~BluetoothCharacteristicRequest() {}
59 blink::WebString service_instance_id
;
60 blink::WebString characteristic_uuid
;
61 scoped_ptr
<blink::WebBluetoothGetCharacteristicCallbacks
> callbacks
;
68 base::LazyInstance
<base::ThreadLocalPointer
<BluetoothDispatcher
>>::Leaky
69 g_dispatcher_tls
= LAZY_INSTANCE_INITIALIZER
;
71 BluetoothDispatcher
* const kHasBeenDeleted
=
72 reinterpret_cast<BluetoothDispatcher
*>(0x1);
74 int CurrentWorkerId() {
75 return WorkerTaskRunner::Instance()->CurrentWorkerId();
78 WebBluetoothError::ErrorType
WebBluetoothErrorFromBluetoothError(
79 BluetoothError error_type
) {
81 case BluetoothError::ABORT
:
82 return WebBluetoothError::AbortError
;
83 case BluetoothError::INVALID_MODIFICATION
:
84 return WebBluetoothError::InvalidModificationError
;
85 case BluetoothError::INVALID_STATE
:
86 return WebBluetoothError::InvalidStateError
;
87 case BluetoothError::NETWORK
:
88 return WebBluetoothError::NetworkError
;
89 case BluetoothError::NOT_FOUND
:
90 return WebBluetoothError::NotFoundError
;
91 case BluetoothError::NOT_SUPPORTED
:
92 return WebBluetoothError::NotSupportedError
;
93 case BluetoothError::SECURITY
:
94 return WebBluetoothError::SecurityError
;
95 case BluetoothError::SYNTAX
:
96 return WebBluetoothError::SyntaxError
;
99 return WebBluetoothError::NotFoundError
;
102 WebBluetoothDevice::VendorIDSource
GetWebVendorIdSource(
103 device::BluetoothDevice::VendorIDSource vendor_id_source
) {
104 switch (vendor_id_source
) {
105 case device::BluetoothDevice::VENDOR_ID_UNKNOWN
:
106 return WebBluetoothDevice::VendorIDSource::Unknown
;
107 case device::BluetoothDevice::VENDOR_ID_BLUETOOTH
:
108 return WebBluetoothDevice::VendorIDSource::Bluetooth
;
109 case device::BluetoothDevice::VENDOR_ID_USB
:
110 return WebBluetoothDevice::VendorIDSource::USB
;
113 return WebBluetoothDevice::VendorIDSource::Unknown
;
118 BluetoothDispatcher::BluetoothDispatcher(ThreadSafeSender
* sender
)
119 : thread_safe_sender_(sender
) {
120 g_dispatcher_tls
.Pointer()->Set(this);
123 BluetoothDispatcher::~BluetoothDispatcher() {
124 g_dispatcher_tls
.Pointer()->Set(kHasBeenDeleted
);
127 BluetoothDispatcher
* BluetoothDispatcher::GetOrCreateThreadSpecificInstance(
128 ThreadSafeSender
* thread_safe_sender
) {
129 if (g_dispatcher_tls
.Pointer()->Get() == kHasBeenDeleted
) {
130 NOTREACHED() << "Re-instantiating TLS BluetoothDispatcher.";
131 g_dispatcher_tls
.Pointer()->Set(NULL
);
133 if (g_dispatcher_tls
.Pointer()->Get())
134 return g_dispatcher_tls
.Pointer()->Get();
136 BluetoothDispatcher
* dispatcher
= new BluetoothDispatcher(thread_safe_sender
);
137 if (CurrentWorkerId())
138 WorkerTaskRunner::Instance()->AddStopObserver(dispatcher
);
142 bool BluetoothDispatcher::Send(IPC::Message
* msg
) {
143 return thread_safe_sender_
->Send(msg
);
146 void BluetoothDispatcher::OnMessageReceived(const IPC::Message
& msg
) {
148 IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcher
, msg
)
149 IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceSuccess
,
150 OnRequestDeviceSuccess
);
151 IPC_MESSAGE_HANDLER(BluetoothMsg_RequestDeviceError
, OnRequestDeviceError
);
152 IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTSuccess
, OnConnectGATTSuccess
);
153 IPC_MESSAGE_HANDLER(BluetoothMsg_ConnectGATTError
, OnConnectGATTError
);
154 IPC_MESSAGE_HANDLER(BluetoothMsg_GetPrimaryServiceSuccess
,
155 OnGetPrimaryServiceSuccess
);
156 IPC_MESSAGE_HANDLER(BluetoothMsg_GetPrimaryServiceError
,
157 OnGetPrimaryServiceError
);
158 IPC_MESSAGE_HANDLER(BluetoothMsg_GetCharacteristicSuccess
,
159 OnGetCharacteristicSuccess
);
160 IPC_MESSAGE_HANDLER(BluetoothMsg_GetCharacteristicError
,
161 OnGetCharacteristicError
);
162 IPC_MESSAGE_HANDLER(BluetoothMsg_ReadCharacteristicValueSuccess
,
164 IPC_MESSAGE_HANDLER(BluetoothMsg_ReadCharacteristicValueError
,
166 IPC_MESSAGE_UNHANDLED(handled
= false)
167 IPC_END_MESSAGE_MAP()
168 DCHECK(handled
) << "Unhandled message:" << msg
.type();
171 void BluetoothDispatcher::requestDevice(
172 const WebRequestDeviceOptions
& options
,
173 blink::WebBluetoothRequestDeviceCallbacks
* callbacks
) {
174 int request_id
= pending_requests_
.Add(callbacks
);
176 // Convert |options| to its IPC form.
177 std::vector
<content::BluetoothScanFilter
> filters(options
.filters
.size());
178 for (size_t i
= 0; i
< options
.filters
.size(); ++i
) {
179 const WebBluetoothScanFilter
& web_filter
= options
.filters
[i
];
180 BluetoothScanFilter
& filter
= filters
[i
];
181 filter
.services
.reserve(web_filter
.services
.size());
182 for (const WebString
& service
: web_filter
.services
) {
183 filter
.services
.push_back(device::BluetoothUUID(service
.utf8()));
186 std::vector
<device::BluetoothUUID
> optional_services
;
187 optional_services
.reserve(options
.optionalServices
.size());
188 for (const WebString
& optional_service
: options
.optionalServices
) {
189 optional_services
.push_back(device::BluetoothUUID(optional_service
.utf8()));
192 Send(new BluetoothHostMsg_RequestDevice(CurrentWorkerId(), request_id
,
193 filters
, optional_services
));
196 void BluetoothDispatcher::connectGATT(
197 const blink::WebString
& device_instance_id
,
198 blink::WebBluetoothConnectGATTCallbacks
* callbacks
) {
199 int request_id
= pending_connect_requests_
.Add(callbacks
);
200 Send(new BluetoothHostMsg_ConnectGATT(CurrentWorkerId(), request_id
,
201 device_instance_id
.utf8()));
204 void BluetoothDispatcher::getPrimaryService(
205 const blink::WebString
& device_instance_id
,
206 const blink::WebString
& service_uuid
,
207 blink::WebBluetoothGetPrimaryServiceCallbacks
* callbacks
) {
209 pending_primary_service_requests_
.Add(new BluetoothPrimaryServiceRequest(
210 device_instance_id
, service_uuid
, callbacks
));
211 Send(new BluetoothHostMsg_GetPrimaryService(CurrentWorkerId(), request_id
,
212 device_instance_id
.utf8(),
213 service_uuid
.utf8()));
216 void BluetoothDispatcher::getCharacteristic(
217 const blink::WebString
& service_instance_id
,
218 const blink::WebString
& characteristic_uuid
,
219 blink::WebBluetoothGetCharacteristicCallbacks
* callbacks
) {
221 pending_characteristic_requests_
.Add(new BluetoothCharacteristicRequest(
222 service_instance_id
, characteristic_uuid
, callbacks
));
223 Send(new BluetoothHostMsg_GetCharacteristic(CurrentWorkerId(), request_id
,
224 service_instance_id
.utf8(),
225 characteristic_uuid
.utf8()));
228 void BluetoothDispatcher::readValue(
229 const blink::WebString
& characteristic_instance_id
,
230 blink::WebBluetoothReadValueCallbacks
* callbacks
) {
231 int request_id
= pending_read_value_requests_
.Add(callbacks
);
232 Send(new BluetoothHostMsg_ReadValue(CurrentWorkerId(), request_id
,
233 characteristic_instance_id
.utf8()));
236 void BluetoothDispatcher::OnWorkerRunLoopStopped() {
240 void BluetoothDispatcher::OnRequestDeviceSuccess(
243 const BluetoothDevice
& device
) {
244 DCHECK(pending_requests_
.Lookup(request_id
)) << request_id
;
246 WebVector
<WebString
> uuids(device
.uuids
.size());
247 for (size_t i
= 0; i
< device
.uuids
.size(); ++i
)
248 uuids
[i
] = WebString::fromUTF8(device
.uuids
[i
].c_str());
250 pending_requests_
.Lookup(request_id
)
251 ->onSuccess(new WebBluetoothDevice(
252 WebString::fromUTF8(device
.instance_id
), WebString(device
.name
),
253 device
.device_class
, GetWebVendorIdSource(device
.vendor_id_source
),
254 device
.vendor_id
, device
.product_id
, device
.product_version
,
255 device
.paired
, uuids
));
256 pending_requests_
.Remove(request_id
);
259 void BluetoothDispatcher::OnRequestDeviceError(
262 BluetoothError error_type
,
263 const std::string
& error_message
) {
264 DCHECK(pending_requests_
.Lookup(request_id
)) << request_id
;
265 pending_requests_
.Lookup(request_id
)
266 ->onError(new WebBluetoothError(
267 // TODO(ortuno): Return more descriptive error messages.
268 // http://crbug.com/490419
269 WebBluetoothErrorFromBluetoothError(error_type
),
270 WebString::fromUTF8(error_message
)));
271 pending_requests_
.Remove(request_id
);
274 void BluetoothDispatcher::OnConnectGATTSuccess(
277 const std::string
& device_instance_id
) {
278 DCHECK(pending_connect_requests_
.Lookup(request_id
)) << request_id
;
279 pending_connect_requests_
.Lookup(request_id
)
280 ->onSuccess(new WebBluetoothGATTRemoteServer(
281 WebString::fromUTF8(device_instance_id
), true /* connected */));
282 pending_connect_requests_
.Remove(request_id
);
285 void BluetoothDispatcher::OnConnectGATTError(int thread_id
,
287 BluetoothError error_type
,
288 const std::string
& error_message
) {
289 DCHECK(pending_connect_requests_
.Lookup(request_id
)) << request_id
;
290 pending_connect_requests_
.Lookup(request_id
)
291 ->onError(new WebBluetoothError(
292 // TODO(ortuno): Return more descriptive error messages.
293 // http://crbug.com/490419
294 WebBluetoothErrorFromBluetoothError(error_type
),
295 WebString::fromUTF8(error_message
)));
296 pending_connect_requests_
.Remove(request_id
);
299 void BluetoothDispatcher::OnGetPrimaryServiceSuccess(
302 const std::string
& service_instance_id
) {
303 DCHECK(pending_primary_service_requests_
.Lookup(request_id
)) << request_id
;
304 BluetoothPrimaryServiceRequest
* request
=
305 pending_primary_service_requests_
.Lookup(request_id
);
306 request
->callbacks
->onSuccess(new WebBluetoothGATTService(
307 WebString::fromUTF8(service_instance_id
), request
->service_uuid
,
308 true /* isPrimary */, request
->device_instance_id
));
309 pending_primary_service_requests_
.Remove(request_id
);
312 void BluetoothDispatcher::OnGetPrimaryServiceError(
315 BluetoothError error_type
,
316 const std::string
& error_message
) {
317 DCHECK(pending_primary_service_requests_
.Lookup(request_id
)) << request_id
;
319 // Since we couldn't find the service return null. See Step 3 of
320 // getPrimaryService algorithm:
321 // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothgattremoteserver-getprimaryservice
322 if (error_type
== BluetoothError::NOT_FOUND
) {
323 pending_primary_service_requests_
.Lookup(request_id
)
324 ->callbacks
->onSuccess(nullptr);
325 pending_primary_service_requests_
.Remove(request_id
);
329 pending_primary_service_requests_
.Lookup(request_id
)
330 ->callbacks
->onError(new WebBluetoothError(
331 // TODO(ortuno): Return more descriptive error messages.
332 // http://crbug.com/490419
333 WebBluetoothErrorFromBluetoothError(error_type
),
334 WebString::fromUTF8(error_message
)));
335 pending_primary_service_requests_
.Remove(request_id
);
338 void BluetoothDispatcher::OnGetCharacteristicSuccess(
341 const std::string
& characteristic_instance_id
) {
342 DCHECK(pending_characteristic_requests_
.Lookup(request_id
)) << request_id
;
344 BluetoothCharacteristicRequest
* request
=
345 pending_characteristic_requests_
.Lookup(request_id
);
346 request
->callbacks
->onSuccess(new WebBluetoothGATTCharacteristic(
347 WebString::fromUTF8(characteristic_instance_id
),
348 request
->service_instance_id
, request
->characteristic_uuid
));
350 pending_characteristic_requests_
.Remove(request_id
);
353 void BluetoothDispatcher::OnGetCharacteristicError(
356 BluetoothError error_type
,
357 const std::string
& error_message
) {
358 DCHECK(pending_characteristic_requests_
.Lookup(request_id
)) << request_id
;
360 // Since we couldn't find the characteristic return null. See Step 3 of
361 // getCharacteristic algorithm:
362 // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothgattservice-getcharacteristic
363 if (error_type
== BluetoothError::NOT_FOUND
) {
364 pending_characteristic_requests_
.Lookup(request_id
)
365 ->callbacks
->onSuccess(nullptr);
367 pending_characteristic_requests_
.Lookup(request_id
)
368 ->callbacks
->onError(new WebBluetoothError(
369 // TODO(ortuno): Return more descriptive error messages.
370 // http://crbug.com/490419
371 WebBluetoothErrorFromBluetoothError(error_type
),
372 WebString::fromUTF8(error_message
)));
374 pending_characteristic_requests_
.Remove(request_id
);
377 void BluetoothDispatcher::OnReadValueSuccess(
380 const std::vector
<uint8_t>& value
) {
381 DCHECK(pending_read_value_requests_
.Lookup(request_id
)) << request_id
;
383 // WebArrayBuffer is not accessible from Source/modules so we pass a
384 // WebVector instead.
385 pending_read_value_requests_
.Lookup(request_id
)
386 ->onSuccess(new WebVector
<uint8_t>(value
));
388 pending_read_value_requests_
.Remove(request_id
);
391 void BluetoothDispatcher::OnReadValueError(int thread_id
,
393 BluetoothError error_type
,
394 const std::string
& error_message
) {
395 DCHECK(pending_read_value_requests_
.Lookup(request_id
)) << request_id
;
397 pending_read_value_requests_
.Lookup(request_id
)
398 ->onError(new WebBluetoothError(
399 // TODO(ortuno): Return more descriptive error messages.
400 // http://crbug.com/490419
401 WebBluetoothErrorFromBluetoothError(error_type
),
402 WebString::fromUTF8(error_message
)));
404 pending_read_value_requests_
.Remove(request_id
);
407 } // namespace content