Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(671)

Side by Side Diff: chromeos/components/tether/ble_scanner.cc

Issue 2604063003: [CrOS Tether] Create BleScanner, a class which scan BLE advertisements and identifies nearby device… (Closed)
Patch Set: Adjusted comment. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "chromeos/components/tether/ble_scanner.h"
6
7 #include "base/bind.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/strings/string_util.h"
10 #include "chromeos/components/tether/ble_constants.h"
11 #include "components/cryptauth/proto/cryptauth_api.pb.h"
12 #include "components/cryptauth/remote_device.h"
13 #include "components/proximity_auth/logging/logging.h"
14 #include "device/bluetooth/bluetooth_device.h"
15 #include "device/bluetooth/bluetooth_discovery_session.h"
16 #include "device/bluetooth/bluetooth_uuid.h"
17
18 namespace chromeos {
19
20 namespace tether {
21
22 namespace {
23
24 const int kMinDiscoveryRSSI = -90;
Ryan Hansberry 2017/01/04 00:01:03 nit: briefly comment on where this number comes fr
Kyle Horimoto 2017/01/04 18:35:43 Done.
25 const size_t kMinNumBytesInServiceData = 4;
Ryan Hansberry 2017/01/04 00:01:03 nit: make this (2 * cryptauth::EidGenerator::kNumB
Kyle Horimoto 2017/01/04 18:35:43 Done.
26
27 } // namespace
28
29 BleScanner::DelegateImpl::DelegateImpl() {}
30
31 BleScanner::DelegateImpl::~DelegateImpl() {}
32
33 bool BleScanner::DelegateImpl::IsBluetoothAdapterAvailable() const {
34 return device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
35 }
36
37 void BleScanner::DelegateImpl::GetAdapter(
38 const device::BluetoothAdapterFactory::AdapterCallback& callback) {
39 device::BluetoothAdapterFactory::GetAdapter(callback);
40 }
41
42 const std::vector<uint8_t>* BleScanner::DelegateImpl::GetServiceDataForUUID(
43 const device::BluetoothUUID& service_uuid,
44 device::BluetoothDevice* device) {
45 return device->GetServiceDataForUUID(service_uuid);
46 }
47
48 BleScanner::BleScanner(
49 const LocalDeviceDataProvider* local_device_data_provider)
50 : BleScanner(base::MakeUnique<DelegateImpl>(),
51 cryptauth::EidGenerator::GetInstance(),
52 local_device_data_provider) {}
53
54 BleScanner::~BleScanner() {}
55
56 BleScanner::BleScanner(
57 std::unique_ptr<Delegate> delegate,
58 const cryptauth::EidGenerator* eid_generator,
59 const LocalDeviceDataProvider* local_device_data_provider)
60 : delegate_(std::move(delegate)),
61 eid_generator_(eid_generator),
62 local_device_data_provider_(local_device_data_provider),
63 initializing_adapter_(false),
64 initializing_discovery_session_(false),
65 discovery_session_(nullptr),
66 weak_ptr_factory_(this) {}
67
68 bool BleScanner::RegisterScanFilterForDevice(
69 const cryptauth::RemoteDevice& remote_device) {
70 if (!delegate_->IsBluetoothAdapterAvailable()) {
71 PA_LOG(ERROR) << "Bluetooth is not supported on this platform.";
72 return false;
73 }
74
75 if (registered_devices_.size() >= kMaxConcurrentAdvertisements) {
76 // Each scan filter corresponds to an advertisement. Thus, the number of
77 // concurrent advertisements cannot exceed the maximum number of conrurrent
Ryan Hansberry 2017/01/04 00:01:03 concurrent*
Kyle Horimoto 2017/01/04 18:35:43 Done.
78 // advertisements.
79 return false;
80 }
81
82 std::vector<cryptauth::BeaconSeed> local_device_beacon_seeds;
83 if (!local_device_data_provider_->GetLocalDeviceData(
84 nullptr, &local_device_beacon_seeds)) {
85 // If the local device's beacon seeds could not be fetched, a scan filter
86 // cannot be generated.
87 return false;
88 }
89
90 std::unique_ptr<cryptauth::EidGenerator::EidData> scan_filters =
91 eid_generator_->GenerateBackgroundScanFilter(local_device_beacon_seeds);
92 if (!scan_filters) {
93 // If a background scan filter cannot be generated, give up.
94 return false;
95 }
96
97 registered_devices_.push_back(remote_device);
98 UpdateDiscoveryStatus();
99
100 return true;
101 }
102
103 bool BleScanner::UnregisterScanFilterForDevice(
104 const cryptauth::RemoteDevice& device) {
105 for (auto iter = registered_devices_.begin();
106 iter != registered_devices_.end(); iter++) {
Ryan Hansberry 2017/01/04 00:01:03 nit: iterator incrementation should generally be d
Kyle Horimoto 2017/01/04 18:35:43 Done.
107 if (iter->GetDeviceId() == device.GetDeviceId()) {
108 registered_devices_.erase(iter);
109 UpdateDiscoveryStatus();
110 return true;
111 }
112 }
113
114 return false;
115 }
116
117 bool BleScanner::IsDeviceRegistered(const std::string& device_id) {
118 for (auto iter = registered_devices_.begin();
Ryan Hansberry 2017/01/04 00:01:03 super-nit: I find that 'it' is the more common sho
Kyle Horimoto 2017/01/04 18:35:43 Done.
119 iter != registered_devices_.end(); iter++) {
Ryan Hansberry 2017/01/04 00:01:03 Same comment about prefix incrementing.
Kyle Horimoto 2017/01/04 18:35:43 Done.
120 if (iter->GetDeviceId() == device_id) {
121 return true;
122 }
123 }
124
125 return false;
126 }
127
128 void BleScanner::AddObserver(Observer* observer) {
129 observer_list_.AddObserver(observer);
130 }
131
132 void BleScanner::RemoveObserver(Observer* observer) {
133 observer_list_.RemoveObserver(observer);
134 }
135
136 void BleScanner::AdapterPoweredChanged(device::BluetoothAdapter* adapter,
137 bool powered) {
138 DCHECK_EQ(adapter_.get(), adapter);
139 PA_LOG(INFO) << "Adapter power changed. Powered = " << powered;
140 UpdateDiscoveryStatus();
141 }
142
143 void BleScanner::DeviceAdded(device::BluetoothAdapter* adapter,
144 device::BluetoothDevice* device) {
145 DCHECK_EQ(adapter_.get(), adapter);
146 HandleDeviceUpdated(device);
147 }
148
149 void BleScanner::DeviceChanged(device::BluetoothAdapter* adapter,
150 device::BluetoothDevice* device) {
151 DCHECK_EQ(adapter_.get(), adapter);
152 HandleDeviceUpdated(device);
153 }
154
155 void BleScanner::UpdateDiscoveryStatus() {
156 if (registered_devices_.empty()) {
157 StopDiscoverySession();
158 return;
159 }
160
161 if (initializing_adapter_) {
162 return;
163 } else if (!adapter_) {
164 InitializeBluetoothAdapter();
165 return;
166 }
167
168 if (!adapter_->IsPowered()) {
169 // If the adapter has powered off, no devices can be discovered.
170 StopDiscoverySession();
171 return;
172 }
173
174 if (initializing_discovery_session_) {
175 return;
176 } else if (!discovery_session_ ||
177 (discovery_session_ && !discovery_session_->IsActive())) {
178 StartDiscoverySession();
179 }
180 }
181
182 void BleScanner::InitializeBluetoothAdapter() {
183 PA_LOG(INFO) << "Initializing Bluetooth adapter.";
Ryan Hansberry 2017/01/04 00:01:03 Should we be using ProximityAuth logging?
Kyle Horimoto 2017/01/04 18:35:43 For now, yes. We may want to come up with a CrOS T
184 initializing_adapter_ = true;
185 delegate_->GetAdapter(base::Bind(&BleScanner::OnAdapterInitialized,
186 weak_ptr_factory_.GetWeakPtr()));
187 }
188
189 void BleScanner::OnAdapterInitialized(
190 scoped_refptr<device::BluetoothAdapter> adapter) {
191 DCHECK(initializing_adapter_ && !discovery_session_ &&
192 !initializing_discovery_session_);
193 PA_LOG(INFO) << "Bluetooth adapter initialized.";
194 initializing_adapter_ = false;
195
196 adapter_ = adapter;
197 adapter_->AddObserver(this);
198
199 UpdateDiscoveryStatus();
200 }
201
202 void BleScanner::StartDiscoverySession() {
203 DCHECK(adapter_);
204 PA_LOG(INFO) << "Starting discovery session.";
205 initializing_discovery_session_ = true;
206
207 // Discover only low energy (LE) devices with strong enough signal.
208 std::unique_ptr<device::BluetoothDiscoveryFilter> filter =
209 base::MakeUnique<device::BluetoothDiscoveryFilter>(
210 device::BLUETOOTH_TRANSPORT_LE);
211 filter->SetRSSI(kMinDiscoveryRSSI);
212
213 adapter_->StartDiscoverySessionWithFilter(
214 std::move(filter), base::Bind(&BleScanner::OnDiscoverySessionStarted,
Ryan Hansberry 2017/01/04 00:01:03 This needs to be placed on another line (the 2nd a
Kyle Horimoto 2017/01/04 18:35:43 Nope, the Chromium lint tool did this.
215 weak_ptr_factory_.GetWeakPtr()),
216 base::Bind(&BleScanner::OnStartDiscoverySessionError,
217 weak_ptr_factory_.GetWeakPtr()));
218 }
219
220 void BleScanner::OnDiscoverySessionStarted(
221 std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) {
222 PA_LOG(INFO) << "Discovery session started. Scanning fully initialized.";
223 initializing_discovery_session_ = false;
224 discovery_session_ = std::move(discovery_session);
225 }
226
227 void BleScanner::OnStartDiscoverySessionError() {
228 PA_LOG(WARNING) << "Error starting discovery session. Initialization failed.";
229 initializing_discovery_session_ = false;
230 }
231
232 void BleScanner::StopDiscoverySession() {
233 if (!discovery_session_) {
234 // If there is no discovery session to stop, return early.
235 return;
236 }
237
238 PA_LOG(WARNING) << "Stopping discovery session.";
239 discovery_session_.reset();
240 }
241
242 void BleScanner::HandleDeviceUpdated(device::BluetoothDevice* device) {
243 DCHECK(device);
244
245 const std::vector<uint8_t>* service_data = delegate_->GetServiceDataForUUID(
246 device::BluetoothUUID(kAdvertisingServiceUuid), device);
247 if (!service_data || service_data->size() < kMinNumBytesInServiceData) {
248 // If there is no service data or the service data is of insufficient
249 // length, there is not enough information to create a connection.
250 return;
Ryan Hansberry 2017/01/04 00:01:03 nit: add a log.
Kyle Horimoto 2017/01/04 18:35:43 I don't want to add a log here since it would be v
251 }
252
253 // Convert the service data from a std::vector<uint8_t> to a std::string.
254 std::string service_data_str;
255 char* string_contents_ptr =
256 base::WriteInto(&service_data_str, service_data->size() + 1);
257 memcpy(string_contents_ptr, service_data->data(), service_data->size() + 1);
258
259 CheckForMatchingScanFilters(device, service_data_str);
260 }
261
262 void BleScanner::CheckForMatchingScanFilters(device::BluetoothDevice* device,
263 std::string& service_data) {
264 std::vector<cryptauth::BeaconSeed> beacon_seeds;
265 if (!local_device_data_provider_->GetLocalDeviceData(nullptr,
266 &beacon_seeds)) {
267 // If no beacon seeds are available, the scan cannot be checked for a match.
268 return;
269 }
270
271 const cryptauth::RemoteDevice* identified_device =
272 eid_generator_->IdentifyRemoteDeviceByAdvertisement(
273 service_data, registered_devices_, beacon_seeds);
274
275 if (identified_device) {
276 for (auto& observer : observer_list_) {
277 observer.OnReceivedAdvertisementFromDevice(device, *identified_device);
278 }
279 }
Ryan Hansberry 2017/01/04 00:01:03 nit: add a log for when a device cannot be identif
Kyle Horimoto 2017/01/04 18:35:43 Done.
280 }
281
282 } // namespace tether
283
284 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698