// 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. // Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly // classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation // classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and // Objective-C++ scores. Oddly, "#import " does not contribute any points. // This comment alone should be enough to trick the IDE in to believing this is actually some sort // of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data #import #include #include #include #include #include "internal/platform/cancellation_flag.h" #import "internal/platform/implementation/apple/ble_l2cap_server_socket.h" #import "internal/platform/implementation/apple/ble_server_socket.h" #import "internal/platform/implementation/apple/bluetooth_adapter_v2.h" #import "internal/platform/implementation/apple/single_thread_executor.h" #include "internal/platform/implementation/ble.h" #include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/uuid.h" @class GNCBLEMedium; @class GNSCentralManager; @class GNSPeripheralManager; @class GNSPeripheralServiceManager; namespace nearby { namespace apple { class BleMediumPeer; // The main BLE medium used inside of Nearby. This serves as the entry point for all BLE and GATT // related operations. class BleMedium : public api::ble::BleMedium { friend class BleMediumPeer; public: // Define factory types for managers. using PeripheralManagerFactory = std::function; using CentralManagerFactory = std::function; BleMedium(); // For testing only. explicit BleMedium(GNCBLEMedium *medium); ~BleMedium() override; // Async interface for StartAdvertising. // // Result status will be passed to start_advertising_result callback. To stop advertising, invoke // the stop_advertising callback in AdvertisingSession. // // Advertising must be stopped before attempting to start advertising again. std::unique_ptr StartAdvertising( const api::ble::BleAdvertisementData &advertising_data, api::ble::AdvertiseParameters advertise_set_parameters, api::ble::BleMedium::AdvertisingCallback callback) override; // Starts BLE advertising and returns whether or not it was successful. // // Advertising must be stopped before attempting to start advertising again. bool StartAdvertising(const api::ble::BleAdvertisementData &advertising_data, api::ble::AdvertiseParameters advertise_set_parameters) override; // Stops advertising. // // Returns whether or not advertising was successfully stopped. bool StopAdvertising() override; // Async interface for StartScanning. // // Result status will be passed to start_scanning_result callback on a private queue. To stop // scanning, invoke the stop_scanning callback in ScanningSession. // // Scanning must be stopped before attempting to start scanning again. std::unique_ptr StartScanning( const Uuid &service_uuid, api::ble::TxPowerLevel tx_power_level, api::ble::BleMedium::ScanningCallback callback) override; // Starts scanning and returns whether or not it was successful. // // Scanning must be stopped before attempting to start scanning again. bool StartScanning(const Uuid &service_uuid, api::ble::TxPowerLevel tx_power_level, api::ble::BleMedium::ScanCallback callback) override; // Starts scanning on multiple services and returns whether or not it was successful. bool StartMultipleServicesScanning(const std::vector &service_uuids, api::ble::TxPowerLevel tx_power_level, api::ble::BleMedium::ScanCallback callback) override; // Stops scanning. // // Returns whether or not scanning was successfully stopped. bool StopScanning() override; // Pauses BLE scanning at platform Medium level. // // Returns whether or not scanning was successfully paused. bool PauseMediumScanning() override; // Resumes BLE scanning at platform Medium level. // // Returns whether or not scanning was successfully resumed. bool ResumeMediumScanning() override; // TODO(b/290385712): ServerGattConnectionCallback methods are not yet implemented. // // Starts a GATT server. Returns a nullptr upon error. std::unique_ptr StartGattServer( api::ble::ServerGattConnectionCallback callback) override; // Connects to a GATT server and negotiates the specified connection parameters. Returns nullptr // upon error. // // The peripheral must outlive the GATT client or undefined behavior will occur. The peripheral // should not be modified by this method. std::unique_ptr ConnectToGattServer( api::ble::BlePeripheral::UniqueId peripheral_id, api::ble::TxPowerLevel tx_power_level, api::ble::ClientGattConnectionCallback callback) override; // Opens a BLE server socket based on service ID. // // On success, returns a new BleServerSocket. On error, returns nullptr. std::unique_ptr OpenServerSocket( const std::string &service_id) override; // Opens a L2CAP server socket based on service ID. // // On success, returns a new BleL2capServerSocket. On error, returns nullptr. std::unique_ptr OpenL2capServerSocket( const std::string &service_id) override; // TODO(b/290385712): cancellation_flag support is not yet implemented. // // Connects to a BLE peripheral. // // The peripheral must outlive the socket or undefined behavior will occur. The peripheral // should not be modified by this method. // // On success, returns a new BleSocket. On error, returns nullptr. std::unique_ptr Connect(const std::string &service_id, api::ble::TxPowerLevel tx_power_level, api::ble::BlePeripheral::UniqueId peripheral_id, CancellationFlag *cancellation_flag) override; // TODO(b/290385712): cancellation_flag support is not yet implemented. // // Connects to a BLE peripheral over L2CAP. // // The peripheral must outlive the socket or undefined behavior will occur. The peripheral // should not be modified by this method. // // On success, returns a new BleL2capSocket. On error, returns nullptr. std::unique_ptr ConnectOverL2cap( int psm, const std::string &service_id, api::ble::TxPowerLevel tx_power_level, api::ble::BlePeripheral::UniqueId peripheral_id, CancellationFlag *cancellation_flag) override; // Returns whether the hardware supports BOTH advertising extensions and extended scans. // // This is currently always false for all Apple hardware. bool IsExtendedAdvertisementsAvailable() override; // Retrieves a BlePeripheral ID from a native BLE peripheral ID. // On Apple platform, the native ID is NSUUID in string format like // "E621E1F8-C36C-495A-93FC-0C247A3E6E5F". // // Returns std::nullopt if cannot retrieve the BlePeripheral from the native // BLE peripheral id. std::optional RetrieveBlePeripheralIdFromNativeId( const std::string &ble_peripheral_native_id) override; private: // A map for maintaining the set of currently known peripherals. class PeripheralsMap { public: PeripheralsMap() = default; ~PeripheralsMap() = default; api::ble::BlePeripheral::UniqueId Add(id peripheral) ABSL_LOCKS_EXCLUDED(mutex_); id Get(api::ble::BlePeripheral::UniqueId peripheral_id) ABSL_LOCKS_EXCLUDED(mutex_); void Clear() ABSL_LOCKS_EXCLUDED(mutex_); private: absl::Mutex mutex_; absl::flat_hash_map> peripherals_ ABSL_GUARDED_BY(mutex_); }; void HandleAdvertisementFound(id peripheral, NSDictionary *serviceData); void ClearAdvertisementPacketsMap(); bool ShouldReportAdvertisement(NSDate *now, api::ble::BlePeripheral::UniqueId peripheral_id, NSDictionary *service_data); void AddAdvertisementPacketInfo(api::ble::BlePeripheral::UniqueId peripheral_id, NSDictionary *service_data); NSDate *GetLastTimestampToCleanExpiredAdvertisementPackets(); // Opens a BLE server socket based on service ID with deadlock safety. std::unique_ptr OpenServerSocketWithDeadlockSafety( const std::string &service_id); // Opens a BLE server socket based on service ID using the legacy implementation. std::unique_ptr OpenServerSocketLegacy(const std::string &service_id); // The executor for handling callbacks. apple::SingleThreadExecutor callback_executor_; // Factories for lazy initialization PeripheralManagerFactory peripheral_manager_factory_ = nullptr; CentralManagerFactory central_manager_factory_ = nullptr; GNCBLEMedium *medium_; PeripheralsMap peripherals_; struct AdvertisementPacketInfo { NSDate *last_timestamp; NSDictionary *last_service_data; }; absl::Mutex advertisement_packets_mutex_; // A map for maintaining the set of advertisement packets that should be tracked. absl::flat_hash_map advertisement_packets_map_ ABSL_GUARDED_BY(advertisement_packets_mutex_); // The timestamp of the last time to clean up expired advertisement packets. This is used to // prevent the map from growing indefinitely. NSDate *last_timestamp_to_clean_expired_advertisement_packets_ ABSL_GUARDED_BY(advertisement_packets_mutex_) = {nil}; GNSPeripheralServiceManager *socketPeripheralServiceManager_; GNSPeripheralManager *socketPeripheralManager_; absl::Mutex scanning_mutex_; std::vector scanning_service_uuids_ ABSL_GUARDED_BY(scanning_mutex_); GNSCentralManager *socketCentralManager_ ABSL_GUARDED_BY(scanning_mutex_); // Used for the blocking version of StartAdvertising and only has an advertisement found callback. std::shared_ptr scan_cb_ ABSL_GUARDED_BY(scanning_mutex_); // Used for the async version of StartAdvertising and has both an advertisement found and result // callback. std::shared_ptr scanning_cb_ ABSL_GUARDED_BY(scanning_mutex_); // Used for the BleServerSocket. absl::Mutex server_socket_mutex_; BleServerSocket *server_socket_ptr_ ABSL_GUARDED_BY(server_socket_mutex_) = nullptr; // Used for the L2CAP server socket. absl::Mutex l2cap_server_socket_mutex_; BleL2capServerSocket *l2cap_server_socket_ptr_ = nullptr; dispatch_queue_t connection_callback_queue_ = nullptr; }; } // namespace apple } // namespace nearby