| // | 
 | //  Copyright (C) 2016 The Android Open Source Project | 
 | // | 
 | //  Licensed under the Apache License, Version 2.0 (the "License"); | 
 | //  you may not use this file except in compliance with the License. | 
 | //  You may obtain a copy of the License at: | 
 | // | 
 | //  http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | //  Unless required by applicable law or agreed to in writing, software | 
 | //  distributed under the License is distributed on an "AS IS" BASIS, | 
 | //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | //  See the License for the specific language governing permissions and | 
 | //  limitations under the License. | 
 | // | 
 |  | 
 | #include "service/low_energy_scanner.h" | 
 |  | 
 | #include <base/bind.h> | 
 | #include <base/logging.h> | 
 |  | 
 | #include "service/adapter.h" | 
 | #include "service/common/bluetooth/util/address_helper.h" | 
 | #include "service/logging_helpers.h" | 
 | #include "stack/include/bt_types.h" | 
 | #include "stack/include/hcidefs.h" | 
 |  | 
 | using std::lock_guard; | 
 | using std::mutex; | 
 |  | 
 | namespace bluetooth { | 
 |  | 
 | namespace { | 
 |  | 
 | // 31 + 31 for advertising data and scan response. This is the maximum length | 
 | // TODO(armansito): Fix the HAL to return a concatenated blob that contains the | 
 | // true length of each field and also provide a length parameter so that we | 
 | // can support advertising length extensions in the future. | 
 | const size_t kScanRecordLength = 62; | 
 |  | 
 | // Returns the length of the given scan record array. We have to calculate this | 
 | // based on the maximum possible data length and the TLV data. See TODO above | 
 | // |kScanRecordLength|. | 
 | size_t GetScanRecordLength(vector<uint8_t> bytes) { | 
 |   for (size_t i = 0, field_len = 0; i < kScanRecordLength; | 
 |        i += (field_len + 1)) { | 
 |     field_len = bytes[i]; | 
 |  | 
 |     // Assert here that the data returned from the stack is correctly formatted | 
 |     // in TLV form and that the length of the current field won't exceed the | 
 |     // total data length. | 
 |     CHECK(i + field_len < kScanRecordLength); | 
 |  | 
 |     // If the field length is zero and we haven't reached the maximum length, | 
 |     // then we have found the length, as the stack will pad the data with zeros | 
 |     // accordingly. | 
 |     if (field_len == 0) | 
 |       return i; | 
 |   } | 
 |  | 
 |   // We have reached the end. | 
 |   return kScanRecordLength; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | // LowEnergyScanner implementation | 
 | // ======================================================== | 
 |  | 
 | LowEnergyScanner::LowEnergyScanner(Adapter& adapter, const UUID& uuid, | 
 |                                    int scanner_id) | 
 |     : adapter_(adapter), | 
 |       app_identifier_(uuid), | 
 |       scanner_id_(scanner_id), | 
 |       scan_started_(false), | 
 |       delegate_(nullptr) {} | 
 |  | 
 | LowEnergyScanner::~LowEnergyScanner() { | 
 |   // Automatically unregister the scanner. | 
 |   VLOG(1) << "LowEnergyScanner unregistering scanner: " << scanner_id_; | 
 |  | 
 |   // Unregister as observer so we no longer receive any callbacks. | 
 |   hal::BluetoothGattInterface::Get()->RemoveScannerObserver(this); | 
 |  | 
 |   hal::BluetoothGattInterface::Get()-> | 
 |       GetScannerHALInterface()->unregister_scanner(scanner_id_); | 
 |  | 
 |   // Stop any scans started by this client. | 
 |   if (scan_started_.load()) | 
 |     StopScan(); | 
 | } | 
 |  | 
 | void LowEnergyScanner::SetDelegate(Delegate* delegate) { | 
 |   lock_guard<mutex> lock(delegate_mutex_); | 
 |   delegate_ = delegate; | 
 | } | 
 |  | 
 | bool LowEnergyScanner::StartScan(const ScanSettings& settings, | 
 |                                 const std::vector<ScanFilter>& filters) { | 
 |   VLOG(2) << __func__; | 
 |  | 
 |   // Cannot start a scan if the adapter is not enabled. | 
 |   if (!adapter_.IsEnabled()) { | 
 |     LOG(ERROR) << "Cannot scan while Bluetooth is disabled"; | 
 |     return false; | 
 |   } | 
 |  | 
 |   // TODO(jpawlowski): Push settings and filtering logic below the HAL. | 
 |   bt_status_t status = hal::BluetoothGattInterface::Get()-> | 
 |       StartScan(scanner_id_); | 
 |   if (status != BT_STATUS_SUCCESS) { | 
 |     LOG(ERROR) << "Failed to initiate scanning for client: " << scanner_id_; | 
 |     return false; | 
 |   } | 
 |  | 
 |   scan_started_ = true; | 
 |   return true; | 
 | } | 
 |  | 
 | bool LowEnergyScanner::StopScan() { | 
 |   VLOG(2) << __func__; | 
 |  | 
 |   // TODO(armansito): We don't support batch scanning yet so call | 
 |   // StopRegularScanForClient directly. In the future we will need to | 
 |   // conditionally call a batch scan API here. | 
 |   bt_status_t status = hal::BluetoothGattInterface::Get()-> | 
 |       StopScan(scanner_id_); | 
 |   if (status != BT_STATUS_SUCCESS) { | 
 |     LOG(ERROR) << "Failed to stop scan for client: " << scanner_id_; | 
 |     return false; | 
 |   } | 
 |  | 
 |   scan_started_ = false; | 
 |   return true; | 
 | } | 
 |  | 
 | const UUID& LowEnergyScanner::GetAppIdentifier() const { | 
 |   return app_identifier_; | 
 | } | 
 |  | 
 | int LowEnergyScanner::GetInstanceId() const { | 
 |   return scanner_id_; | 
 | } | 
 |  | 
 | void LowEnergyScanner::ScanResultCallback( | 
 |     hal::BluetoothGattInterface* gatt_iface, | 
 |     const bt_bdaddr_t& bda, int rssi, vector<uint8_t> adv_data) { | 
 |   // Ignore scan results if this client didn't start a scan. | 
 |   if (!scan_started_.load()) | 
 |     return; | 
 |  | 
 |   lock_guard<mutex> lock(delegate_mutex_); | 
 |   if (!delegate_) | 
 |     return; | 
 |  | 
 |   // TODO(armansito): Apply software filters here. | 
 |  | 
 |   size_t record_len = GetScanRecordLength(adv_data); | 
 |   std::vector<uint8_t> scan_record(adv_data.begin(), adv_data.begin() + record_len); | 
 |  | 
 |   ScanResult result(BtAddrString(&bda), scan_record, rssi); | 
 |  | 
 |   delegate_->OnScanResult(this, result); | 
 | } | 
 |  | 
 | // LowEnergyScannerFactory implementation | 
 | // ======================================================== | 
 |  | 
 | LowEnergyScannerFactory::LowEnergyScannerFactory(Adapter& adapter) : adapter_(adapter) { | 
 |   hal::BluetoothGattInterface::Get()->AddScannerObserver(this); | 
 | } | 
 |  | 
 | LowEnergyScannerFactory::~LowEnergyScannerFactory() { | 
 |   hal::BluetoothGattInterface::Get()->RemoveScannerObserver(this); | 
 | } | 
 |  | 
 | bool LowEnergyScannerFactory::RegisterInstance( | 
 |     const UUID& uuid, | 
 |     const RegisterCallback& callback) { | 
 |   VLOG(1) << __func__ << " - UUID: " << uuid.ToString(); | 
 |   lock_guard<mutex> lock(pending_calls_lock_); | 
 |  | 
 |   if (pending_calls_.find(uuid) != pending_calls_.end()) { | 
 |     LOG(ERROR) << "Low-Energy scanner with given UUID already registered - " | 
 |                << "UUID: " << uuid.ToString(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   const btgatt_scanner_interface_t* hal_iface = | 
 |       hal::BluetoothGattInterface::Get()->GetScannerHALInterface(); | 
 |   bt_uuid_t app_uuid = uuid.GetBlueDroid(); | 
 |  | 
 |   if (hal_iface->register_scanner(&app_uuid) != BT_STATUS_SUCCESS) | 
 |     return false; | 
 |  | 
 |   pending_calls_[uuid] = callback; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | void LowEnergyScannerFactory::RegisterScannerCallback( | 
 |     hal::BluetoothGattInterface* gatt_iface, | 
 |     int status, int scanner_id, | 
 |     const bt_uuid_t& app_uuid) { | 
 |   UUID uuid(app_uuid); | 
 |  | 
 |   VLOG(1) << __func__ << " - UUID: " << uuid.ToString(); | 
 |   lock_guard<mutex> lock(pending_calls_lock_); | 
 |  | 
 |   auto iter = pending_calls_.find(uuid); | 
 |   if (iter == pending_calls_.end()) { | 
 |     VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString(); | 
 |     return; | 
 |   } | 
 |  | 
 |   // No need to construct a scanner if the call wasn't successful. | 
 |   std::unique_ptr<LowEnergyScanner> scanner; | 
 |   BLEStatus result = BLE_STATUS_FAILURE; | 
 |   if (status == BT_STATUS_SUCCESS) { | 
 |     scanner.reset(new LowEnergyScanner(adapter_, uuid, scanner_id)); | 
 |  | 
 |     gatt_iface->AddScannerObserver(scanner.get()); | 
 |  | 
 |     result = BLE_STATUS_SUCCESS; | 
 |   } | 
 |  | 
 |   // Notify the result via the result callback. | 
 |   iter->second(result, uuid, std::move(scanner)); | 
 |  | 
 |   pending_calls_.erase(iter); | 
 | } | 
 |  | 
 |  | 
 | }  // namespace bluetooth |