blob: eb46d4b88a1fc8e44e5a3d09c52c4a51986d2489 [file] [log] [blame]
Arman Ugurayc2fc0f22015-09-03 15:09:41 -07001//
2// Copyright (C) 2015 Google, Inc.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "service/low_energy_client.h"
18
19#include <base/logging.h>
20
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -080021#include "service/adapter.h"
Jakub Pawlowskia6372e92016-01-19 16:42:37 -080022#include "service/common/bluetooth/util/address_helper.h"
Arman Uguray82ea72f2015-12-02 17:29:27 -080023#include "service/logging_helpers.h"
Arman Uguray12338402015-09-16 18:00:05 -070024#include "stack/include/bt_types.h"
25#include "stack/include/hcidefs.h"
26
Arman Ugurayc2fc0f22015-09-03 15:09:41 -070027using std::lock_guard;
28using std::mutex;
29
30namespace bluetooth {
31
Arman Uguray12338402015-09-16 18:00:05 -070032namespace {
33
Arman Uguray82ea72f2015-12-02 17:29:27 -080034// 31 + 31 for advertising data and scan response. This is the maximum length
35// TODO(armansito): Fix the HAL to return a concatenated blob that contains the
36// true length of each field and also provide a length parameter so that we
37// can support advertising length extensions in the future.
38const size_t kScanRecordLength = 62;
39
Arman Uguray12338402015-09-16 18:00:05 -070040BLEStatus GetBLEStatus(int status) {
41 if (status == BT_STATUS_FAIL)
42 return BLE_STATUS_FAILURE;
43
44 return static_cast<BLEStatus>(status);
45}
46
Arman Uguray82ea72f2015-12-02 17:29:27 -080047// Returns the length of the given scan record array. We have to calculate this
48// based on the maximum possible data length and the TLV data. See TODO above
49// |kScanRecordLength|.
50size_t GetScanRecordLength(uint8_t* bytes) {
51 for (size_t i = 0, field_len = 0; i < kScanRecordLength;
52 i += (field_len + 1)) {
53 field_len = bytes[i];
54
55 // Assert here that the data returned from the stack is correctly formatted
56 // in TLV form and that the length of the current field won't exceed the
57 // total data length.
58 CHECK(i + field_len < kScanRecordLength);
59
60 // If the field length is zero and we haven't reached the maximum length,
61 // then we have found the length, as the stack will pad the data with zeros
62 // accordingly.
63 if (field_len == 0)
64 return i;
65 }
66
67 // We have reached the end.
68 return kScanRecordLength;
69}
70
Arman Uguray12338402015-09-16 18:00:05 -070071// TODO(armansito): BTIF currently expects each advertising field in a
72// specific format passed directly in arguments. We should fix BTIF to accept
73// the advertising data directly instead.
74struct HALAdvertiseData {
75 std::vector<uint8_t> manufacturer_data;
76 std::vector<uint8_t> service_data;
77 std::vector<uint8_t> service_uuid;
78};
79
Arman Uguray9fc7d812015-10-14 12:22:27 -070080bool ProcessUUID(const uint8_t* uuid_data, size_t uuid_len, UUID* out_uuid) {
81 // BTIF expects a single 128-bit UUID to be passed in little-endian form, so
82 // we need to convert into that from raw data.
83 // TODO(armansito): We have three repeated if bodies below only because UUID
84 // accepts std::array which requires constexpr lengths. We should just have a
85 // single UUID constructor that takes in an std::vector instead.
86 if (uuid_len == UUID::kNumBytes16) {
87 UUID::UUID16Bit uuid_bytes;
88 for (size_t i = 0; i < uuid_len; ++i)
89 uuid_bytes[uuid_len - i - 1] = uuid_data[i];
90 *out_uuid = UUID(uuid_bytes);
91 } else if (uuid_len == UUID::kNumBytes32) {
92 UUID::UUID32Bit uuid_bytes;
93 for (size_t i = 0; i < uuid_len; ++i)
94 uuid_bytes[uuid_len - i - 1] = uuid_data[i];
95 *out_uuid = UUID(uuid_bytes);
96 } else if (uuid_len == UUID::kNumBytes128) {
97 UUID::UUID128Bit uuid_bytes;
98 for (size_t i = 0; i < uuid_len; ++i)
99 uuid_bytes[uuid_len - i - 1] = uuid_data[i];
100 *out_uuid = UUID(uuid_bytes);
101 } else {
102 LOG(ERROR) << "Invalid UUID length";
103 return false;
104 }
105
106 return true;
107}
108
Ajay Panickerff651b72015-09-30 15:49:47 -0700109bool ProcessServiceData(const uint8_t* data,
Arman Uguray9fc7d812015-10-14 12:22:27 -0700110 uint8_t uuid_len,
Jakub Pawlowskia6372e92016-01-19 16:42:37 -0800111 HALAdvertiseData* out_data) {
Ajay Panickerff651b72015-09-30 15:49:47 -0700112 size_t field_len = data[0];
113
114 // Minimum packet size should be equal to the uuid length + 1 to include
115 // the byte for the type of packet
Arman Uguray9fc7d812015-10-14 12:22:27 -0700116 if (field_len < uuid_len + 1) {
Ajay Panickerff651b72015-09-30 15:49:47 -0700117 // Invalid packet size
118 return false;
119 }
120
121 if (!out_data->service_data.empty()) {
122 // More than one Service Data is not allowed due to the limitations
123 // of the HAL API. We error in order to make sure there
124 // is no ambiguity on which data to send.
125 VLOG(1) << "More than one Service Data entry not allowed";
126 return false;
127 }
128
129 const uint8_t* service_uuid = data + 2;
Arman Uguray9fc7d812015-10-14 12:22:27 -0700130 UUID uuid;
131 if (!ProcessUUID(service_uuid, uuid_len, &uuid))
132 return false;
133
134 UUID::UUID128Bit uuid_bytes = uuid.GetFullLittleEndian();
135 const std::vector<uint8_t> temp_uuid(
136 uuid_bytes.data(), uuid_bytes.data() + uuid_bytes.size());
Ajay Panickerff651b72015-09-30 15:49:47 -0700137
138 // This section is to make sure that there is no UUID conflict
139 if (out_data->service_uuid.empty()) {
140 out_data->service_uuid = temp_uuid;
141 } else if (out_data->service_uuid != temp_uuid) {
142 // Mismatch in uuid passed through service data and uuid passed
143 // through uuid field
144 VLOG(1) << "More than one UUID entry not allowed";
145 return false;
Jakub Pawlowskia6372e92016-01-19 16:42:37 -0800146 } // else do nothing as UUID is already properly assigned
Ajay Panickerff651b72015-09-30 15:49:47 -0700147
Arman Uguray9fc7d812015-10-14 12:22:27 -0700148 // Use + uuid_len + 2 here in order to skip over a
Ajay Panickerff651b72015-09-30 15:49:47 -0700149 // uuid contained in the beggining of the field
Arman Uguray9fc7d812015-10-14 12:22:27 -0700150 const uint8_t* srv_data = data + uuid_len + 2;
Ajay Panickerff651b72015-09-30 15:49:47 -0700151
152
153 out_data->service_data.insert(
154 out_data->service_data.begin(),
Arman Uguray9fc7d812015-10-14 12:22:27 -0700155 srv_data, srv_data + field_len - uuid_len - 1);
Ajay Panickerff651b72015-09-30 15:49:47 -0700156
157 return true;
158}
159
Arman Uguray12338402015-09-16 18:00:05 -0700160bool ProcessAdvertiseData(const AdvertiseData& adv,
161 HALAdvertiseData* out_data) {
162 CHECK(out_data);
163 CHECK(out_data->manufacturer_data.empty());
164 CHECK(out_data->service_data.empty());
165 CHECK(out_data->service_uuid.empty());
166
167 const auto& data = adv.data();
168 size_t len = data.size();
169 for (size_t i = 0, field_len = 0; i < len; i += (field_len + 1)) {
170 // The length byte is the first byte in the adv. "TLV" format.
171 field_len = data[i];
172
173 // The type byte is the next byte in the adv. "TLV" format.
174 uint8_t type = data[i + 1];
175 size_t uuid_len = 0;
176
177 switch (type) {
178 case HCI_EIR_MANUFACTURER_SPECIFIC_TYPE: {
179 // TODO(armansito): BTIF doesn't allow setting more than one
180 // manufacturer-specific data entry. This is something we should fix. For
181 // now, fail if more than one entry was set.
182 if (!out_data->manufacturer_data.empty()) {
Arman Uguray9fc7d812015-10-14 12:22:27 -0700183 LOG(ERROR) << "More than one Manufacturer Specific Data entry not allowed";
Arman Uguray12338402015-09-16 18:00:05 -0700184 return false;
185 }
186
187 // The value bytes start at the next byte in the "TLV" format.
188 const uint8_t* mnf_data = data.data() + i + 2;
189 out_data->manufacturer_data.insert(
190 out_data->manufacturer_data.begin(),
191 mnf_data, mnf_data + field_len - 1);
192 break;
193 }
Ajay Panickerff651b72015-09-30 15:49:47 -0700194 case HCI_EIR_MORE_16BITS_UUID_TYPE:
195 case HCI_EIR_COMPLETE_16BITS_UUID_TYPE:
196 case HCI_EIR_MORE_32BITS_UUID_TYPE:
197 case HCI_EIR_COMPLETE_32BITS_UUID_TYPE:
198 case HCI_EIR_MORE_128BITS_UUID_TYPE:
199 case HCI_EIR_COMPLETE_128BITS_UUID_TYPE: {
200 const uint8_t* uuid_data = data.data() + i + 2;
Arman Uguray9fc7d812015-10-14 12:22:27 -0700201 size_t uuid_len = field_len - 1;
202 UUID uuid;
203 if (!ProcessUUID(uuid_data, uuid_len, &uuid))
204 return false;
205
206 UUID::UUID128Bit uuid_bytes = uuid.GetFullLittleEndian();
Ajay Panickerff651b72015-09-30 15:49:47 -0700207
208 if (!out_data->service_uuid.empty() &&
Arman Uguray9fc7d812015-10-14 12:22:27 -0700209 memcmp(out_data->service_uuid.data(),
210 uuid_bytes.data(), uuid_bytes.size()) != 0) {
Ajay Panickerff651b72015-09-30 15:49:47 -0700211 // More than one UUID is not allowed due to the limitations
212 // of the HAL API. We error in order to make sure there
213 // is no ambiguity on which UUID to send. Also makes sure that
214 // UUID Hasn't been set by service data first
Arman Uguray9fc7d812015-10-14 12:22:27 -0700215 LOG(ERROR) << "More than one UUID entry not allowed";
Ajay Panickerff651b72015-09-30 15:49:47 -0700216 return false;
217 }
218
219 out_data->service_uuid.assign(
Arman Uguray9fc7d812015-10-14 12:22:27 -0700220 uuid_bytes.data(), uuid_bytes.data() + UUID::kNumBytes128);
Ajay Panickerff651b72015-09-30 15:49:47 -0700221 break;
222 }
223 case HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE: {
224 if (!ProcessServiceData(data.data() + i, 2, out_data))
225 return false;
226 break;
227 }
228 case HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE: {
229 if (!ProcessServiceData(data.data() + i, 4, out_data))
230 return false;
231 break;
232 }
233 case HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE: {
234 if (!ProcessServiceData(data.data() + i, 16, out_data))
235 return false;
236 break;
237 }
Arman Uguray12338402015-09-16 18:00:05 -0700238 // TODO(armansito): Support other fields.
239 default:
240 VLOG(1) << "Unrecognized EIR field: " << type;
241 return false;
242 }
243 }
244
245 return true;
246}
247
248// The Bluetooth Core Specification defines time interval (e.g. Page Scan
249// Interval, Advertising Interval, etc) units as 0.625 milliseconds (or 1
250// Baseband slot). The HAL advertising functions expect the interval in this
251// unit. This function maps an AdvertiseSettings::Mode value to the
252// corresponding time unit.
253int GetAdvertisingIntervalUnit(AdvertiseSettings::Mode mode) {
254 int ms;
255
256 switch (mode) {
257 case AdvertiseSettings::MODE_BALANCED:
258 ms = kAdvertisingIntervalMediumMs;
259 break;
260 case AdvertiseSettings::MODE_LOW_LATENCY:
261 ms = kAdvertisingIntervalLowMs;
262 break;
263 case AdvertiseSettings::MODE_LOW_POWER:
264 // Fall through
265 default:
266 ms = kAdvertisingIntervalHighMs;
267 break;
268 }
269
270 // Convert milliseconds Bluetooth units.
271 return (ms * 1000) / 625;
272}
273
274struct AdvertiseParams {
275 int min_interval;
276 int max_interval;
277 int event_type;
278 int tx_power_level;
279 int timeout_s;
280};
281
282void GetAdvertiseParams(const AdvertiseSettings& settings, bool has_scan_rsp,
283 AdvertiseParams* out_params) {
284 CHECK(out_params);
285
286 out_params->min_interval = GetAdvertisingIntervalUnit(settings.mode());
287 out_params->max_interval =
288 out_params->min_interval + kAdvertisingIntervalDeltaUnit;
289
290 if (settings.connectable())
291 out_params->event_type = kAdvertisingEventTypeConnectable;
292 else if (has_scan_rsp)
293 out_params->event_type = kAdvertisingEventTypeScannable;
294 else
295 out_params->event_type = kAdvertisingEventTypeNonConnectable;
296
297 out_params->tx_power_level = settings.tx_power_level();
298 out_params->timeout_s = settings.timeout().InSeconds();
299}
300
301} // namespace
302
303// LowEnergyClient implementation
304// ========================================================
305
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -0800306LowEnergyClient::LowEnergyClient(
307 Adapter& adapter, const UUID& uuid, int client_id)
308 : adapter_(adapter),
309 app_identifier_(uuid),
Arman Uguraybb18c412015-11-12 13:44:31 -0800310 client_id_(client_id),
Arman Uguray12338402015-09-16 18:00:05 -0700311 adv_data_needs_update_(false),
312 scan_rsp_needs_update_(false),
313 is_setting_adv_data_(false),
314 adv_started_(false),
315 adv_start_callback_(nullptr),
Arman Uguray480174f2015-11-30 15:36:17 -0800316 adv_stop_callback_(nullptr),
317 scan_started_(false) {
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700318}
319
320LowEnergyClient::~LowEnergyClient() {
321 // Automatically unregister the client.
Arman Uguraybb18c412015-11-12 13:44:31 -0800322 VLOG(1) << "LowEnergyClient unregistering client: " << client_id_;
Arman Uguray12338402015-09-16 18:00:05 -0700323
324 // Unregister as observer so we no longer receive any callbacks.
325 hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
326
327 // Stop advertising and ignore the result.
328 hal::BluetoothGattInterface::Get()->
Arman Uguraybb18c412015-11-12 13:44:31 -0800329 GetClientHALInterface()->multi_adv_disable(client_id_);
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700330 hal::BluetoothGattInterface::Get()->
Arman Uguraybb18c412015-11-12 13:44:31 -0800331 GetClientHALInterface()->unregister_client(client_id_);
Arman Uguray480174f2015-11-30 15:36:17 -0800332
333 // Stop any scans started by this client.
334 if (scan_started_.load())
335 StopScan();
336}
337
Jakub Pawlowskia6372e92016-01-19 16:42:37 -0800338bool LowEnergyClient::Connect(std::string address, bool is_direct) {
339 VLOG(2) << __func__ << "Address: " << address << " is_direct: " << is_direct;
340
341 bt_bdaddr_t bda;
342 util::BdAddrFromString(address, &bda);
343
344 bt_status_t status = hal::BluetoothGattInterface::Get()->
345 GetClientHALInterface()->connect(client_id_, &bda, is_direct,
346 BT_TRANSPORT_LE);
347 if (status != BT_STATUS_SUCCESS) {
348 LOG(ERROR) << "HAL call to connect failed";
349 return false;
350 }
351
352 return true;
353}
354
355bool LowEnergyClient::Disconnect(std::string address) {
356 VLOG(2) << __func__ << "Address: " << address;
357
358 bt_bdaddr_t bda;
359 util::BdAddrFromString(address, &bda);
360
361 std::map<const bt_bdaddr_t, int>::iterator conn_id;
362 {
363 lock_guard<mutex> lock(connection_fields_lock_);
364 conn_id = connection_ids_.find(bda);
365 if (conn_id == connection_ids_.end()) {
366 LOG(WARNING) << "Can't disconnect, no existing connection to " << address;
367 return false;
368 }
369 }
370
371 bt_status_t status = hal::BluetoothGattInterface::Get()->
372 GetClientHALInterface()->disconnect(client_id_, &bda, conn_id->second);
373 if (status != BT_STATUS_SUCCESS) {
374 LOG(ERROR) << "HAL call to disconnect failed";
375 return false;
376 }
377
378 return true;
379}
380
Arman Uguray82ea72f2015-12-02 17:29:27 -0800381void LowEnergyClient::SetDelegate(Delegate* delegate) {
382 lock_guard<mutex> lock(delegate_mutex_);
383 delegate_ = delegate;
384}
385
Arman Uguray480174f2015-11-30 15:36:17 -0800386bool LowEnergyClient::StartScan(const ScanSettings& settings,
387 const std::vector<ScanFilter>& filters) {
388 VLOG(2) << __func__;
389
390 // Cannot start a scan if the adapter is not enabled.
391 if (!adapter_.IsEnabled()) {
392 LOG(ERROR) << "Cannot scan while Bluetooth is disabled";
393 return false;
394 }
395
396 // TODO(jpawlowski): Push settings and filtering logic below the HAL.
397 bt_status_t status = hal::BluetoothGattInterface::Get()->
398 StartScan(client_id_);
399 if (status != BT_STATUS_SUCCESS) {
400 LOG(ERROR) << "Failed to initiate scanning for client: " << client_id_;
401 return false;
402 }
403
404 scan_started_ = true;
405 return true;
406}
407
408bool LowEnergyClient::StopScan() {
409 VLOG(2) << __func__;
410
411 // TODO(armansito): We don't support batch scanning yet so call
412 // StopRegularScanForClient directly. In the future we will need to
413 // conditionally call a batch scan API here.
414 bt_status_t status = hal::BluetoothGattInterface::Get()->
415 StopScan(client_id_);
416 if (status != BT_STATUS_SUCCESS) {
417 LOG(ERROR) << "Failed to stop scan for client: " << client_id_;
418 return false;
419 }
420
421 scan_started_ = false;
422 return true;
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700423}
424
Arman Uguray12338402015-09-16 18:00:05 -0700425bool LowEnergyClient::StartAdvertising(const AdvertiseSettings& settings,
426 const AdvertiseData& advertise_data,
427 const AdvertiseData& scan_response,
428 const StatusCallback& callback) {
429 VLOG(2) << __func__;
430 lock_guard<mutex> lock(adv_fields_lock_);
431
432 if (IsAdvertisingStarted()) {
433 LOG(WARNING) << "Already advertising";
434 return false;
435 }
436
437 if (IsStartingAdvertising()) {
438 LOG(WARNING) << "StartAdvertising already pending";
439 return false;
440 }
441
442 if (!advertise_data.IsValid()) {
443 LOG(ERROR) << "Invalid advertising data";
444 return false;
445 }
446
447 if (!scan_response.IsValid()) {
448 LOG(ERROR) << "Invalid scan response data";
449 return false;
450 }
451
452 CHECK(!adv_data_needs_update_.load());
453 CHECK(!scan_rsp_needs_update_.load());
454
455 adv_data_ = advertise_data;
456 scan_response_ = scan_response;
Jakub Pawlowskid748ef22016-01-12 13:43:33 -0800457 advertise_settings_ = settings;
Arman Uguray12338402015-09-16 18:00:05 -0700458
459 AdvertiseParams params;
460 GetAdvertiseParams(settings, !scan_response_.data().empty(), &params);
461
462 bt_status_t status = hal::BluetoothGattInterface::Get()->
463 GetClientHALInterface()->multi_adv_enable(
Arman Uguraybb18c412015-11-12 13:44:31 -0800464 client_id_,
Arman Uguray12338402015-09-16 18:00:05 -0700465 params.min_interval,
466 params.max_interval,
467 params.event_type,
468 kAdvertisingChannelAll,
469 params.tx_power_level,
470 params.timeout_s);
471 if (status != BT_STATUS_SUCCESS) {
472 LOG(ERROR) << "Failed to initiate call to enable multi-advertising";
473 return false;
474 }
475
476 // Always update advertising data.
477 adv_data_needs_update_ = true;
478
479 // Update scan response only if it has data, since otherwise we just won't
480 // send ADV_SCAN_IND.
481 if (!scan_response_.data().empty())
482 scan_rsp_needs_update_ = true;
483
484 // OK to set this at the end since we're still holding |adv_fields_lock_|.
485 adv_start_callback_.reset(new StatusCallback(callback));
486
487 return true;
488}
489
490bool LowEnergyClient::StopAdvertising(const StatusCallback& callback) {
491 VLOG(2) << __func__;
492 lock_guard<mutex> lock(adv_fields_lock_);
493
494 if (!IsAdvertisingStarted()) {
495 LOG(ERROR) << "Not advertising";
496 return false;
497 }
498
499 if (IsStoppingAdvertising()) {
500 LOG(ERROR) << "StopAdvertising already pending";
501 return false;
502 }
503
504 CHECK(!adv_start_callback_);
505
506 bt_status_t status = hal::BluetoothGattInterface::Get()->
Arman Uguraybb18c412015-11-12 13:44:31 -0800507 GetClientHALInterface()->multi_adv_disable(client_id_);
Arman Uguray12338402015-09-16 18:00:05 -0700508 if (status != BT_STATUS_SUCCESS) {
509 LOG(ERROR) << "Failed to initiate call to disable multi-advertising";
510 return false;
511 }
512
513 // OK to set this at the end since we're still holding |adv_fields_lock_|.
514 adv_stop_callback_.reset(new StatusCallback(callback));
515
516 return true;
517}
518
519bool LowEnergyClient::IsAdvertisingStarted() const {
520 return adv_started_.load();
521}
522
523bool LowEnergyClient::IsStartingAdvertising() const {
524 return !IsAdvertisingStarted() && adv_start_callback_;
525}
526
527bool LowEnergyClient::IsStoppingAdvertising() const {
528 return IsAdvertisingStarted() && adv_stop_callback_;
529}
530
Arman Uguray08f80eb2015-09-21 11:17:07 -0700531const UUID& LowEnergyClient::GetAppIdentifier() const {
532 return app_identifier_;
533}
534
Arman Uguraybb18c412015-11-12 13:44:31 -0800535int LowEnergyClient::GetInstanceId() const {
536 return client_id_;
Arman Uguray08f80eb2015-09-21 11:17:07 -0700537}
538
Arman Uguray82ea72f2015-12-02 17:29:27 -0800539void LowEnergyClient::ScanResultCallback(
540 hal::BluetoothGattInterface* gatt_iface,
541 const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) {
542 // Ignore scan results if this client didn't start a scan.
543 if (!scan_started_.load())
544 return;
545
546 lock_guard<mutex> lock(delegate_mutex_);
547 if (!delegate_)
548 return;
549
550 // TODO(armansito): Apply software filters here.
551
552 size_t record_len = GetScanRecordLength(adv_data);
553 std::vector<uint8_t> scan_record(adv_data, adv_data + record_len);
554
555 ScanResult result(BtAddrString(&bda), scan_record, rssi);
556
557 delegate_->OnScanResult(this, result);
558}
559
Jakub Pawlowskia6372e92016-01-19 16:42:37 -0800560void LowEnergyClient::ConnectCallback(
561 hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
562 int client_id, const bt_bdaddr_t& bda) {
563 if (client_id != client_id_)
564 return;
565
566 VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
567
568 {
569 lock_guard<mutex> lock(connection_fields_lock_);
570 auto success = connection_ids_.emplace(bda, conn_id);
571 if (!success.second) {
572 LOG(ERROR) << __func__ << " Insertion into connection_ids_ failed!";
573 }
574 }
575
576 if (delegate_)
577 delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
578 true);
579}
580
581void LowEnergyClient::DisconnectCallback(
582 hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
583 int client_id, const bt_bdaddr_t& bda) {
584 if (client_id != client_id_)
585 return;
586
587 VLOG(1) << __func__ << " client_id: " << client_id << " status: " << status;
588 {
589 lock_guard<mutex> lock(connection_fields_lock_);
590 if (!connection_ids_.erase(bda)) {
591 LOG(ERROR) << __func__ << " Erasing from connection_ids_ failed!";
592 }
593 }
594
595 if (delegate_)
596 delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
597 false);
598}
599
Arman Uguray12338402015-09-16 18:00:05 -0700600void LowEnergyClient::MultiAdvEnableCallback(
601 hal::BluetoothGattInterface* gatt_iface,
Arman Uguraybb18c412015-11-12 13:44:31 -0800602 int client_id, int status) {
603 if (client_id != client_id_)
Arman Uguray12338402015-09-16 18:00:05 -0700604 return;
605
606 lock_guard<mutex> lock(adv_fields_lock_);
607
Arman Uguraybb18c412015-11-12 13:44:31 -0800608 VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
Arman Uguray12338402015-09-16 18:00:05 -0700609
610 CHECK(adv_start_callback_);
611 CHECK(!adv_stop_callback_);
612
613 // Terminate operation in case of error.
614 if (status != BT_STATUS_SUCCESS) {
615 LOG(ERROR) << "Failed to enable multi-advertising";
616 InvokeAndClearStartCallback(GetBLEStatus(status));
617 return;
618 }
619
620 // Now handle deferred tasks.
621 HandleDeferredAdvertiseData(gatt_iface);
622}
623
624void LowEnergyClient::MultiAdvDataCallback(
625 hal::BluetoothGattInterface* gatt_iface,
Arman Uguraybb18c412015-11-12 13:44:31 -0800626 int client_id, int status) {
627 if (client_id != client_id_)
Arman Uguray12338402015-09-16 18:00:05 -0700628 return;
629
630 lock_guard<mutex> lock(adv_fields_lock_);
631
Arman Uguraybb18c412015-11-12 13:44:31 -0800632 VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
Arman Uguray12338402015-09-16 18:00:05 -0700633
634 is_setting_adv_data_ = false;
635
636 // Terminate operation in case of error.
637 if (status != BT_STATUS_SUCCESS) {
638 LOG(ERROR) << "Failed to set advertising data";
639 InvokeAndClearStartCallback(GetBLEStatus(status));
640 return;
641 }
642
643 // Now handle deferred tasks.
644 HandleDeferredAdvertiseData(gatt_iface);
645}
646
647void LowEnergyClient::MultiAdvDisableCallback(
648 hal::BluetoothGattInterface* /* gatt_iface */,
Arman Uguraybb18c412015-11-12 13:44:31 -0800649 int client_id, int status) {
650 if (client_id != client_id_)
Arman Uguray12338402015-09-16 18:00:05 -0700651 return;
652
653 lock_guard<mutex> lock(adv_fields_lock_);
654
Arman Uguraybb18c412015-11-12 13:44:31 -0800655 VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
Arman Uguray12338402015-09-16 18:00:05 -0700656
657 CHECK(!adv_start_callback_);
658 CHECK(adv_stop_callback_);
659
660 if (status == BT_STATUS_SUCCESS) {
Arman Uguraybb18c412015-11-12 13:44:31 -0800661 VLOG(1) << "Multi-advertising stopped for client_id: " << client_id;
Arman Uguray12338402015-09-16 18:00:05 -0700662 adv_started_ = false;
663 } else {
664 LOG(ERROR) << "Failed to stop multi-advertising";
665 }
666
667 InvokeAndClearStopCallback(GetBLEStatus(status));
668}
669
670bt_status_t LowEnergyClient::SetAdvertiseData(
671 hal::BluetoothGattInterface* gatt_iface,
672 const AdvertiseData& data,
673 bool set_scan_rsp) {
674 VLOG(2) << __func__;
675
676 HALAdvertiseData hal_data;
677
678 // TODO(armansito): The stack should check that the length is valid when other
679 // fields inserted by the stack (e.g. flags, device name, tx-power) are taken
680 // into account. At the moment we are skipping this check; this means that if
681 // the given data is too long then the stack will truncate it.
682 if (!ProcessAdvertiseData(data, &hal_data)) {
Ajay Panickerff651b72015-09-30 15:49:47 -0700683 LOG(ERROR) << "Malformed advertise data given";
Arman Uguray12338402015-09-16 18:00:05 -0700684 return BT_STATUS_FAIL;
685 }
686
687 if (is_setting_adv_data_.load()) {
Ajay Panickerff651b72015-09-30 15:49:47 -0700688 LOG(ERROR) << "Setting advertising data already in progress.";
Arman Uguray12338402015-09-16 18:00:05 -0700689 return BT_STATUS_FAIL;
690 }
691
692 // TODO(armansito): The length fields in the BTIF function below are signed
693 // integers so a call to std::vector::size might get capped. This is very
694 // unlikely anyway but it's safer to stop using signed-integer types for
695 // length in APIs, so we should change that.
696 bt_status_t status = gatt_iface->GetClientHALInterface()->
697 multi_adv_set_inst_data(
Arman Uguraybb18c412015-11-12 13:44:31 -0800698 client_id_,
Arman Uguray12338402015-09-16 18:00:05 -0700699 set_scan_rsp,
700 data.include_device_name(),
701 data.include_tx_power_level(),
702 0, // This is what Bluetooth.apk current hardcodes for "appearance".
703 hal_data.manufacturer_data.size(),
704 reinterpret_cast<char*>(hal_data.manufacturer_data.data()),
Ajay Panickerff651b72015-09-30 15:49:47 -0700705 hal_data.service_data.size(),
706 reinterpret_cast<char*>(hal_data.service_data.data()),
707 hal_data.service_uuid.size(),
708 reinterpret_cast<char*>(hal_data.service_uuid.data()));
709
Arman Uguray12338402015-09-16 18:00:05 -0700710 if (status != BT_STATUS_SUCCESS) {
711 LOG(ERROR) << "Failed to set instance advertising data.";
712 return status;
713 }
714
715 if (set_scan_rsp)
716 scan_rsp_needs_update_ = false;
717 else
718 adv_data_needs_update_ = false;
719
720 is_setting_adv_data_ = true;
721
722 return status;
723}
724
725void LowEnergyClient::HandleDeferredAdvertiseData(
726 hal::BluetoothGattInterface* gatt_iface) {
727 VLOG(2) << __func__;
728
729 CHECK(!IsAdvertisingStarted());
730 CHECK(!IsStoppingAdvertising());
731 CHECK(IsStartingAdvertising());
732 CHECK(!is_setting_adv_data_.load());
733
734 if (adv_data_needs_update_.load()) {
735 bt_status_t status = SetAdvertiseData(gatt_iface, adv_data_, false);
736 if (status != BT_STATUS_SUCCESS) {
737 LOG(ERROR) << "Failed setting advertisement data";
738 InvokeAndClearStartCallback(GetBLEStatus(status));
739 }
740 return;
741 }
742
743 if (scan_rsp_needs_update_.load()) {
744 bt_status_t status = SetAdvertiseData(gatt_iface, scan_response_, true);
745 if (status != BT_STATUS_SUCCESS) {
746 LOG(ERROR) << "Failed setting scan response data";
747 InvokeAndClearStartCallback(GetBLEStatus(status));
748 }
749 return;
750 }
751
752 // All pending tasks are complete. Report success.
753 adv_started_ = true;
754 InvokeAndClearStartCallback(BLE_STATUS_SUCCESS);
755}
756
757void LowEnergyClient::InvokeAndClearStartCallback(BLEStatus status) {
758 adv_data_needs_update_ = false;
759 scan_rsp_needs_update_ = false;
760
761 // We allow NULL callbacks.
762 if (*adv_start_callback_)
763 (*adv_start_callback_)(status);
764
765 adv_start_callback_ = nullptr;
766}
767
768void LowEnergyClient::InvokeAndClearStopCallback(BLEStatus status) {
769 // We allow NULL callbacks.
770 if (*adv_stop_callback_)
771 (*adv_stop_callback_)(status);
772
773 adv_stop_callback_ = nullptr;
774}
775
776// LowEnergyClientFactory implementation
777// ========================================================
778
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -0800779LowEnergyClientFactory::LowEnergyClientFactory(Adapter& adapter)
780 : adapter_(adapter) {
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700781 hal::BluetoothGattInterface::Get()->AddClientObserver(this);
782}
783
784LowEnergyClientFactory::~LowEnergyClientFactory() {
785 hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
786}
787
Arman Uguraybb18c412015-11-12 13:44:31 -0800788bool LowEnergyClientFactory::RegisterInstance(
789 const UUID& uuid,
790 const RegisterCallback& callback) {
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700791 VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
792 lock_guard<mutex> lock(pending_calls_lock_);
793
794 if (pending_calls_.find(uuid) != pending_calls_.end()) {
795 LOG(ERROR) << "Low-Energy client with given UUID already registered - "
796 << "UUID: " << uuid.ToString();
797 return false;
798 }
799
800 const btgatt_client_interface_t* hal_iface =
801 hal::BluetoothGattInterface::Get()->GetClientHALInterface();
802 bt_uuid_t app_uuid = uuid.GetBlueDroid();
803
804 if (hal_iface->register_client(&app_uuid) != BT_STATUS_SUCCESS)
805 return false;
806
807 pending_calls_[uuid] = callback;
808
809 return true;
810}
811
812void LowEnergyClientFactory::RegisterClientCallback(
Arman Uguray12338402015-09-16 18:00:05 -0700813 hal::BluetoothGattInterface* gatt_iface,
Arman Uguraybb18c412015-11-12 13:44:31 -0800814 int status, int client_id,
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700815 const bt_uuid_t& app_uuid) {
816 UUID uuid(app_uuid);
817
818 VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
819 lock_guard<mutex> lock(pending_calls_lock_);
820
821 auto iter = pending_calls_.find(uuid);
822 if (iter == pending_calls_.end()) {
823 VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
824 return;
825 }
826
827 // No need to construct a client if the call wasn't successful.
828 std::unique_ptr<LowEnergyClient> client;
829 BLEStatus result = BLE_STATUS_FAILURE;
830 if (status == BT_STATUS_SUCCESS) {
Jakub Pawlowski60b0e8f2016-01-12 13:51:35 -0800831 client.reset(new LowEnergyClient(adapter_, uuid, client_id));
Arman Uguray12338402015-09-16 18:00:05 -0700832
833 // Use the unsafe variant to register this as an observer, since
834 // LowEnergyClient instances only get created by LowEnergyClientCallback
835 // from inside this GATT client observer event, which would otherwise cause
836 // a deadlock.
837 gatt_iface->AddClientObserverUnsafe(client.get());
838
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700839 result = BLE_STATUS_SUCCESS;
840 }
841
Arman Uguray08f80eb2015-09-21 11:17:07 -0700842 // Notify the result via the result callback.
Arman Ugurayc2fc0f22015-09-03 15:09:41 -0700843 iter->second(result, uuid, std::move(client));
844
845 pending_calls_.erase(iter);
846}
847
848} // namespace bluetooth