OLD | NEW |
---|---|
(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 | |
OLD | NEW |