1c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//
2c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  Copyright (C) 2015 Google, Inc.
3c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//
4c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  Licensed under the Apache License, Version 2.0 (the "License");
5c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  you may not use this file except in compliance with the License.
6c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  You may obtain a copy of the License at:
7c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//
8c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  http://www.apache.org/licenses/LICENSE-2.0
9c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//
10c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  Unless required by applicable law or agreed to in writing, software
11c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  distributed under the License is distributed on an "AS IS" BASIS,
12c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  See the License for the specific language governing permissions and
14c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//  limitations under the License.
15c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray//
16c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
17c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray#include "service/low_energy_client.h"
18c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
19c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray#include <base/logging.h>
20c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
2160b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski#include "service/adapter.h"
22a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski#include "service/common/bluetooth/util/address_helper.h"
2382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray#include "service/logging_helpers.h"
2412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray#include "stack/include/bt_types.h"
2512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray#include "stack/include/hcidefs.h"
2612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
27c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Ugurayusing std::lock_guard;
28c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Ugurayusing std::mutex;
29c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
30c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguraynamespace bluetooth {
31c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
3212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraynamespace {
3312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
3482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// 31 + 31 for advertising data and scan response. This is the maximum length
3582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// TODO(armansito): Fix the HAL to return a concatenated blob that contains the
3682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// true length of each field and also provide a length parameter so that we
3782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// can support advertising length extensions in the future.
3882ea72f905565f83116f74d5ccbacea5d710a853Arman Ugurayconst size_t kScanRecordLength = 62;
3982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
4012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman UgurayBLEStatus GetBLEStatus(int status) {
4112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (status == BT_STATUS_FAIL)
4212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return BLE_STATUS_FAILURE;
4312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
4412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  return static_cast<BLEStatus>(status);
4512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
4612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
4782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// Returns the length of the given scan record array. We have to calculate this
4882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// based on the maximum possible data length and the TLV data. See TODO above
4982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray// |kScanRecordLength|.
5082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguraysize_t GetScanRecordLength(uint8_t* bytes) {
5182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  for (size_t i = 0, field_len = 0; i < kScanRecordLength;
5282ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray       i += (field_len + 1)) {
5382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    field_len = bytes[i];
5482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
5582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    // Assert here that the data returned from the stack is correctly formatted
5682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    // in TLV form and that the length of the current field won't exceed the
5782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    // total data length.
5882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    CHECK(i + field_len < kScanRecordLength);
5982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
6082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    // If the field length is zero and we haven't reached the maximum length,
6182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    // then we have found the length, as the stack will pad the data with zeros
6282ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    // accordingly.
6382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    if (field_len == 0)
6482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray      return i;
6582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  }
6682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
6782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  // We have reached the end.
6882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  return kScanRecordLength;
6982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray}
7082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
7112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// TODO(armansito): BTIF currently expects each advertising field in a
7212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// specific format passed directly in arguments. We should fix BTIF to accept
7312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// the advertising data directly instead.
7412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraystruct HALAdvertiseData {
7512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  std::vector<uint8_t> manufacturer_data;
7612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  std::vector<uint8_t> service_data;
7712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  std::vector<uint8_t> service_uuid;
7812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray};
7912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
809fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguraybool ProcessUUID(const uint8_t* uuid_data, size_t uuid_len, UUID* out_uuid) {
819fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  // BTIF expects a single 128-bit UUID to be passed in little-endian form, so
829fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  // we need to convert into that from raw data.
839fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  // TODO(armansito): We have three repeated if bodies below only because UUID
849fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  // accepts std::array which requires constexpr lengths. We should just have a
859fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  // single UUID constructor that takes in an std::vector instead.
869fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  if (uuid_len == UUID::kNumBytes16) {
879fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    UUID::UUID16Bit uuid_bytes;
889fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    for (size_t i = 0; i < uuid_len; ++i)
899fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray      uuid_bytes[uuid_len - i - 1] = uuid_data[i];
909fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    *out_uuid = UUID(uuid_bytes);
919fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  } else if (uuid_len == UUID::kNumBytes32) {
929fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    UUID::UUID32Bit uuid_bytes;
939fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    for (size_t i = 0; i < uuid_len; ++i)
949fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray      uuid_bytes[uuid_len - i - 1] = uuid_data[i];
959fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    *out_uuid = UUID(uuid_bytes);
969fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  } else if (uuid_len == UUID::kNumBytes128) {
979fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    UUID::UUID128Bit uuid_bytes;
989fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    for (size_t i = 0; i < uuid_len; ++i)
999fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray      uuid_bytes[uuid_len - i - 1] = uuid_data[i];
1009fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    *out_uuid = UUID(uuid_bytes);
1019fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  } else {
1029fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    LOG(ERROR) << "Invalid UUID length";
1039fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    return false;
1049fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  }
1059fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray
1069fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  return true;
1079fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray}
1089fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray
109ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panickerbool ProcessServiceData(const uint8_t* data,
1109fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray        uint8_t uuid_len,
111a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski        HALAdvertiseData* out_data) {
112ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  size_t field_len = data[0];
113ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
114ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  // Minimum packet size should be equal to the uuid length + 1 to include
115ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  // the byte for the type of packet
1169fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  if (field_len < uuid_len + 1) {
117ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    // Invalid packet size
118ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    return false;
119ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  }
120ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
121ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  if (!out_data->service_data.empty()) {
122ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    // More than one Service Data is not allowed due to the limitations
123ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    // of the HAL API. We error in order to make sure there
124ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    // is no ambiguity on which data to send.
125ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    VLOG(1) << "More than one Service Data entry not allowed";
126ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    return false;
127ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  }
128ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
129ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  const uint8_t* service_uuid = data + 2;
1309fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  UUID uuid;
1319fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  if (!ProcessUUID(service_uuid, uuid_len, &uuid))
1329fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray    return false;
1339fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray
1349fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  UUID::UUID128Bit uuid_bytes = uuid.GetFullLittleEndian();
1359fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  const std::vector<uint8_t> temp_uuid(
1369fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray      uuid_bytes.data(), uuid_bytes.data() + uuid_bytes.size());
137ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
138ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  // This section is to make sure that there is no UUID conflict
139ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  if (out_data->service_uuid.empty()) {
140ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    out_data->service_uuid = temp_uuid;
141ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  } else if (out_data->service_uuid != temp_uuid) {
142ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    // Mismatch in uuid passed through service data and uuid passed
143ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    // through uuid field
144ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    VLOG(1) << "More than one UUID entry not allowed";
145ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    return false;
146a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  }  // else do nothing as UUID is already properly assigned
147ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
1489fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  // Use + uuid_len + 2 here in order to skip over a
149ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  // uuid contained in the beggining of the field
1509fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray  const uint8_t* srv_data = data + uuid_len + 2;
151ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
152ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
153ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  out_data->service_data.insert(
154ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      out_data->service_data.begin(),
1559fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray      srv_data, srv_data + field_len - uuid_len - 1);
156ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
157ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker  return true;
158ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker}
159ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
16012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool ProcessAdvertiseData(const AdvertiseData& adv,
16112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray                          HALAdvertiseData* out_data) {
16212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(out_data);
16312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(out_data->manufacturer_data.empty());
16412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(out_data->service_data.empty());
16512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(out_data->service_uuid.empty());
16612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
16712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  const auto& data = adv.data();
16812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  size_t len = data.size();
16912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  for (size_t i = 0, field_len = 0; i < len; i += (field_len + 1)) {
17012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    // The length byte is the first byte in the adv. "TLV" format.
17112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    field_len = data[i];
17212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
17312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    // The type byte is the next byte in the adv. "TLV" format.
17412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    uint8_t type = data[i + 1];
17512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
17612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    switch (type) {
17712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    case HCI_EIR_MANUFACTURER_SPECIFIC_TYPE: {
17812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      // TODO(armansito): BTIF doesn't allow setting more than one
17912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      // manufacturer-specific data entry. This is something we should fix. For
18012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      // now, fail if more than one entry was set.
18112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      if (!out_data->manufacturer_data.empty()) {
1829fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray        LOG(ERROR) << "More than one Manufacturer Specific Data entry not allowed";
18312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray        return false;
18412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      }
18512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
18612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      // The value bytes start at the next byte in the "TLV" format.
18712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      const uint8_t* mnf_data = data.data() + i + 2;
18812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      out_data->manufacturer_data.insert(
18912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          out_data->manufacturer_data.begin(),
19012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          mnf_data, mnf_data + field_len - 1);
19112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      break;
19212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    }
193ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    case HCI_EIR_MORE_16BITS_UUID_TYPE:
194ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    case HCI_EIR_COMPLETE_16BITS_UUID_TYPE:
195ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    case HCI_EIR_MORE_32BITS_UUID_TYPE:
196ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    case HCI_EIR_COMPLETE_32BITS_UUID_TYPE:
197ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    case HCI_EIR_MORE_128BITS_UUID_TYPE:
198ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    case HCI_EIR_COMPLETE_128BITS_UUID_TYPE: {
199ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      const uint8_t* uuid_data = data.data() + i + 2;
2009fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray      size_t uuid_len = field_len - 1;
2019fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray      UUID uuid;
2029fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray      if (!ProcessUUID(uuid_data, uuid_len, &uuid))
2039fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray        return false;
2049fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray
2059fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray      UUID::UUID128Bit uuid_bytes = uuid.GetFullLittleEndian();
206ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
207ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      if (!out_data->service_uuid.empty() &&
2089fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray          memcmp(out_data->service_uuid.data(),
2099fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray                 uuid_bytes.data(), uuid_bytes.size()) != 0) {
210ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker        // More than one UUID is not allowed due to the limitations
211ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker        // of the HAL API. We error in order to make sure there
212ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker        // is no ambiguity on which UUID to send. Also makes sure that
213ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker        // UUID Hasn't been set by service data first
2149fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray        LOG(ERROR) << "More than one UUID entry not allowed";
215ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker        return false;
216ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      }
217ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
218ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      out_data->service_uuid.assign(
2199fc7d81c2dfa3f9b7c4381cd83e5e8f788e235f3Arman Uguray          uuid_bytes.data(), uuid_bytes.data() + UUID::kNumBytes128);
220ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      break;
221ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    }
222ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    case HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE: {
223ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      if (!ProcessServiceData(data.data() + i, 2, out_data))
224ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker        return false;
225ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      break;
226ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    }
227ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    case HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE: {
228ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      if (!ProcessServiceData(data.data() + i, 4, out_data))
229ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker        return false;
230ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      break;
231ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    }
232ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    case HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE: {
233ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      if (!ProcessServiceData(data.data() + i, 16, out_data))
234ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker        return false;
235ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker      break;
236ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    }
23712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    // TODO(armansito): Support other fields.
23812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    default:
23912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      VLOG(1) << "Unrecognized EIR field: " << type;
24012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      return false;
24112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    }
24212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
24312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
24412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  return true;
24512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
24612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
24712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// The Bluetooth Core Specification defines time interval (e.g. Page Scan
24812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// Interval, Advertising Interval, etc) units as 0.625 milliseconds (or 1
24912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// Baseband slot). The HAL advertising functions expect the interval in this
25012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// unit. This function maps an AdvertiseSettings::Mode value to the
25112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// corresponding time unit.
25212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayint GetAdvertisingIntervalUnit(AdvertiseSettings::Mode mode) {
25312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  int ms;
25412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
25512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  switch (mode) {
25612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  case AdvertiseSettings::MODE_BALANCED:
25712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    ms = kAdvertisingIntervalMediumMs;
25812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    break;
25912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  case AdvertiseSettings::MODE_LOW_LATENCY:
26012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    ms = kAdvertisingIntervalLowMs;
26112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    break;
26212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  case AdvertiseSettings::MODE_LOW_POWER:
26312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    // Fall through
26412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  default:
26512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    ms = kAdvertisingIntervalHighMs;
26612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    break;
26712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
26812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
26912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // Convert milliseconds Bluetooth units.
27012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  return (ms * 1000) / 625;
27112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
27212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
27312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraystruct AdvertiseParams {
27412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  int min_interval;
27512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  int max_interval;
27612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  int event_type;
27712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  int tx_power_level;
27812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  int timeout_s;
27912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray};
28012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
28112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid GetAdvertiseParams(const AdvertiseSettings& settings, bool has_scan_rsp,
28212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray                        AdvertiseParams* out_params) {
28312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(out_params);
28412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
28512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  out_params->min_interval = GetAdvertisingIntervalUnit(settings.mode());
28612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  out_params->max_interval =
28712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      out_params->min_interval + kAdvertisingIntervalDeltaUnit;
28812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
28912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (settings.connectable())
29012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    out_params->event_type = kAdvertisingEventTypeConnectable;
29112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  else if (has_scan_rsp)
29212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    out_params->event_type = kAdvertisingEventTypeScannable;
29312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  else
29412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    out_params->event_type = kAdvertisingEventTypeNonConnectable;
29512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
29612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  out_params->tx_power_level = settings.tx_power_level();
29712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  out_params->timeout_s = settings.timeout().InSeconds();
29812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
29912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
30012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}  // namespace
30112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
30212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// LowEnergyClient implementation
30312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// ========================================================
30412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
30560b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub PawlowskiLowEnergyClient::LowEnergyClient(
30660b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski    Adapter& adapter, const UUID& uuid, int client_id)
30760b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski    : adapter_(adapter),
30860b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski      app_identifier_(uuid),
309bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray      client_id_(client_id),
31012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      adv_data_needs_update_(false),
31112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      scan_rsp_needs_update_(false),
31212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      is_setting_adv_data_(false),
31312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      adv_started_(false),
31412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      adv_start_callback_(nullptr),
315480174f874a664affda33831c904eb3574ae9389Arman Uguray      adv_stop_callback_(nullptr),
316480174f874a664affda33831c904eb3574ae9389Arman Uguray      scan_started_(false) {
317c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray}
318c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
319c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman UgurayLowEnergyClient::~LowEnergyClient() {
320c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  // Automatically unregister the client.
321bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray  VLOG(1) << "LowEnergyClient unregistering client: " << client_id_;
32212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
32312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // Unregister as observer so we no longer receive any callbacks.
32412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
32512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
32612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // Stop advertising and ignore the result.
32712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  hal::BluetoothGattInterface::Get()->
328bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray      GetClientHALInterface()->multi_adv_disable(client_id_);
329c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  hal::BluetoothGattInterface::Get()->
330bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray      GetClientHALInterface()->unregister_client(client_id_);
331480174f874a664affda33831c904eb3574ae9389Arman Uguray
332480174f874a664affda33831c904eb3574ae9389Arman Uguray  // Stop any scans started by this client.
333480174f874a664affda33831c904eb3574ae9389Arman Uguray  if (scan_started_.load())
334480174f874a664affda33831c904eb3574ae9389Arman Uguray    StopScan();
335480174f874a664affda33831c904eb3574ae9389Arman Uguray}
336480174f874a664affda33831c904eb3574ae9389Arman Uguray
337a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowskibool LowEnergyClient::Connect(std::string address, bool is_direct) {
338a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  VLOG(2) << __func__ << "Address: " << address << " is_direct: " << is_direct;
339a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
340a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  bt_bdaddr_t bda;
341a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  util::BdAddrFromString(address, &bda);
342a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
343a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  bt_status_t status = hal::BluetoothGattInterface::Get()->
344a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      GetClientHALInterface()->connect(client_id_, &bda, is_direct,
345a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski                                       BT_TRANSPORT_LE);
346a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  if (status != BT_STATUS_SUCCESS) {
347a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    LOG(ERROR) << "HAL call to connect failed";
348a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    return false;
349a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  }
350a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
351a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  return true;
352a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski}
353a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
354a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowskibool LowEnergyClient::Disconnect(std::string address) {
355a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  VLOG(2) << __func__ << "Address: " << address;
356a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
357a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  bt_bdaddr_t bda;
358a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  util::BdAddrFromString(address, &bda);
359a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
360a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  std::map<const bt_bdaddr_t, int>::iterator conn_id;
361a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  {
362a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    lock_guard<mutex> lock(connection_fields_lock_);
363a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    conn_id = connection_ids_.find(bda);
364a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    if (conn_id == connection_ids_.end()) {
365a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      LOG(WARNING) << "Can't disconnect, no existing connection to " << address;
366a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      return false;
367a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    }
368a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  }
369a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
370a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  bt_status_t status = hal::BluetoothGattInterface::Get()->
371a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      GetClientHALInterface()->disconnect(client_id_, &bda, conn_id->second);
372a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  if (status != BT_STATUS_SUCCESS) {
373a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    LOG(ERROR) << "HAL call to disconnect failed";
374a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    return false;
375a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  }
376a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
377a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  return true;
378a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski}
379a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
380a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowskibool LowEnergyClient::SetMtu(std::string address, int mtu) {
381a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  VLOG(2) << __func__ << "Address: " << address
382a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski          << " MTU: " << mtu;
383a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
384a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  bt_bdaddr_t bda;
385a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  util::BdAddrFromString(address, &bda);
386a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
387a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  std::map<const bt_bdaddr_t, int>::iterator conn_id;
388a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  {
389a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    lock_guard<mutex> lock(connection_fields_lock_);
390a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    conn_id = connection_ids_.find(bda);
391a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    if (conn_id == connection_ids_.end()) {
392a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski      LOG(WARNING) << "Can't set MTU, no existing connection to " << address;
393a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski      return false;
394a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    }
395a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  }
396a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
397a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  bt_status_t status = hal::BluetoothGattInterface::Get()->
398a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski      GetClientHALInterface()->configure_mtu(conn_id->second, mtu);
399a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  if (status != BT_STATUS_SUCCESS) {
400a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    LOG(ERROR) << "HAL call to set MTU failed";
401a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    return false;
402a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  }
403a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
404a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  return true;
405a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski}
406a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
40782ea72f905565f83116f74d5ccbacea5d710a853Arman Ugurayvoid LowEnergyClient::SetDelegate(Delegate* delegate) {
40882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  lock_guard<mutex> lock(delegate_mutex_);
40982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  delegate_ = delegate;
41082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray}
41182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
412480174f874a664affda33831c904eb3574ae9389Arman Uguraybool LowEnergyClient::StartScan(const ScanSettings& settings,
413480174f874a664affda33831c904eb3574ae9389Arman Uguray                                const std::vector<ScanFilter>& filters) {
414480174f874a664affda33831c904eb3574ae9389Arman Uguray  VLOG(2) << __func__;
415480174f874a664affda33831c904eb3574ae9389Arman Uguray
416480174f874a664affda33831c904eb3574ae9389Arman Uguray  // Cannot start a scan if the adapter is not enabled.
417480174f874a664affda33831c904eb3574ae9389Arman Uguray  if (!adapter_.IsEnabled()) {
418480174f874a664affda33831c904eb3574ae9389Arman Uguray    LOG(ERROR) << "Cannot scan while Bluetooth is disabled";
419480174f874a664affda33831c904eb3574ae9389Arman Uguray    return false;
420480174f874a664affda33831c904eb3574ae9389Arman Uguray  }
421480174f874a664affda33831c904eb3574ae9389Arman Uguray
422480174f874a664affda33831c904eb3574ae9389Arman Uguray  // TODO(jpawlowski): Push settings and filtering logic below the HAL.
423480174f874a664affda33831c904eb3574ae9389Arman Uguray  bt_status_t status = hal::BluetoothGattInterface::Get()->
424480174f874a664affda33831c904eb3574ae9389Arman Uguray      StartScan(client_id_);
425480174f874a664affda33831c904eb3574ae9389Arman Uguray  if (status != BT_STATUS_SUCCESS) {
426480174f874a664affda33831c904eb3574ae9389Arman Uguray    LOG(ERROR) << "Failed to initiate scanning for client: " << client_id_;
427480174f874a664affda33831c904eb3574ae9389Arman Uguray    return false;
428480174f874a664affda33831c904eb3574ae9389Arman Uguray  }
429480174f874a664affda33831c904eb3574ae9389Arman Uguray
430480174f874a664affda33831c904eb3574ae9389Arman Uguray  scan_started_ = true;
431480174f874a664affda33831c904eb3574ae9389Arman Uguray  return true;
432480174f874a664affda33831c904eb3574ae9389Arman Uguray}
433480174f874a664affda33831c904eb3574ae9389Arman Uguray
434480174f874a664affda33831c904eb3574ae9389Arman Uguraybool LowEnergyClient::StopScan() {
435480174f874a664affda33831c904eb3574ae9389Arman Uguray  VLOG(2) << __func__;
436480174f874a664affda33831c904eb3574ae9389Arman Uguray
437480174f874a664affda33831c904eb3574ae9389Arman Uguray  // TODO(armansito): We don't support batch scanning yet so call
438480174f874a664affda33831c904eb3574ae9389Arman Uguray  // StopRegularScanForClient directly. In the future we will need to
439480174f874a664affda33831c904eb3574ae9389Arman Uguray  // conditionally call a batch scan API here.
440480174f874a664affda33831c904eb3574ae9389Arman Uguray  bt_status_t status = hal::BluetoothGattInterface::Get()->
441480174f874a664affda33831c904eb3574ae9389Arman Uguray      StopScan(client_id_);
442480174f874a664affda33831c904eb3574ae9389Arman Uguray  if (status != BT_STATUS_SUCCESS) {
443480174f874a664affda33831c904eb3574ae9389Arman Uguray    LOG(ERROR) << "Failed to stop scan for client: " << client_id_;
444480174f874a664affda33831c904eb3574ae9389Arman Uguray    return false;
445480174f874a664affda33831c904eb3574ae9389Arman Uguray  }
446480174f874a664affda33831c904eb3574ae9389Arman Uguray
447480174f874a664affda33831c904eb3574ae9389Arman Uguray  scan_started_ = false;
448480174f874a664affda33831c904eb3574ae9389Arman Uguray  return true;
449c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray}
450c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
45112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::StartAdvertising(const AdvertiseSettings& settings,
45212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray                                       const AdvertiseData& advertise_data,
45312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray                                       const AdvertiseData& scan_response,
45412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray                                       const StatusCallback& callback) {
45512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  VLOG(2) << __func__;
45612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  lock_guard<mutex> lock(adv_fields_lock_);
45712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
45812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (IsAdvertisingStarted()) {
45912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(WARNING) << "Already advertising";
46012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return false;
46112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
46212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
46312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (IsStartingAdvertising()) {
46412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(WARNING) << "StartAdvertising already pending";
46512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return false;
46612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
46712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
46812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (!advertise_data.IsValid()) {
46912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "Invalid advertising data";
47012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return false;
47112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
47212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
47312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (!scan_response.IsValid()) {
47412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "Invalid scan response data";
47512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return false;
47612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
47712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
47812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(!adv_data_needs_update_.load());
47912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(!scan_rsp_needs_update_.load());
48012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
48112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  adv_data_ = advertise_data;
48212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  scan_response_ = scan_response;
483d748ef2bcc24747659dadec242fd5a7a0c8ba3c4Jakub Pawlowski  advertise_settings_ = settings;
48412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
48512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  AdvertiseParams params;
48612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  GetAdvertiseParams(settings, !scan_response_.data().empty(), &params);
48712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
48812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  bt_status_t status = hal::BluetoothGattInterface::Get()->
48912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      GetClientHALInterface()->multi_adv_enable(
490bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray          client_id_,
49112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          params.min_interval,
49212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          params.max_interval,
49312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          params.event_type,
49412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          kAdvertisingChannelAll,
49512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          params.tx_power_level,
49612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          params.timeout_s);
49712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (status != BT_STATUS_SUCCESS) {
49812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "Failed to initiate call to enable multi-advertising";
49912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return false;
50012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
50112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
50212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // Always update advertising data.
50312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  adv_data_needs_update_ = true;
50412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
50512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // Update scan response only if it has data, since otherwise we just won't
50612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // send ADV_SCAN_IND.
50712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (!scan_response_.data().empty())
50812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    scan_rsp_needs_update_ = true;
50912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
51012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // OK to set this at the end since we're still holding |adv_fields_lock_|.
51112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  adv_start_callback_.reset(new StatusCallback(callback));
51212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
51312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  return true;
51412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
51512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
51612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::StopAdvertising(const StatusCallback& callback) {
51712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  VLOG(2) << __func__;
51812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  lock_guard<mutex> lock(adv_fields_lock_);
51912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
52012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (!IsAdvertisingStarted()) {
52112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "Not advertising";
52212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return false;
52312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
52412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
52512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (IsStoppingAdvertising()) {
52612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "StopAdvertising already pending";
52712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return false;
52812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
52912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
53012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(!adv_start_callback_);
53112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
53212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  bt_status_t status = hal::BluetoothGattInterface::Get()->
533bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray      GetClientHALInterface()->multi_adv_disable(client_id_);
53412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (status != BT_STATUS_SUCCESS) {
53512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "Failed to initiate call to disable multi-advertising";
53612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return false;
53712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
53812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
53912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // OK to set this at the end since we're still holding |adv_fields_lock_|.
54012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  adv_stop_callback_.reset(new StatusCallback(callback));
54112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
54212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  return true;
54312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
54412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
54512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::IsAdvertisingStarted() const {
54612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  return adv_started_.load();
54712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
54812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
54912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::IsStartingAdvertising() const {
55012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  return !IsAdvertisingStarted() && adv_start_callback_;
55112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
55212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
55312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybool LowEnergyClient::IsStoppingAdvertising() const {
55412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  return IsAdvertisingStarted() && adv_stop_callback_;
55512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
55612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
55708f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Ugurayconst UUID& LowEnergyClient::GetAppIdentifier() const {
55808f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray  return app_identifier_;
55908f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray}
56008f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray
561bb18c41ffa0370d4eb0c4a15904b114355606466Arman Ugurayint LowEnergyClient::GetInstanceId() const {
562bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray  return client_id_;
56308f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray}
56408f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray
56582ea72f905565f83116f74d5ccbacea5d710a853Arman Ugurayvoid LowEnergyClient::ScanResultCallback(
56682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    hal::BluetoothGattInterface* gatt_iface,
56782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) {
56882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  // Ignore scan results if this client didn't start a scan.
56982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  if (!scan_started_.load())
57082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    return;
57182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
57282ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  lock_guard<mutex> lock(delegate_mutex_);
57382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  if (!delegate_)
57482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray    return;
57582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
57682ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  // TODO(armansito): Apply software filters here.
57782ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
57882ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  size_t record_len = GetScanRecordLength(adv_data);
57982ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  std::vector<uint8_t> scan_record(adv_data, adv_data + record_len);
58082ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
58182ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  ScanResult result(BtAddrString(&bda), scan_record, rssi);
58282ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
58382ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray  delegate_->OnScanResult(this, result);
58482ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray}
58582ea72f905565f83116f74d5ccbacea5d710a853Arman Uguray
586a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowskivoid LowEnergyClient::ConnectCallback(
587a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
588a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      int client_id, const bt_bdaddr_t& bda) {
589a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  if (client_id != client_id_)
590a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    return;
591a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
592a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
593a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
594a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  {
595a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    lock_guard<mutex> lock(connection_fields_lock_);
596a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    auto success = connection_ids_.emplace(bda, conn_id);
597a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    if (!success.second) {
598a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      LOG(ERROR) << __func__ << " Insertion into connection_ids_ failed!";
599a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    }
600a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  }
601a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
602a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  if (delegate_)
603a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
604a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski                                 true);
605a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski}
606a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
607a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowskivoid LowEnergyClient::DisconnectCallback(
608a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
609a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      int client_id, const bt_bdaddr_t& bda) {
610a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  if (client_id != client_id_)
611a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    return;
612a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
613a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  VLOG(1) << __func__ << " client_id: " << client_id << " status: " << status;
614a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  {
615a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    lock_guard<mutex> lock(connection_fields_lock_);
616a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    if (!connection_ids_.erase(bda)) {
617a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski      LOG(ERROR) << __func__ << " Erasing from connection_ids_ failed!";
618a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    }
619a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  }
620a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
621a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski  if (delegate_)
622a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski    delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
623a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski                                 false);
624a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski}
625a6372e984aea35ffb451fca378046efbf280291cJakub Pawlowski
626a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowskivoid LowEnergyClient::MtuChangedCallback(
627a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski      hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
628a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski      int mtu) {
629a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status
630a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski          << " mtu: " << mtu;
631a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
632a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  const bt_bdaddr_t *bda = nullptr;
633a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  {
634a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    lock_guard<mutex> lock(connection_fields_lock_);
635a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    for (auto& connection: connection_ids_) {
636a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski      if (connection.second == conn_id) {
637a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski        bda = &connection.first;
638a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski        break;
639a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski      }
640a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    }
641a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  }
642a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
643a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  if (!bda)
644a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    return;
645a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
646a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  const char *addr = BtAddrString(bda).c_str();
647a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski  if (delegate_)
648a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski    delegate_->OnMtuChanged(this, status, addr, mtu);
649a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski}
650a6551079fe71b1c76505ada0e4f758f6faf651e0Jakub Pawlowski
65112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::MultiAdvEnableCallback(
65212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    hal::BluetoothGattInterface* gatt_iface,
653bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray    int client_id, int status) {
654bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray  if (client_id != client_id_)
65512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return;
65612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
65712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  lock_guard<mutex> lock(adv_fields_lock_);
65812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
659bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray  VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
66012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
66112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(adv_start_callback_);
66212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(!adv_stop_callback_);
66312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
66412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // Terminate operation in case of error.
66512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (status != BT_STATUS_SUCCESS) {
66612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "Failed to enable multi-advertising";
66712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    InvokeAndClearStartCallback(GetBLEStatus(status));
66812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return;
66912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
67012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
67112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // Now handle deferred tasks.
67212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  HandleDeferredAdvertiseData(gatt_iface);
67312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
67412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
67512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::MultiAdvDataCallback(
67612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    hal::BluetoothGattInterface* gatt_iface,
677bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray    int client_id, int status) {
678bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray  if (client_id != client_id_)
67912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return;
68012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
68112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  lock_guard<mutex> lock(adv_fields_lock_);
68212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
683bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray  VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
68412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
68512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  is_setting_adv_data_ = false;
68612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
68712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // Terminate operation in case of error.
68812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (status != BT_STATUS_SUCCESS) {
68912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "Failed to set advertising data";
69012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    InvokeAndClearStartCallback(GetBLEStatus(status));
69112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return;
69212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
69312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
69412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // Now handle deferred tasks.
69512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  HandleDeferredAdvertiseData(gatt_iface);
69612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
69712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
69812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::MultiAdvDisableCallback(
69912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    hal::BluetoothGattInterface* /* gatt_iface */,
700bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray    int client_id, int status) {
701bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray  if (client_id != client_id_)
70212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return;
70312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
70412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  lock_guard<mutex> lock(adv_fields_lock_);
70512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
706bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray  VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
70712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
70812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(!adv_start_callback_);
70912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(adv_stop_callback_);
71012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
71112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (status == BT_STATUS_SUCCESS) {
712bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray    VLOG(1) << "Multi-advertising stopped for client_id: " << client_id;
71312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    adv_started_ = false;
71412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  } else {
71512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "Failed to stop multi-advertising";
71612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
71712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
71812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  InvokeAndClearStopCallback(GetBLEStatus(status));
71912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
72012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
72112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguraybt_status_t LowEnergyClient::SetAdvertiseData(
72212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    hal::BluetoothGattInterface* gatt_iface,
72312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    const AdvertiseData& data,
72412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    bool set_scan_rsp) {
72512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  VLOG(2) << __func__;
72612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
72712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  HALAdvertiseData hal_data;
72812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
72912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // TODO(armansito): The stack should check that the length is valid when other
73012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // fields inserted by the stack (e.g. flags, device name, tx-power) are taken
73112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // into account. At the moment we are skipping this check; this means that if
73212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // the given data is too long then the stack will truncate it.
73312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (!ProcessAdvertiseData(data, &hal_data)) {
734ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    LOG(ERROR) << "Malformed advertise data given";
73512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return BT_STATUS_FAIL;
73612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
73712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
73812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (is_setting_adv_data_.load()) {
739ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker    LOG(ERROR) << "Setting advertising data already in progress.";
74012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return BT_STATUS_FAIL;
74112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
74212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
74312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // TODO(armansito): The length fields in the BTIF function below are signed
74412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // integers so a call to std::vector::size might get capped. This is very
74512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // unlikely anyway but it's safer to stop using signed-integer types for
74612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // length in APIs, so we should change that.
74712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  bt_status_t status = gatt_iface->GetClientHALInterface()->
74812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      multi_adv_set_inst_data(
749bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray          client_id_,
75012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          set_scan_rsp,
75112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          data.include_device_name(),
75212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          data.include_tx_power_level(),
75312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          0,  // This is what Bluetooth.apk current hardcodes for "appearance".
75412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          hal_data.manufacturer_data.size(),
75512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray          reinterpret_cast<char*>(hal_data.manufacturer_data.data()),
756ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker          hal_data.service_data.size(),
757ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker          reinterpret_cast<char*>(hal_data.service_data.data()),
758ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker          hal_data.service_uuid.size(),
759ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker          reinterpret_cast<char*>(hal_data.service_uuid.data()));
760ff651b7fd11daaa29732cb8735d248910d9248f9Ajay Panicker
76112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (status != BT_STATUS_SUCCESS) {
76212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    LOG(ERROR) << "Failed to set instance advertising data.";
76312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return status;
76412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
76512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
76612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (set_scan_rsp)
76712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    scan_rsp_needs_update_ = false;
76812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  else
76912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    adv_data_needs_update_ = false;
77012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
77112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  is_setting_adv_data_ = true;
77212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
77312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  return status;
77412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
77512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
77612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::HandleDeferredAdvertiseData(
77712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    hal::BluetoothGattInterface* gatt_iface) {
77812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  VLOG(2) << __func__;
77912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
78012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(!IsAdvertisingStarted());
78112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(!IsStoppingAdvertising());
78212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(IsStartingAdvertising());
78312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  CHECK(!is_setting_adv_data_.load());
78412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
78512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (adv_data_needs_update_.load()) {
78612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    bt_status_t status = SetAdvertiseData(gatt_iface, adv_data_, false);
78712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    if (status != BT_STATUS_SUCCESS) {
78812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      LOG(ERROR) << "Failed setting advertisement data";
78912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      InvokeAndClearStartCallback(GetBLEStatus(status));
79012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    }
79112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return;
79212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
79312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
79412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (scan_rsp_needs_update_.load()) {
79512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    bt_status_t status = SetAdvertiseData(gatt_iface, scan_response_, true);
79612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    if (status != BT_STATUS_SUCCESS) {
79712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      LOG(ERROR) << "Failed setting scan response data";
79812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray      InvokeAndClearStartCallback(GetBLEStatus(status));
79912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    }
80012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    return;
80112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  }
80212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
80312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // All pending tasks are complete. Report success.
80412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  adv_started_ = true;
80512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  InvokeAndClearStartCallback(BLE_STATUS_SUCCESS);
80612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
80712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
80812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::InvokeAndClearStartCallback(BLEStatus status) {
80912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  adv_data_needs_update_ = false;
81012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  scan_rsp_needs_update_ = false;
81112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
81212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // We allow NULL callbacks.
81312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (*adv_start_callback_)
81412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    (*adv_start_callback_)(status);
81512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
81612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  adv_start_callback_ = nullptr;
81712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
81812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
81912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Ugurayvoid LowEnergyClient::InvokeAndClearStopCallback(BLEStatus status) {
82012338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  // We allow NULL callbacks.
82112338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  if (*adv_stop_callback_)
82212338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    (*adv_stop_callback_)(status);
82312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
82412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray  adv_stop_callback_ = nullptr;
82512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray}
82612338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
82712338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// LowEnergyClientFactory implementation
82812338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray// ========================================================
82912338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
83060b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub PawlowskiLowEnergyClientFactory::LowEnergyClientFactory(Adapter& adapter)
83160b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski    : adapter_(adapter) {
832c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  hal::BluetoothGattInterface::Get()->AddClientObserver(this);
833c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray}
834c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
835c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman UgurayLowEnergyClientFactory::~LowEnergyClientFactory() {
836c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
837c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray}
838c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
839bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguraybool LowEnergyClientFactory::RegisterInstance(
840bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray    const UUID& uuid,
841bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray    const RegisterCallback& callback) {
842c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
843c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  lock_guard<mutex> lock(pending_calls_lock_);
844c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
845c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  if (pending_calls_.find(uuid) != pending_calls_.end()) {
846c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray    LOG(ERROR) << "Low-Energy client with given UUID already registered - "
847c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray               << "UUID: " << uuid.ToString();
848c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray    return false;
849c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  }
850c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
851c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  const btgatt_client_interface_t* hal_iface =
852c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray      hal::BluetoothGattInterface::Get()->GetClientHALInterface();
853c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  bt_uuid_t app_uuid = uuid.GetBlueDroid();
854c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
855c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  if (hal_iface->register_client(&app_uuid) != BT_STATUS_SUCCESS)
856c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray    return false;
857c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
858c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  pending_calls_[uuid] = callback;
859c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
860c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  return true;
861c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray}
862c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
863c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Ugurayvoid LowEnergyClientFactory::RegisterClientCallback(
86412338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray    hal::BluetoothGattInterface* gatt_iface,
865bb18c41ffa0370d4eb0c4a15904b114355606466Arman Uguray    int status, int client_id,
866c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray    const bt_uuid_t& app_uuid) {
867c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  UUID uuid(app_uuid);
868c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
869c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
870c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  lock_guard<mutex> lock(pending_calls_lock_);
871c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
872c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  auto iter = pending_calls_.find(uuid);
873c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  if (iter == pending_calls_.end()) {
874c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray    VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
875c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray    return;
876c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  }
877c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
878c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  // No need to construct a client if the call wasn't successful.
879c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  std::unique_ptr<LowEnergyClient> client;
880c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  BLEStatus result = BLE_STATUS_FAILURE;
881c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  if (status == BT_STATUS_SUCCESS) {
88260b0e8f7ef14b1c0bd0e6d86656cd912dd4c4221Jakub Pawlowski    client.reset(new LowEnergyClient(adapter_, uuid, client_id));
88312338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
88425689c1676ab911fa7887ec87b730b00325e4b90Jakub Pawlowski    gatt_iface->AddClientObserver(client.get());
88512338405e0d8d70573e650560ccc8e1ce7d8e8cdArman Uguray
886c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray    result = BLE_STATUS_SUCCESS;
887c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  }
888c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
88908f80ebd5c714364cb76cc4e4a93454b42ed5669Arman Uguray  // Notify the result via the result callback.
890c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  iter->second(result, uuid, std::move(client));
891c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
892c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray  pending_calls_.erase(iter);
893c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray}
894c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray
895c2fc0f287f4dfaf206a51856b8d5dfa923af3c05Arman Uguray}  // namespace bluetooth
896