• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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