// Copyright 2022 Google LLC // // 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 // // https://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 "presence/implementation/scan_manager.h" #include #include #include #include #include #include #include "absl/status/status.h" #include "absl/types/variant.h" #include "internal/platform/implementation/crypto.h" #include "internal/platform/future.h" #include "internal/platform/implementation/ble_v2.h" #include "internal/platform/implementation/credential_callbacks.h" #include "internal/platform/uuid.h" #include "presence/data_types.h" #include "presence/implementation/advertisement_decoder.h" #include "presence/implementation/mediums/ble.h" #include "presence/presence_device.h" #include "presence/scan_request.h" namespace nearby { namespace presence { namespace { using BleAdvertisementData = ::nearby::api::ble_v2::BleAdvertisementData; using BlePeripheral = ::nearby::api::ble_v2::BlePeripheral; using ScanningSession = ::nearby::api::ble_v2::BleMedium::ScanningSession; using ScanningCallback = ::nearby::api::ble_v2::BleMedium::ScanningCallback; } // namespace ScanSessionId ScanManager::StartScan(ScanRequest scan_request, ScanCallback cb) { ScanSessionId id = nearby::RandData(); RunOnServiceControllerThread( "start-scan", [this, id, scan_request, scan_callback = std::move(cb)]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) mutable { ScanningCallback callback = ScanningCallback{ .start_scanning_result = [start_scan_client = std::move(scan_callback.start_scan_cb)]( absl::Status ble_status) mutable { start_scan_client(ble_status); }, .advertisement_found_cb = [this, id](BlePeripheral& peripheral, BleAdvertisementData data) { RunOnServiceControllerThread( "notify-found-ble", [this, id, data = std::move(data), address = peripheral.GetAddress()]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { NotifyFoundBle(id, data, address); }); }}; FetchCredentials(id, scan_request); scan_sessions_.insert( {id, ScanSessionState{ .request = scan_request, .callback = std::move(scan_callback), .decoder = AdvertisementDecoder(scan_request), .scanning_session = mediums_->GetBle().StartScanning( scan_request, std::move(callback))}}); }); return id; } void ScanManager::StopScan(ScanSessionId id) { RunOnServiceControllerThread( "stop-scan", [this, id]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { auto it = scan_sessions_.find(id); if (it == scan_sessions_.end()) { return; } if (it->second.scanning_session) { absl::Status status = it->second.scanning_session->stop_scanning(); if (!status.ok()) { NEARBY_LOGS(WARNING) << "StopScan error: " << status; } } scan_sessions_.erase(it); }); } void ScanManager::NotifyFoundBle(ScanSessionId id, BleAdvertisementData data, absl::string_view remote_address) { auto advertisement_data = data.service_data[kPresenceServiceUuid].AsStringView(); auto it = scan_sessions_.find(id); if (it == scan_sessions_.end()) { return; } auto advert = it->second.decoder.DecodeAdvertisement(advertisement_data); if (!advert.ok()) { // This advertisement is not relevant to the current element, skip. return; } if (it->second.decoder.MatchesScanFilter(advert->data_elements)) { internal::Metadata metadata; metadata.set_bluetooth_mac_address(std::string(remote_address)); PresenceDevice device(DeviceMotion(), metadata, advert->identity_type); // Ok if the advertisement is for trusted/private identity. if (advert->public_credential.ok()) { device.SetDecryptSharedCredential(*(advert->public_credential)); } device.AddExtendedProperties(advert->data_elements); for (const auto& data_element : advert->data_elements) { if (data_element.GetType() == DataElement::kActionFieldType) { device.AddAction(PresenceAction(static_cast( static_cast(data_element.GetValue()[0])))); } } it->second.callback.on_discovered_cb(std::move(device)); } } void ScanManager::FetchCredentials(ScanSessionId id, const ScanRequest& scan_request) { std::vector credential_selectors = AdvertisementDecoder::GetCredentialSelectors(scan_request); for (const CredentialSelector& selector : credential_selectors) { // Not fetching for PUBLIC. if (selector.identity_type == internal::IDENTITY_TYPE_UNSPECIFIED || selector.identity_type == internal::IDENTITY_TYPE_PUBLIC) { NEARBY_LOGS(INFO) << __func__ << ": skip feteching creds for identity type: " << selector.identity_type; continue; } credential_manager_->GetPublicCredentials( selector, PublicCredentialType::kRemotePublicCredential, {.credentials_fetched_cb = [this, id, identity_type = selector.identity_type]( absl::StatusOr< std::vector<::nearby::internal::SharedCredential>> credentials) { if (!credentials.ok()) { NEARBY_LOGS(WARNING) << "Failed to fetch credentials: " << credentials.status(); return; } RunOnServiceControllerThread( "update-credentials", [this, id, identity_type, credentials = std::move(*credentials)]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { UpdateCredentials(id, identity_type, std::move(credentials)); }); }}); } } void ScanManager::UpdateCredentials(ScanSessionId id, IdentityType identity_type, std::vector credentials) { auto it = scan_sessions_.find(id); if (it == scan_sessions_.end()) { return; } ScanSessionState& session = it->second; session.credentials[identity_type] = std::move(credentials); session.decoder = AdvertisementDecoder(session.request, &session.credentials); } int ScanManager::ScanningCallbacksLengthForTest() { ::nearby::Future count; RunOnServiceControllerThread("callbacks-size", [&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { count.Set(scan_sessions_.size()); }); return count.Get().GetResult(); } } // namespace presence } // namespace nearby