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.
4
5 #include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_event_router.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/values.h"
10 #include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_connection.h"
11 #include "chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_notify_session.h"
12 #include "chrome/browser/extensions/api/bluetooth_low_energy/utils.h"
13 #include "chrome/common/extensions/api/bluetooth/bluetooth_manifest_data.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "device/bluetooth/bluetooth_adapter_factory.h"
16 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
17 #include "device/bluetooth/bluetooth_gatt_connection.h"
18 #include "device/bluetooth/bluetooth_gatt_descriptor.h"
19 #include "extensions/browser/event_router.h"
20 #include "extensions/browser/extension_registry.h"
21
22 using content::BrowserThread;
23
24 using device::BluetoothAdapter;
25 using device::BluetoothAdapterFactory;
26 using device::BluetoothDevice;
27 using device::BluetoothGattCharacteristic;
28 using device::BluetoothGattConnection;
29 using device::BluetoothGattDescriptor;
30 using device::BluetoothGattService;
31
32 namespace apibtle = extensions::api::bluetooth_low_energy;
33
34 namespace {
35
PopulateService(const BluetoothGattService * service,apibtle::Service * out)36 void PopulateService(const BluetoothGattService* service,
37 apibtle::Service* out) {
38 DCHECK(out);
39
40 out->uuid = service->GetUUID().canonical_value();
41 out->is_primary = service->IsPrimary();
42 out->is_local = service->IsLocal();
43 out->instance_id.reset(new std::string(service->GetIdentifier()));
44
45 if (!service->GetDevice())
46 return;
47
48 out->device_address.reset(
49 new std::string(service->GetDevice()->GetAddress()));
50 }
51
PopulateCharacteristicProperties(BluetoothGattCharacteristic::Properties properties,std::vector<apibtle::CharacteristicProperty> * api_properties)52 void PopulateCharacteristicProperties(
53 BluetoothGattCharacteristic::Properties properties,
54 std::vector<apibtle::CharacteristicProperty>* api_properties) {
55 DCHECK(api_properties && api_properties->empty());
56
57 if (properties == BluetoothGattCharacteristic::kPropertyNone)
58 return;
59
60 if (properties & BluetoothGattCharacteristic::kPropertyBroadcast)
61 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_BROADCAST);
62 if (properties & BluetoothGattCharacteristic::kPropertyRead)
63 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_READ);
64 if (properties & BluetoothGattCharacteristic::kPropertyWriteWithoutResponse) {
65 api_properties->push_back(
66 apibtle::CHARACTERISTIC_PROPERTY_WRITEWITHOUTRESPONSE);
67 }
68 if (properties & BluetoothGattCharacteristic::kPropertyWrite)
69 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_WRITE);
70 if (properties & BluetoothGattCharacteristic::kPropertyNotify)
71 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_NOTIFY);
72 if (properties & BluetoothGattCharacteristic::kPropertyIndicate)
73 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_INDICATE);
74 if (properties &
75 BluetoothGattCharacteristic::kPropertyAuthenticatedSignedWrites) {
76 api_properties->push_back(
77 apibtle::CHARACTERISTIC_PROPERTY_AUTHENTICATEDSIGNEDWRITES);
78 }
79 if (properties & BluetoothGattCharacteristic::kPropertyExtendedProperties) {
80 api_properties->push_back(
81 apibtle::CHARACTERISTIC_PROPERTY_EXTENDEDPROPERTIES);
82 }
83 if (properties & BluetoothGattCharacteristic::kPropertyReliableWrite)
84 api_properties->push_back(apibtle::CHARACTERISTIC_PROPERTY_RELIABLEWRITE);
85 if (properties & BluetoothGattCharacteristic::kPropertyWritableAuxiliaries) {
86 api_properties->push_back(
87 apibtle::CHARACTERISTIC_PROPERTY_WRITABLEAUXILIARIES);
88 }
89 }
90
PopulateCharacteristic(const BluetoothGattCharacteristic * characteristic,apibtle::Characteristic * out)91 void PopulateCharacteristic(const BluetoothGattCharacteristic* characteristic,
92 apibtle::Characteristic* out) {
93 DCHECK(out);
94
95 out->uuid = characteristic->GetUUID().canonical_value();
96 out->is_local = characteristic->IsLocal();
97 out->instance_id.reset(new std::string(characteristic->GetIdentifier()));
98
99 PopulateService(characteristic->GetService(), &out->service);
100 PopulateCharacteristicProperties(characteristic->GetProperties(),
101 &out->properties);
102
103 const std::vector<uint8>& value = characteristic->GetValue();
104 if (value.empty())
105 return;
106
107 out->value.reset(new std::string(value.begin(), value.end()));
108 }
109
PopulateDescriptor(const BluetoothGattDescriptor * descriptor,apibtle::Descriptor * out)110 void PopulateDescriptor(const BluetoothGattDescriptor* descriptor,
111 apibtle::Descriptor* out) {
112 DCHECK(out);
113
114 out->uuid = descriptor->GetUUID().canonical_value();
115 out->is_local = descriptor->IsLocal();
116 out->instance_id.reset(new std::string(descriptor->GetIdentifier()));
117
118 PopulateCharacteristic(descriptor->GetCharacteristic(), &out->characteristic);
119
120 const std::vector<uint8>& value = descriptor->GetValue();
121 if (value.empty())
122 return;
123
124 out->value.reset(new std::string(value.begin(), value.end()));
125 }
126
127 typedef extensions::ApiResourceManager<extensions::BluetoothLowEnergyConnection>
128 ConnectionResourceManager;
GetConnectionResourceManager(content::BrowserContext * context)129 ConnectionResourceManager* GetConnectionResourceManager(
130 content::BrowserContext* context) {
131 ConnectionResourceManager* manager = ConnectionResourceManager::Get(context);
132 DCHECK(manager)
133 << "There is no Bluetooth low energy connection manager. "
134 "If this assertion is failing during a test, then it is likely that "
135 "TestExtensionSystem is failing to provide an instance of "
136 "ApiResourceManager<BluetoothLowEnergyConnection>.";
137 return manager;
138 }
139
140 typedef extensions::ApiResourceManager<
141 extensions::BluetoothLowEnergyNotifySession> NotifySessionResourceManager;
GetNotifySessionResourceManager(content::BrowserContext * context)142 NotifySessionResourceManager* GetNotifySessionResourceManager(
143 content::BrowserContext* context) {
144 NotifySessionResourceManager* manager =
145 NotifySessionResourceManager::Get(context);
146 DCHECK(manager)
147 << "There is no Bluetooth low energy value update session manager."
148 "If this assertion is failing during a test, then it is likely that "
149 "TestExtensionSystem is failing to provide an instance of "
150 "ApiResourceManager<BluetoothLowEnergyNotifySession>.";
151 return manager;
152 }
153
154 } // namespace
155
156 namespace extensions {
157
BluetoothLowEnergyEventRouter(content::BrowserContext * context)158 BluetoothLowEnergyEventRouter::BluetoothLowEnergyEventRouter(
159 content::BrowserContext* context)
160 : adapter_(NULL), browser_context_(context), weak_ptr_factory_(this) {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
162 DCHECK(browser_context_);
163 VLOG(1) << "Initializing BluetoothLowEnergyEventRouter.";
164
165 if (!IsBluetoothSupported()) {
166 VLOG(1) << "Bluetooth not supported on the current platform.";
167 return;
168 }
169 }
170
~BluetoothLowEnergyEventRouter()171 BluetoothLowEnergyEventRouter::~BluetoothLowEnergyEventRouter() {
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
173 if (!adapter_.get())
174 return;
175
176 adapter_->RemoveObserver(this);
177
178 for (std::set<std::string>::const_iterator iter = observed_devices_.begin();
179 iter != observed_devices_.end();
180 ++iter) {
181 BluetoothDevice* device = adapter_->GetDevice(*iter);
182 if (!device)
183 continue;
184 device->RemoveObserver(this);
185 }
186
187 for (std::set<std::string>::const_iterator iter =
188 observed_gatt_services_.begin();
189 iter != observed_gatt_services_.end();
190 ++iter) {
191 BluetoothGattService* service = FindServiceById(*iter);
192 if (!service)
193 continue;
194 service->RemoveObserver(this);
195 }
196
197 adapter_ = NULL;
198 }
199
IsBluetoothSupported() const200 bool BluetoothLowEnergyEventRouter::IsBluetoothSupported() const {
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
202 return adapter_.get() ||
203 BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
204 }
205
InitializeAdapterAndInvokeCallback(const base::Closure & callback)206 bool BluetoothLowEnergyEventRouter::InitializeAdapterAndInvokeCallback(
207 const base::Closure& callback) {
208 if (!IsBluetoothSupported())
209 return false;
210
211 if (adapter_.get()) {
212 callback.Run();
213 return true;
214 }
215
216 BluetoothAdapterFactory::GetAdapter(
217 base::Bind(&BluetoothLowEnergyEventRouter::OnGetAdapter,
218 weak_ptr_factory_.GetWeakPtr(),
219 callback));
220 return true;
221 }
222
HasAdapter() const223 bool BluetoothLowEnergyEventRouter::HasAdapter() const {
224 return (adapter_.get() != NULL);
225 }
226
Connect(bool persistent,const Extension * extension,const std::string & device_address,const base::Closure & callback,const ErrorCallback & error_callback)227 void BluetoothLowEnergyEventRouter::Connect(
228 bool persistent,
229 const Extension* extension,
230 const std::string& device_address,
231 const base::Closure& callback,
232 const ErrorCallback& error_callback) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
234 if (!adapter_) {
235 VLOG(1) << "BluetoothAdapter not ready.";
236 error_callback.Run(kStatusErrorFailed);
237 return;
238 }
239
240 const std::string extension_id = extension->id();
241 const std::string connect_id = extension_id + device_address;
242
243 if (connecting_devices_.count(connect_id) != 0) {
244 error_callback.Run(kStatusErrorInProgress);
245 return;
246 }
247
248 BluetoothLowEnergyConnection* conn =
249 FindConnection(extension_id, device_address);
250 if (conn) {
251 if (conn->GetConnection()->IsConnected()) {
252 VLOG(1) << "Application already connected to device: " << device_address;
253 error_callback.Run(kStatusErrorAlreadyConnected);
254 return;
255 }
256
257 // There is a connection object but it's no longer active. Simply remove it.
258 RemoveConnection(extension_id, device_address);
259 }
260
261 BluetoothDevice* device = adapter_->GetDevice(device_address);
262 if (!device) {
263 VLOG(1) << "Bluetooth device not found: " << device_address;
264 error_callback.Run(kStatusErrorNotFound);
265 return;
266 }
267
268 connecting_devices_.insert(connect_id);
269 device->CreateGattConnection(
270 base::Bind(&BluetoothLowEnergyEventRouter::OnCreateGattConnection,
271 weak_ptr_factory_.GetWeakPtr(),
272 persistent,
273 extension_id,
274 device_address,
275 callback),
276 base::Bind(&BluetoothLowEnergyEventRouter::OnConnectError,
277 weak_ptr_factory_.GetWeakPtr(),
278 extension_id,
279 device_address,
280 error_callback));
281 }
282
Disconnect(const Extension * extension,const std::string & device_address,const base::Closure & callback,const ErrorCallback & error_callback)283 void BluetoothLowEnergyEventRouter::Disconnect(
284 const Extension* extension,
285 const std::string& device_address,
286 const base::Closure& callback,
287 const ErrorCallback& error_callback) {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
289 if (!adapter_) {
290 VLOG(1) << "BluetoothAdapter not ready.";
291 error_callback.Run(kStatusErrorFailed);
292 return;
293 }
294
295 const std::string extension_id = extension->id();
296 const std::string disconnect_id = extension_id + device_address;
297
298 if (disconnecting_devices_.count(disconnect_id) != 0) {
299 error_callback.Run(kStatusErrorInProgress);
300 return;
301 }
302
303 BluetoothLowEnergyConnection* conn =
304 FindConnection(extension_id, device_address);
305 if (!conn || !conn->GetConnection()->IsConnected()) {
306 VLOG(1) << "Application not connected to device: " << device_address;
307 error_callback.Run(kStatusErrorNotConnected);
308 return;
309 }
310
311 disconnecting_devices_.insert(disconnect_id);
312 conn->GetConnection()->Disconnect(
313 base::Bind(&BluetoothLowEnergyEventRouter::OnDisconnect,
314 weak_ptr_factory_.GetWeakPtr(),
315 extension_id,
316 device_address,
317 callback));
318 }
319
GetServices(const std::string & device_address,ServiceList * out_services) const320 bool BluetoothLowEnergyEventRouter::GetServices(
321 const std::string& device_address,
322 ServiceList* out_services) const {
323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
324 DCHECK(out_services);
325 if (!adapter_) {
326 VLOG(1) << "BluetoothAdapter not ready.";
327 return false;
328 }
329
330 BluetoothDevice* device = adapter_->GetDevice(device_address);
331 if (!device) {
332 VLOG(1) << "Bluetooth device not found: " << device_address;
333 return false;
334 }
335
336 out_services->clear();
337
338 const std::vector<BluetoothGattService*>& services =
339 device->GetGattServices();
340 for (std::vector<BluetoothGattService*>::const_iterator iter =
341 services.begin();
342 iter != services.end();
343 ++iter) {
344 // Populate an API service and add it to the return value.
345 const BluetoothGattService* service = *iter;
346 linked_ptr<apibtle::Service> api_service(new apibtle::Service());
347 PopulateService(service, api_service.get());
348
349 out_services->push_back(api_service);
350 }
351
352 return true;
353 }
354
GetService(const std::string & instance_id,apibtle::Service * out_service) const355 BluetoothLowEnergyEventRouter::Status BluetoothLowEnergyEventRouter::GetService(
356 const std::string& instance_id,
357 apibtle::Service* out_service) const {
358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
359 DCHECK(out_service);
360 if (!adapter_) {
361 VLOG(1) << "BluetoothAdapter not ready.";
362 return kStatusErrorFailed;
363 }
364
365 BluetoothGattService* gatt_service = FindServiceById(instance_id);
366 if (!gatt_service) {
367 VLOG(1) << "Service not found: " << instance_id;
368 return kStatusErrorNotFound;
369 }
370
371 PopulateService(gatt_service, out_service);
372 return kStatusSuccess;
373 }
374
375 BluetoothLowEnergyEventRouter::Status
GetIncludedServices(const std::string & instance_id,ServiceList * out_services) const376 BluetoothLowEnergyEventRouter::GetIncludedServices(
377 const std::string& instance_id,
378 ServiceList* out_services) const {
379 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
380 DCHECK(out_services);
381 if (!adapter_) {
382 VLOG(1) << "BluetoothAdapter not ready.";
383 return kStatusErrorFailed;
384 }
385
386 BluetoothGattService* service = FindServiceById(instance_id);
387 if (!service) {
388 VLOG(1) << "Service not found: " << instance_id;
389 return kStatusErrorNotFound;
390 }
391
392 out_services->clear();
393
394 const std::vector<BluetoothGattService*>& includes =
395 service->GetIncludedServices();
396 for (std::vector<BluetoothGattService*>::const_iterator iter =
397 includes.begin();
398 iter != includes.end();
399 ++iter) {
400 // Populate an API service and add it to the return value.
401 const BluetoothGattService* included = *iter;
402 linked_ptr<apibtle::Service> api_service(new apibtle::Service());
403 PopulateService(included, api_service.get());
404
405 out_services->push_back(api_service);
406 }
407
408 return kStatusSuccess;
409 }
410
411 BluetoothLowEnergyEventRouter::Status
GetCharacteristics(const Extension * extension,const std::string & instance_id,CharacteristicList * out_characteristics) const412 BluetoothLowEnergyEventRouter::GetCharacteristics(
413 const Extension* extension,
414 const std::string& instance_id,
415 CharacteristicList* out_characteristics) const {
416 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
417 DCHECK(extension);
418 DCHECK(out_characteristics);
419 if (!adapter_) {
420 VLOG(1) << "BlutoothAdapter not ready.";
421 return kStatusErrorFailed;
422 }
423
424 BluetoothGattService* service = FindServiceById(instance_id);
425 if (!service) {
426 VLOG(1) << "Service not found: " << instance_id;
427 return kStatusErrorNotFound;
428 }
429
430 BluetoothPermissionRequest request(service->GetUUID().value());
431 if (!BluetoothManifestData::CheckRequest(extension, request)) {
432 VLOG(1) << "App has no permission to access the characteristics of this "
433 << "service: " << instance_id;
434 return kStatusErrorPermissionDenied;
435 }
436
437 out_characteristics->clear();
438
439 const std::vector<BluetoothGattCharacteristic*>& characteristics =
440 service->GetCharacteristics();
441 for (std::vector<BluetoothGattCharacteristic*>::const_iterator iter =
442 characteristics.begin();
443 iter != characteristics.end();
444 ++iter) {
445 // Populate an API characteristic and add it to the return value.
446 const BluetoothGattCharacteristic* characteristic = *iter;
447 linked_ptr<apibtle::Characteristic> api_characteristic(
448 new apibtle::Characteristic());
449 PopulateCharacteristic(characteristic, api_characteristic.get());
450
451 out_characteristics->push_back(api_characteristic);
452 }
453
454 return kStatusSuccess;
455 }
456
457 BluetoothLowEnergyEventRouter::Status
GetCharacteristic(const Extension * extension,const std::string & instance_id,apibtle::Characteristic * out_characteristic) const458 BluetoothLowEnergyEventRouter::GetCharacteristic(
459 const Extension* extension,
460 const std::string& instance_id,
461 apibtle::Characteristic* out_characteristic) const {
462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
463 DCHECK(extension);
464 DCHECK(out_characteristic);
465 if (!adapter_) {
466 VLOG(1) << "BluetoothAdapter not ready.";
467 return kStatusErrorFailed;
468 }
469
470 BluetoothGattCharacteristic* characteristic =
471 FindCharacteristicById(instance_id);
472 if (!characteristic) {
473 VLOG(1) << "Characteristic not found: " << instance_id;
474 return kStatusErrorNotFound;
475 }
476
477 BluetoothPermissionRequest request(
478 characteristic->GetService()->GetUUID().value());
479 if (!BluetoothManifestData::CheckRequest(extension, request)) {
480 VLOG(1) << "App has no permission to access this characteristic: "
481 << instance_id;
482 return kStatusErrorPermissionDenied;
483 }
484
485 PopulateCharacteristic(characteristic, out_characteristic);
486 return kStatusSuccess;
487 }
488
489 BluetoothLowEnergyEventRouter::Status
GetDescriptors(const Extension * extension,const std::string & instance_id,DescriptorList * out_descriptors) const490 BluetoothLowEnergyEventRouter::GetDescriptors(
491 const Extension* extension,
492 const std::string& instance_id,
493 DescriptorList* out_descriptors) const {
494 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
495 DCHECK(extension);
496 DCHECK(out_descriptors);
497 if (!adapter_) {
498 VLOG(1) << "BlutoothAdapter not ready.";
499 return kStatusErrorFailed;
500 }
501
502 BluetoothGattCharacteristic* characteristic =
503 FindCharacteristicById(instance_id);
504 if (!characteristic) {
505 VLOG(1) << "Characteristic not found: " << instance_id;
506 return kStatusErrorNotFound;
507 }
508
509 BluetoothPermissionRequest request(
510 characteristic->GetService()->GetUUID().value());
511 if (!BluetoothManifestData::CheckRequest(extension, request)) {
512 VLOG(1) << "App has no permission to access the descriptors of this "
513 << "characteristic: " << instance_id;
514 return kStatusErrorPermissionDenied;
515 }
516
517 out_descriptors->clear();
518
519 const std::vector<BluetoothGattDescriptor*>& descriptors =
520 characteristic->GetDescriptors();
521 for (std::vector<BluetoothGattDescriptor*>::const_iterator iter =
522 descriptors.begin();
523 iter != descriptors.end();
524 ++iter) {
525 // Populate an API descriptor and add it to the return value.
526 const BluetoothGattDescriptor* descriptor = *iter;
527 linked_ptr<apibtle::Descriptor> api_descriptor(new apibtle::Descriptor());
528 PopulateDescriptor(descriptor, api_descriptor.get());
529
530 out_descriptors->push_back(api_descriptor);
531 }
532
533 return kStatusSuccess;
534 }
535
536 BluetoothLowEnergyEventRouter::Status
GetDescriptor(const Extension * extension,const std::string & instance_id,api::bluetooth_low_energy::Descriptor * out_descriptor) const537 BluetoothLowEnergyEventRouter::GetDescriptor(
538 const Extension* extension,
539 const std::string& instance_id,
540 api::bluetooth_low_energy::Descriptor* out_descriptor) const {
541 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
542 DCHECK(extension);
543 DCHECK(out_descriptor);
544 if (!adapter_) {
545 VLOG(1) << "BluetoothAdapter not ready.";
546 return kStatusErrorFailed;
547 }
548
549 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
550 if (!descriptor) {
551 VLOG(1) << "Descriptor not found: " << instance_id;
552 return kStatusErrorNotFound;
553 }
554
555 BluetoothPermissionRequest request(
556 descriptor->GetCharacteristic()->GetService()->GetUUID().value());
557 if (!BluetoothManifestData::CheckRequest(extension, request)) {
558 VLOG(1) << "App has no permission to access this descriptor: "
559 << instance_id;
560 return kStatusErrorPermissionDenied;
561 }
562
563 PopulateDescriptor(descriptor, out_descriptor);
564 return kStatusSuccess;
565 }
566
ReadCharacteristicValue(const Extension * extension,const std::string & instance_id,const base::Closure & callback,const ErrorCallback & error_callback)567 void BluetoothLowEnergyEventRouter::ReadCharacteristicValue(
568 const Extension* extension,
569 const std::string& instance_id,
570 const base::Closure& callback,
571 const ErrorCallback& error_callback) {
572 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
573 DCHECK(extension);
574 if (!adapter_) {
575 VLOG(1) << "BluetoothAdapter not ready.";
576 error_callback.Run(kStatusErrorFailed);
577 return;
578 }
579
580 BluetoothGattCharacteristic* characteristic =
581 FindCharacteristicById(instance_id);
582 if (!characteristic) {
583 VLOG(1) << "Characteristic not found: " << instance_id;
584 error_callback.Run(kStatusErrorNotFound);
585 return;
586 }
587
588 BluetoothPermissionRequest request(
589 characteristic->GetService()->GetUUID().value());
590 if (!BluetoothManifestData::CheckRequest(extension, request)) {
591 VLOG(1) << "App has no permission to access this characteristic: "
592 << instance_id;
593 error_callback.Run(kStatusErrorPermissionDenied);
594 return;
595 }
596
597 characteristic->ReadRemoteCharacteristic(
598 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
599 weak_ptr_factory_.GetWeakPtr(),
600 callback),
601 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
602 weak_ptr_factory_.GetWeakPtr(),
603 error_callback));
604 }
605
WriteCharacteristicValue(const Extension * extension,const std::string & instance_id,const std::vector<uint8> & value,const base::Closure & callback,const ErrorCallback & error_callback)606 void BluetoothLowEnergyEventRouter::WriteCharacteristicValue(
607 const Extension* extension,
608 const std::string& instance_id,
609 const std::vector<uint8>& value,
610 const base::Closure& callback,
611 const ErrorCallback& error_callback) {
612 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
613 DCHECK(extension);
614 if (!adapter_) {
615 VLOG(1) << "BluetoothAdapter not ready.";
616 error_callback.Run(kStatusErrorFailed);
617 return;
618 }
619
620 BluetoothGattCharacteristic* characteristic =
621 FindCharacteristicById(instance_id);
622 if (!characteristic) {
623 VLOG(1) << "Characteristic not found: " << instance_id;
624 error_callback.Run(kStatusErrorNotFound);
625 return;
626 }
627
628 BluetoothPermissionRequest request(
629 characteristic->GetService()->GetUUID().value());
630 if (!BluetoothManifestData::CheckRequest(extension, request)) {
631 VLOG(1) << "App has no permission to access this characteristic: "
632 << instance_id;
633 error_callback.Run(kStatusErrorPermissionDenied);
634 return;
635 }
636
637 characteristic->WriteRemoteCharacteristic(
638 value,
639 callback,
640 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
641 weak_ptr_factory_.GetWeakPtr(),
642 error_callback));
643 }
644
StartCharacteristicNotifications(bool persistent,const Extension * extension,const std::string & instance_id,const base::Closure & callback,const ErrorCallback & error_callback)645 void BluetoothLowEnergyEventRouter::StartCharacteristicNotifications(
646 bool persistent,
647 const Extension* extension,
648 const std::string& instance_id,
649 const base::Closure& callback,
650 const ErrorCallback& error_callback) {
651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
652 if (!adapter_) {
653 VLOG(1) << "BluetoothAdapter not ready.";
654 error_callback.Run(kStatusErrorFailed);
655 return;
656 }
657
658 const std::string extension_id = extension->id();
659 const std::string session_id = extension_id + instance_id;
660
661 if (pending_session_calls_.count(session_id) != 0) {
662 error_callback.Run(kStatusErrorInProgress);
663 return;
664 }
665
666 BluetoothLowEnergyNotifySession* session =
667 FindNotifySession(extension_id, instance_id);
668 if (session) {
669 if (session->GetSession()->IsActive()) {
670 VLOG(1) << "Application has already enabled notifications from "
671 << "characteristic: " << instance_id;
672 error_callback.Run(kStatusErrorAlreadyNotifying);
673 return;
674 }
675
676 RemoveNotifySession(extension_id, instance_id);
677 }
678
679 BluetoothGattCharacteristic* characteristic =
680 FindCharacteristicById(instance_id);
681 if (!characteristic) {
682 VLOG(1) << "Characteristic not found: " << instance_id;
683 error_callback.Run(kStatusErrorNotFound);
684 return;
685 }
686
687 BluetoothPermissionRequest request(
688 characteristic->GetService()->GetUUID().value());
689 if (!BluetoothManifestData::CheckRequest(extension, request)) {
690 VLOG(1) << "App has no permission to access this characteristic: "
691 << instance_id;
692 error_callback.Run(kStatusErrorPermissionDenied);
693 return;
694 }
695
696 pending_session_calls_.insert(session_id);
697 characteristic->StartNotifySession(
698 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySession,
699 weak_ptr_factory_.GetWeakPtr(),
700 persistent,
701 extension_id,
702 instance_id,
703 callback),
704 base::Bind(&BluetoothLowEnergyEventRouter::OnStartNotifySessionError,
705 weak_ptr_factory_.GetWeakPtr(),
706 extension_id,
707 instance_id,
708 error_callback));
709 }
710
StopCharacteristicNotifications(const Extension * extension,const std::string & instance_id,const base::Closure & callback,const ErrorCallback & error_callback)711 void BluetoothLowEnergyEventRouter::StopCharacteristicNotifications(
712 const Extension* extension,
713 const std::string& instance_id,
714 const base::Closure& callback,
715 const ErrorCallback& error_callback) {
716 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
717 if (!adapter_) {
718 VLOG(1) << "BluetoothAdapter not ready.";
719 error_callback.Run(kStatusErrorFailed);
720 return;
721 }
722
723 const std::string extension_id = extension->id();
724
725 BluetoothLowEnergyNotifySession* session =
726 FindNotifySession(extension_id, instance_id);
727 if (!session || !session->GetSession()->IsActive()) {
728 VLOG(1) << "Application has not enabled notifications from "
729 << "characteristic: " << instance_id;
730 error_callback.Run(kStatusErrorNotNotifying);
731 return;
732 }
733
734 session->GetSession()->Stop(
735 base::Bind(&BluetoothLowEnergyEventRouter::OnStopNotifySession,
736 weak_ptr_factory_.GetWeakPtr(),
737 extension_id,
738 instance_id,
739 callback));
740 }
741
ReadDescriptorValue(const Extension * extension,const std::string & instance_id,const base::Closure & callback,const ErrorCallback & error_callback)742 void BluetoothLowEnergyEventRouter::ReadDescriptorValue(
743 const Extension* extension,
744 const std::string& instance_id,
745 const base::Closure& callback,
746 const ErrorCallback& error_callback) {
747 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
748 DCHECK(extension);
749 if (!adapter_) {
750 VLOG(1) << "BluetoothAdapter not ready.";
751 error_callback.Run(kStatusErrorFailed);
752 return;
753 }
754
755 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
756 if (!descriptor) {
757 VLOG(1) << "Descriptor not found: " << instance_id;
758 error_callback.Run(kStatusErrorNotFound);
759 return;
760 }
761
762 BluetoothPermissionRequest request(
763 descriptor->GetCharacteristic()->GetService()->GetUUID().value());
764 if (!BluetoothManifestData::CheckRequest(extension, request)) {
765 VLOG(1) << "App has no permission to access this descriptor: "
766 << instance_id;
767 error_callback.Run(kStatusErrorPermissionDenied);
768 return;
769 }
770
771 descriptor->ReadRemoteDescriptor(
772 base::Bind(&BluetoothLowEnergyEventRouter::OnValueSuccess,
773 weak_ptr_factory_.GetWeakPtr(),
774 callback),
775 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
776 weak_ptr_factory_.GetWeakPtr(),
777 error_callback));
778 }
779
WriteDescriptorValue(const Extension * extension,const std::string & instance_id,const std::vector<uint8> & value,const base::Closure & callback,const ErrorCallback & error_callback)780 void BluetoothLowEnergyEventRouter::WriteDescriptorValue(
781 const Extension* extension,
782 const std::string& instance_id,
783 const std::vector<uint8>& value,
784 const base::Closure& callback,
785 const ErrorCallback& error_callback) {
786 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
787 DCHECK(extension);
788 if (!adapter_) {
789 VLOG(1) << "BluetoothAdapter not ready.";
790 error_callback.Run(kStatusErrorFailed);
791 return;
792 }
793
794 BluetoothGattDescriptor* descriptor = FindDescriptorById(instance_id);
795 if (!descriptor) {
796 VLOG(1) << "Descriptor not found: " << instance_id;
797 error_callback.Run(kStatusErrorNotFound);
798 return;
799 }
800
801 BluetoothPermissionRequest request(
802 descriptor->GetCharacteristic()->GetService()->GetUUID().value());
803 if (!BluetoothManifestData::CheckRequest(extension, request)) {
804 VLOG(1) << "App has no permission to access this descriptor: "
805 << instance_id;
806 error_callback.Run(kStatusErrorPermissionDenied);
807 return;
808 }
809
810 descriptor->WriteRemoteDescriptor(
811 value,
812 callback,
813 base::Bind(&BluetoothLowEnergyEventRouter::OnError,
814 weak_ptr_factory_.GetWeakPtr(),
815 error_callback));
816 }
817
SetAdapterForTesting(device::BluetoothAdapter * adapter)818 void BluetoothLowEnergyEventRouter::SetAdapterForTesting(
819 device::BluetoothAdapter* adapter) {
820 adapter_ = adapter;
821 InitializeIdentifierMappings();
822 }
823
DeviceAdded(BluetoothAdapter * adapter,BluetoothDevice * device)824 void BluetoothLowEnergyEventRouter::DeviceAdded(BluetoothAdapter* adapter,
825 BluetoothDevice* device) {
826 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
827 DCHECK(observed_devices_.find(device->GetAddress()) ==
828 observed_devices_.end());
829 device->AddObserver(this);
830 observed_devices_.insert(device->GetAddress());
831 }
832
DeviceRemoved(BluetoothAdapter * adapter,BluetoothDevice * device)833 void BluetoothLowEnergyEventRouter::DeviceRemoved(BluetoothAdapter* adapter,
834 BluetoothDevice* device) {
835 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
836 DCHECK(observed_devices_.find(device->GetAddress()) !=
837 observed_devices_.end());
838 device->RemoveObserver(this);
839 observed_devices_.erase(device->GetAddress());
840 }
841
GattServiceAdded(BluetoothDevice * device,BluetoothGattService * service)842 void BluetoothLowEnergyEventRouter::GattServiceAdded(
843 BluetoothDevice* device,
844 BluetoothGattService* service) {
845 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
846 VLOG(2) << "GATT service added: " << service->GetIdentifier();
847
848 DCHECK(observed_gatt_services_.find(service->GetIdentifier()) ==
849 observed_gatt_services_.end());
850 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) ==
851 service_id_to_device_address_.end());
852
853 service->AddObserver(this);
854
855 const std::string& service_id = service->GetIdentifier();
856 observed_gatt_services_.insert(service_id);
857 service_id_to_device_address_[service_id] = device->GetAddress();
858
859 // Signal API event.
860 apibtle::Service api_service;
861 PopulateService(service, &api_service);
862
863 scoped_ptr<base::ListValue> args =
864 apibtle::OnServiceAdded::Create(api_service);
865 scoped_ptr<Event> event(
866 new Event(apibtle::OnServiceAdded::kEventName, args.Pass()));
867 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
868 }
869
GattServiceRemoved(BluetoothDevice * device,BluetoothGattService * service)870 void BluetoothLowEnergyEventRouter::GattServiceRemoved(
871 BluetoothDevice* device,
872 BluetoothGattService* service) {
873 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
874 VLOG(2) << "GATT service removed: " << service->GetIdentifier();
875
876 DCHECK(observed_gatt_services_.find(service->GetIdentifier()) !=
877 observed_gatt_services_.end());
878 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
879 service_id_to_device_address_.end());
880
881 service->RemoveObserver(this);
882 observed_gatt_services_.erase(service->GetIdentifier());
883
884 DCHECK(device->GetAddress() ==
885 service_id_to_device_address_[service->GetIdentifier()]);
886 service_id_to_device_address_.erase(service->GetIdentifier());
887
888 // Signal API event.
889 apibtle::Service api_service;
890 PopulateService(service, &api_service);
891
892 scoped_ptr<base::ListValue> args =
893 apibtle::OnServiceRemoved::Create(api_service);
894 scoped_ptr<Event> event(
895 new Event(apibtle::OnServiceRemoved::kEventName, args.Pass()));
896 EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
897 }
898
GattServiceChanged(BluetoothGattService * service)899 void BluetoothLowEnergyEventRouter::GattServiceChanged(
900 BluetoothGattService* service) {
901 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
902 VLOG(2) << "GATT service changed: " << service->GetIdentifier();
903
904 DCHECK(observed_gatt_services_.find(service->GetIdentifier()) !=
905 observed_gatt_services_.end());
906 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
907 service_id_to_device_address_.end());
908
909 // Signal API event.
910 apibtle::Service api_service;
911 PopulateService(service, &api_service);
912
913 DispatchEventToExtensionsWithPermission(
914 apibtle::OnServiceChanged::kEventName,
915 service->GetUUID(),
916 "" /* characteristic_id */,
917 apibtle::OnServiceChanged::Create(api_service));
918 }
919
GattCharacteristicAdded(BluetoothGattService * service,BluetoothGattCharacteristic * characteristic)920 void BluetoothLowEnergyEventRouter::GattCharacteristicAdded(
921 BluetoothGattService* service,
922 BluetoothGattCharacteristic* characteristic) {
923 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
924 VLOG(2) << "GATT characteristic added: " << characteristic->GetIdentifier();
925
926 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) ==
927 chrc_id_to_service_id_.end());
928 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
929 service_id_to_device_address_.end());
930
931 chrc_id_to_service_id_[characteristic->GetIdentifier()] =
932 service->GetIdentifier();
933 }
934
GattCharacteristicRemoved(BluetoothGattService * service,BluetoothGattCharacteristic * characteristic)935 void BluetoothLowEnergyEventRouter::GattCharacteristicRemoved(
936 BluetoothGattService* service,
937 BluetoothGattCharacteristic* characteristic) {
938 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
939 VLOG(2) << "GATT characteristic removed: " << characteristic->GetIdentifier();
940
941 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
942 chrc_id_to_service_id_.end());
943 DCHECK(service->GetIdentifier() ==
944 chrc_id_to_service_id_[characteristic->GetIdentifier()]);
945
946 chrc_id_to_service_id_.erase(characteristic->GetIdentifier());
947 }
948
GattDescriptorAdded(BluetoothGattCharacteristic * characteristic,BluetoothGattDescriptor * descriptor)949 void BluetoothLowEnergyEventRouter::GattDescriptorAdded(
950 BluetoothGattCharacteristic* characteristic,
951 BluetoothGattDescriptor* descriptor) {
952 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
953 VLOG(2) << "GATT descriptor added: " << descriptor->GetIdentifier();
954
955 DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) ==
956 desc_id_to_chrc_id_.end());
957 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
958 chrc_id_to_service_id_.end());
959
960 desc_id_to_chrc_id_[descriptor->GetIdentifier()] =
961 characteristic->GetIdentifier();
962 }
963
GattDescriptorRemoved(BluetoothGattCharacteristic * characteristic,BluetoothGattDescriptor * descriptor)964 void BluetoothLowEnergyEventRouter::GattDescriptorRemoved(
965 BluetoothGattCharacteristic* characteristic,
966 BluetoothGattDescriptor* descriptor) {
967 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
968 VLOG(2) << "GATT descriptor removed: " << descriptor->GetIdentifier();
969
970 DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) !=
971 desc_id_to_chrc_id_.end());
972 DCHECK(characteristic->GetIdentifier() ==
973 desc_id_to_chrc_id_[descriptor->GetIdentifier()]);
974
975 desc_id_to_chrc_id_.erase(descriptor->GetIdentifier());
976 }
977
GattCharacteristicValueChanged(BluetoothGattService * service,BluetoothGattCharacteristic * characteristic,const std::vector<uint8> & value)978 void BluetoothLowEnergyEventRouter::GattCharacteristicValueChanged(
979 BluetoothGattService* service,
980 BluetoothGattCharacteristic* characteristic,
981 const std::vector<uint8>& value) {
982 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
983 VLOG(2) << "GATT characteristic value changed: "
984 << characteristic->GetIdentifier();
985
986 DCHECK(observed_gatt_services_.find(service->GetIdentifier()) !=
987 observed_gatt_services_.end());
988 DCHECK(service_id_to_device_address_.find(service->GetIdentifier()) !=
989 service_id_to_device_address_.end());
990 DCHECK(chrc_id_to_service_id_.find(characteristic->GetIdentifier()) !=
991 chrc_id_to_service_id_.end());
992 DCHECK(chrc_id_to_service_id_[characteristic->GetIdentifier()] ==
993 service->GetIdentifier());
994
995 // Send the event; manually construct the arguments, instead of using
996 // apibtle::OnCharacteristicValueChanged::Create, as it doesn't convert
997 // lists of enums correctly.
998 apibtle::Characteristic api_characteristic;
999 PopulateCharacteristic(characteristic, &api_characteristic);
1000 scoped_ptr<base::ListValue> args(new base::ListValue());
1001 args->Append(apibtle::CharacteristicToValue(&api_characteristic).release());
1002
1003 DispatchEventToExtensionsWithPermission(
1004 apibtle::OnCharacteristicValueChanged::kEventName,
1005 service->GetUUID(),
1006 characteristic->GetIdentifier(),
1007 args.Pass());
1008 }
1009
GattDescriptorValueChanged(BluetoothGattCharacteristic * characteristic,BluetoothGattDescriptor * descriptor,const std::vector<uint8> & value)1010 void BluetoothLowEnergyEventRouter::GattDescriptorValueChanged(
1011 BluetoothGattCharacteristic* characteristic,
1012 BluetoothGattDescriptor* descriptor,
1013 const std::vector<uint8>& value) {
1014 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1015 VLOG(2) << "GATT descriptor value changed: " << descriptor->GetIdentifier();
1016
1017 DCHECK(desc_id_to_chrc_id_.find(descriptor->GetIdentifier()) !=
1018 desc_id_to_chrc_id_.end());
1019 DCHECK(characteristic->GetIdentifier() ==
1020 desc_id_to_chrc_id_[descriptor->GetIdentifier()]);
1021
1022 // Send the event; manually construct the arguments, instead of using
1023 // apibtle::OnDescriptorValueChanged::Create, as it doesn't convert
1024 // lists of enums correctly.
1025 apibtle::Descriptor api_descriptor;
1026 PopulateDescriptor(descriptor, &api_descriptor);
1027 scoped_ptr<base::ListValue> args(new base::ListValue());
1028 args->Append(apibtle::DescriptorToValue(&api_descriptor).release());
1029
1030 DispatchEventToExtensionsWithPermission(
1031 apibtle::OnDescriptorValueChanged::kEventName,
1032 characteristic->GetService()->GetUUID(),
1033 "" /* characteristic_id */,
1034 args.Pass());
1035 }
1036
OnGetAdapter(const base::Closure & callback,scoped_refptr<device::BluetoothAdapter> adapter)1037 void BluetoothLowEnergyEventRouter::OnGetAdapter(
1038 const base::Closure& callback,
1039 scoped_refptr<device::BluetoothAdapter> adapter) {
1040 adapter_ = adapter;
1041
1042 // Initialize instance ID mappings for all discovered GATT objects and add
1043 // observers.
1044 InitializeIdentifierMappings();
1045 adapter_->AddObserver(this);
1046
1047 callback.Run();
1048 }
1049
InitializeIdentifierMappings()1050 void BluetoothLowEnergyEventRouter::InitializeIdentifierMappings() {
1051 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1052 DCHECK(service_id_to_device_address_.empty());
1053 DCHECK(chrc_id_to_service_id_.empty());
1054 DCHECK(observed_devices_.empty());
1055 DCHECK(observed_gatt_services_.empty());
1056
1057 // Devices
1058 BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
1059 for (BluetoothAdapter::DeviceList::iterator iter = devices.begin();
1060 iter != devices.end();
1061 ++iter) {
1062 BluetoothDevice* device = *iter;
1063 device->AddObserver(this);
1064 observed_devices_.insert(device->GetAddress());
1065
1066 // Services
1067 std::vector<BluetoothGattService*> services = device->GetGattServices();
1068 for (std::vector<BluetoothGattService*>::iterator siter = services.begin();
1069 siter != services.end();
1070 ++siter) {
1071 BluetoothGattService* service = *siter;
1072 service->AddObserver(this);
1073
1074 const std::string& service_id = service->GetIdentifier();
1075 observed_gatt_services_.insert(service_id);
1076 service_id_to_device_address_[service_id] = device->GetAddress();
1077
1078 // Characteristics
1079 const std::vector<BluetoothGattCharacteristic*>& characteristics =
1080 service->GetCharacteristics();
1081 for (std::vector<BluetoothGattCharacteristic*>::const_iterator citer =
1082 characteristics.begin();
1083 citer != characteristics.end();
1084 ++citer) {
1085 BluetoothGattCharacteristic* characteristic = *citer;
1086
1087 const std::string& chrc_id = characteristic->GetIdentifier();
1088 chrc_id_to_service_id_[chrc_id] = service_id;
1089
1090 // Descriptors
1091 const std::vector<BluetoothGattDescriptor*>& descriptors =
1092 characteristic->GetDescriptors();
1093 for (std::vector<BluetoothGattDescriptor*>::const_iterator diter =
1094 descriptors.begin();
1095 diter != descriptors.end();
1096 ++diter) {
1097 BluetoothGattDescriptor* descriptor = *diter;
1098
1099 const std::string& desc_id = descriptor->GetIdentifier();
1100 desc_id_to_chrc_id_[desc_id] = chrc_id;
1101 }
1102 }
1103 }
1104 }
1105 }
1106
DispatchEventToExtensionsWithPermission(const std::string & event_name,const device::BluetoothUUID & uuid,const std::string & characteristic_id,scoped_ptr<base::ListValue> args)1107 void BluetoothLowEnergyEventRouter::DispatchEventToExtensionsWithPermission(
1108 const std::string& event_name,
1109 const device::BluetoothUUID& uuid,
1110 const std::string& characteristic_id,
1111 scoped_ptr<base::ListValue> args) {
1112 // Obtain the listeners of |event_name|. The list can contain multiple
1113 // entries for the same extension, so we keep track of the extensions that we
1114 // already sent the event to, since we want the send an event to an extension
1115 // only once.
1116 BluetoothPermissionRequest request(uuid.value());
1117 std::set<std::string> handled_extensions;
1118 const EventListenerMap::ListenerList listeners =
1119 EventRouter::Get(browser_context_)->listeners().GetEventListenersByName(
1120 event_name);
1121
1122 for (EventListenerMap::ListenerList::const_iterator iter = listeners.begin();
1123 iter != listeners.end();
1124 ++iter) {
1125 const std::string extension_id = (*iter)->extension_id();
1126 if (handled_extensions.find(extension_id) != handled_extensions.end())
1127 continue;
1128
1129 handled_extensions.insert(extension_id);
1130
1131 const Extension* extension =
1132 ExtensionRegistry::Get(browser_context_)
1133 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
1134
1135 // For all API methods, the "low_energy" permission check is handled by
1136 // BluetoothLowEnergyExtensionFunction but for events we have to do the
1137 // check here.
1138 if (!BluetoothManifestData::CheckRequest(extension, request) ||
1139 !BluetoothManifestData::CheckLowEnergyPermitted(extension))
1140 continue;
1141
1142 // If |event_name| is "onCharacteristicValueChanged", then send the
1143 // event only if the extension has requested notifications from the
1144 // related characteristic.
1145 if (event_name == apibtle::OnCharacteristicValueChanged::kEventName &&
1146 !characteristic_id.empty() &&
1147 !FindNotifySession(extension_id, characteristic_id))
1148 continue;
1149
1150 // Send the event.
1151 scoped_ptr<base::ListValue> args_copy(args->DeepCopy());
1152 scoped_ptr<Event> event(new Event(event_name, args_copy.Pass()));
1153 EventRouter::Get(browser_context_)->DispatchEventToExtension(
1154 extension_id, event.Pass());
1155 }
1156 }
1157
FindServiceById(const std::string & instance_id) const1158 BluetoothGattService* BluetoothLowEnergyEventRouter::FindServiceById(
1159 const std::string& instance_id) const {
1160 InstanceIdMap::const_iterator iter =
1161 service_id_to_device_address_.find(instance_id);
1162 if (iter == service_id_to_device_address_.end()) {
1163 VLOG(1) << "GATT service identifier unknown: " << instance_id;
1164 return NULL;
1165 }
1166
1167 const std::string& address = iter->second;
1168
1169 BluetoothDevice* device = adapter_->GetDevice(address);
1170 if (!device) {
1171 VLOG(1) << "Bluetooth device not found: " << address;
1172 return NULL;
1173 }
1174
1175 BluetoothGattService* service = device->GetGattService(instance_id);
1176 if (!service) {
1177 VLOG(1) << "GATT service with ID \"" << instance_id
1178 << "\" not found on device \"" << address << "\"";
1179 return NULL;
1180 }
1181
1182 return service;
1183 }
1184
1185 BluetoothGattCharacteristic*
FindCharacteristicById(const std::string & instance_id) const1186 BluetoothLowEnergyEventRouter::FindCharacteristicById(
1187 const std::string& instance_id) const {
1188 InstanceIdMap::const_iterator iter = chrc_id_to_service_id_.find(instance_id);
1189 if (iter == chrc_id_to_service_id_.end()) {
1190 VLOG(1) << "GATT characteristic identifier unknown: " << instance_id;
1191 return NULL;
1192 }
1193
1194 const std::string& service_id = iter->second;
1195
1196 BluetoothGattService* service = FindServiceById(service_id);
1197 if (!service) {
1198 VLOG(1) << "Failed to obtain service for characteristic: " << instance_id;
1199 return NULL;
1200 }
1201
1202 BluetoothGattCharacteristic* characteristic =
1203 service->GetCharacteristic(instance_id);
1204 if (!characteristic) {
1205 VLOG(1) << "GATT characteristic with ID \"" << instance_id
1206 << "\" not found on service \"" << service_id << "\"";
1207 return NULL;
1208 }
1209
1210 return characteristic;
1211 }
1212
FindDescriptorById(const std::string & instance_id) const1213 BluetoothGattDescriptor* BluetoothLowEnergyEventRouter::FindDescriptorById(
1214 const std::string& instance_id) const {
1215 InstanceIdMap::const_iterator iter = desc_id_to_chrc_id_.find(instance_id);
1216 if (iter == desc_id_to_chrc_id_.end()) {
1217 VLOG(1) << "GATT descriptor identifier unknown: " << instance_id;
1218 return NULL;
1219 }
1220
1221 const std::string& chrc_id = iter->second;
1222 BluetoothGattCharacteristic* chrc = FindCharacteristicById(chrc_id);
1223 if (!chrc) {
1224 VLOG(1) << "Failed to obtain characteristic for descriptor: "
1225 << instance_id;
1226 return NULL;
1227 }
1228
1229 BluetoothGattDescriptor* descriptor = chrc->GetDescriptor(instance_id);
1230 if (!descriptor) {
1231 VLOG(1) << "GATT descriptor with ID \"" << instance_id
1232 << "\" not found on characteristic \"" << chrc_id << "\"";
1233 return NULL;
1234 }
1235
1236 return descriptor;
1237 }
1238
OnValueSuccess(const base::Closure & callback,const std::vector<uint8> & value)1239 void BluetoothLowEnergyEventRouter::OnValueSuccess(
1240 const base::Closure& callback,
1241 const std::vector<uint8>& value) {
1242 VLOG(2) << "Remote characteristic/descriptor value read successful.";
1243 callback.Run();
1244 }
1245
OnCreateGattConnection(bool persistent,const std::string & extension_id,const std::string & device_address,const base::Closure & callback,scoped_ptr<BluetoothGattConnection> connection)1246 void BluetoothLowEnergyEventRouter::OnCreateGattConnection(
1247 bool persistent,
1248 const std::string& extension_id,
1249 const std::string& device_address,
1250 const base::Closure& callback,
1251 scoped_ptr<BluetoothGattConnection> connection) {
1252 VLOG(2) << "GATT connection created.";
1253 DCHECK(connection.get());
1254 DCHECK(!FindConnection(extension_id, device_address));
1255 DCHECK_EQ(device_address, connection->GetDeviceAddress());
1256
1257 const std::string connect_id = extension_id + device_address;
1258 DCHECK_NE(0U, connecting_devices_.count(connect_id));
1259
1260 BluetoothLowEnergyConnection* conn = new BluetoothLowEnergyConnection(
1261 persistent, extension_id, connection.Pass());
1262 ConnectionResourceManager* manager =
1263 GetConnectionResourceManager(browser_context_);
1264 manager->Add(conn);
1265
1266 connecting_devices_.erase(connect_id);
1267 callback.Run();
1268 }
1269
OnDisconnect(const std::string & extension_id,const std::string & device_address,const base::Closure & callback)1270 void BluetoothLowEnergyEventRouter::OnDisconnect(
1271 const std::string& extension_id,
1272 const std::string& device_address,
1273 const base::Closure& callback) {
1274 VLOG(2) << "GATT connection terminated.";
1275
1276 const std::string disconnect_id = extension_id + device_address;
1277 DCHECK_NE(0U, disconnecting_devices_.count(disconnect_id));
1278
1279 if (!RemoveConnection(extension_id, device_address)) {
1280 VLOG(1) << "The connection was removed before disconnect completed, id: "
1281 << extension_id << ", device: " << device_address;
1282 }
1283
1284 disconnecting_devices_.erase(disconnect_id);
1285 callback.Run();
1286 }
1287
OnError(const ErrorCallback & error_callback)1288 void BluetoothLowEnergyEventRouter::OnError(
1289 const ErrorCallback& error_callback) {
1290 VLOG(2) << "Remote characteristic/descriptor value read/write failed.";
1291 error_callback.Run(kStatusErrorFailed);
1292 }
1293
OnConnectError(const std::string & extension_id,const std::string & device_address,const ErrorCallback & error_callback,BluetoothDevice::ConnectErrorCode error_code)1294 void BluetoothLowEnergyEventRouter::OnConnectError(
1295 const std::string& extension_id,
1296 const std::string& device_address,
1297 const ErrorCallback& error_callback,
1298 BluetoothDevice::ConnectErrorCode error_code) {
1299 VLOG(2) << "Failed to create GATT connection: " << error_code;
1300
1301 const std::string connect_id = extension_id + device_address;
1302 DCHECK_NE(0U, connecting_devices_.count(connect_id));
1303
1304 connecting_devices_.erase(connect_id);
1305 error_callback.Run(kStatusErrorFailed);
1306 }
1307
OnStartNotifySession(bool persistent,const std::string & extension_id,const std::string & characteristic_id,const base::Closure & callback,scoped_ptr<device::BluetoothGattNotifySession> session)1308 void BluetoothLowEnergyEventRouter::OnStartNotifySession(
1309 bool persistent,
1310 const std::string& extension_id,
1311 const std::string& characteristic_id,
1312 const base::Closure& callback,
1313 scoped_ptr<device::BluetoothGattNotifySession> session) {
1314 VLOG(2) << "Value update session created for characteristic: "
1315 << characteristic_id;
1316 DCHECK(session.get());
1317 DCHECK(!FindNotifySession(extension_id, characteristic_id));
1318 DCHECK_EQ(characteristic_id, session->GetCharacteristicIdentifier());
1319
1320 const std::string session_id = extension_id + characteristic_id;
1321 DCHECK_NE(0U, pending_session_calls_.count(session_id));
1322
1323 BluetoothLowEnergyNotifySession* resource =
1324 new BluetoothLowEnergyNotifySession(
1325 persistent, extension_id, session.Pass());
1326
1327 NotifySessionResourceManager* manager =
1328 GetNotifySessionResourceManager(browser_context_);
1329 manager->Add(resource);
1330
1331 pending_session_calls_.erase(session_id);
1332 callback.Run();
1333 }
1334
OnStartNotifySessionError(const std::string & extension_id,const std::string & characteristic_id,const ErrorCallback & error_callback)1335 void BluetoothLowEnergyEventRouter::OnStartNotifySessionError(
1336 const std::string& extension_id,
1337 const std::string& characteristic_id,
1338 const ErrorCallback& error_callback) {
1339 VLOG(2) << "Failed to create value update session for characteristic: "
1340 << characteristic_id;
1341
1342 const std::string session_id = extension_id + characteristic_id;
1343 DCHECK_NE(0U, pending_session_calls_.count(session_id));
1344
1345 pending_session_calls_.erase(session_id);
1346 error_callback.Run(kStatusErrorFailed);
1347 }
1348
OnStopNotifySession(const std::string & extension_id,const std::string & characteristic_id,const base::Closure & callback)1349 void BluetoothLowEnergyEventRouter::OnStopNotifySession(
1350 const std::string& extension_id,
1351 const std::string& characteristic_id,
1352 const base::Closure& callback) {
1353 VLOG(2) << "Value update session terminated.";
1354
1355 if (!RemoveNotifySession(extension_id, characteristic_id)) {
1356 VLOG(1) << "The value update session was removed before Stop completed, "
1357 << "id: " << extension_id
1358 << ", characteristic: " << characteristic_id;
1359 }
1360
1361 callback.Run();
1362 }
1363
FindConnection(const std::string & extension_id,const std::string & device_address)1364 BluetoothLowEnergyConnection* BluetoothLowEnergyEventRouter::FindConnection(
1365 const std::string& extension_id,
1366 const std::string& device_address) {
1367 ConnectionResourceManager* manager =
1368 GetConnectionResourceManager(browser_context_);
1369
1370 base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
1371 if (!connection_ids)
1372 return NULL;
1373
1374 for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
1375 iter != connection_ids->end();
1376 ++iter) {
1377 extensions::BluetoothLowEnergyConnection* conn =
1378 manager->Get(extension_id, *iter);
1379 if (!conn)
1380 continue;
1381
1382 if (conn->GetConnection()->GetDeviceAddress() == device_address)
1383 return conn;
1384 }
1385
1386 return NULL;
1387 }
1388
RemoveConnection(const std::string & extension_id,const std::string & device_address)1389 bool BluetoothLowEnergyEventRouter::RemoveConnection(
1390 const std::string& extension_id,
1391 const std::string& device_address) {
1392 ConnectionResourceManager* manager =
1393 GetConnectionResourceManager(browser_context_);
1394
1395 base::hash_set<int>* connection_ids = manager->GetResourceIds(extension_id);
1396 if (!connection_ids)
1397 return false;
1398
1399 for (base::hash_set<int>::const_iterator iter = connection_ids->begin();
1400 iter != connection_ids->end();
1401 ++iter) {
1402 extensions::BluetoothLowEnergyConnection* conn =
1403 manager->Get(extension_id, *iter);
1404 if (!conn || conn->GetConnection()->GetDeviceAddress() != device_address)
1405 continue;
1406
1407 manager->Remove(extension_id, *iter);
1408 return true;
1409 }
1410
1411 return false;
1412 }
1413
1414 BluetoothLowEnergyNotifySession*
FindNotifySession(const std::string & extension_id,const std::string & characteristic_id)1415 BluetoothLowEnergyEventRouter::FindNotifySession(
1416 const std::string& extension_id,
1417 const std::string& characteristic_id) {
1418 NotifySessionResourceManager* manager =
1419 GetNotifySessionResourceManager(browser_context_);
1420
1421 base::hash_set<int>* ids = manager->GetResourceIds(extension_id);
1422 if (!ids)
1423 return NULL;
1424
1425 for (base::hash_set<int>::const_iterator iter = ids->begin();
1426 iter != ids->end();
1427 ++iter) {
1428 BluetoothLowEnergyNotifySession* session =
1429 manager->Get(extension_id, *iter);
1430 if (!session)
1431 continue;
1432
1433 if (session->GetSession()->GetCharacteristicIdentifier() ==
1434 characteristic_id)
1435 return session;
1436 }
1437
1438 return NULL;
1439 }
1440
RemoveNotifySession(const std::string & extension_id,const std::string & characteristic_id)1441 bool BluetoothLowEnergyEventRouter::RemoveNotifySession(
1442 const std::string& extension_id,
1443 const std::string& characteristic_id) {
1444 NotifySessionResourceManager* manager =
1445 GetNotifySessionResourceManager(browser_context_);
1446
1447 base::hash_set<int>* ids = manager->GetResourceIds(extension_id);
1448 if (!ids)
1449 return false;
1450
1451 for (base::hash_set<int>::const_iterator iter = ids->begin();
1452 iter != ids->end();
1453 ++iter) {
1454 BluetoothLowEnergyNotifySession* session =
1455 manager->Get(extension_id, *iter);
1456 if (!session ||
1457 session->GetSession()->GetCharacteristicIdentifier() !=
1458 characteristic_id)
1459 continue;
1460
1461 manager->Remove(extension_id, *iter);
1462 return true;
1463 }
1464
1465 return false;
1466 }
1467
1468 } // namespace extensions
1469