diff --git a/cpp/core/internal/mediums/webrtc/signaling_frames_test.cc b/cpp/core/internal/mediums/webrtc/signaling_frames_test.cc index 384cf9f1..f12607c7 100644 --- a/cpp/core/internal/mediums/webrtc/signaling_frames_test.cc +++ b/cpp/core/internal/mediums/webrtc/signaling_frames_test.cc @@ -110,7 +110,7 @@ TEST(SignalingFramesTest, EncodeValidOffer) { TEST(SignalingFramesTest, DecodeValidOffer) { location::nearby::mediums::WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromString(kOfferProto, &frame); + proto2::TextFormat::ParseFromStringPiece(kOfferProto, &frame); Ptr decoded_offer = DecodeOffer(frame); EXPECT_EQ(webrtc::SdpType::kOffer, decoded_offer->GetType()); @@ -134,7 +134,7 @@ TEST(SignalingFramesTest, EncodeValidAnswer) { TEST(SignalingFramesTest, DecodeValidAnswer) { location::nearby::mediums::WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromString(kAnswerProto, &frame); + proto2::TextFormat::ParseFromStringPiece(kAnswerProto, &frame); Ptr decoded_answer = DecodeAnswer(frame); EXPECT_EQ(webrtc::SdpType::kAnswer, decoded_answer->GetType()); @@ -177,7 +177,7 @@ TEST(SignalingFramesTest, DecodeValidIceCandidates) { std::vector encoded_candidates_vec; location::nearby::mediums::WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromString(kIceCandidatesProto, &frame); + proto2::TextFormat::ParseFromStringPiece(kIceCandidatesProto, &frame); std::vector> decoded_candidates = DecodeIceCandidates(frame); diff --git a/cpp/core_v2/internal/base_pcp_handler.cc b/cpp/core_v2/internal/base_pcp_handler.cc index 18c796b7..cd82d899 100644 --- a/cpp/core_v2/internal/base_pcp_handler.cc +++ b/cpp/core_v2/internal/base_pcp_handler.cc @@ -23,6 +23,7 @@ #include "core_v2/internal/offline_frames.h" #include "core_v2/internal/pcp_handler.h" #include "core_v2/options.h" +#include "platform_v2/base/bluetooth_utils.h" #include "platform_v2/public/logging.h" #include "platform_v2/public/system_clock.h" #include "securegcm/d2d_connection_context_v1.h" @@ -43,11 +44,13 @@ constexpr absl::Duration BasePcpHandler::kRejectedConnectionCloseDelay; BasePcpHandler::BasePcpHandler(Mediums* mediums, EndpointManager* endpoint_manager, - EndpointChannelManager* channel_manager, Pcp pcp) + EndpointChannelManager* channel_manager, + BwuManager* bwu_manager, Pcp pcp) : mediums_(mediums), endpoint_manager_(endpoint_manager), channel_manager_(channel_manager), - pcp_(pcp) {} + pcp_(pcp), + bwu_manager_(bwu_manager) {} BasePcpHandler::~BasePcpHandler() { NEARBY_LOGS(INFO) << "BasePcpHandler: going down; strategy=" @@ -77,23 +80,23 @@ Status BasePcpHandler::StartAdvertising(ClientProxy* client, const ConnectionRequestInfo& info) { Future response; ConnectionOptions advertising_options = options.CompatibleOptions(); - RunOnPcpHandlerThread( - [this, client, &service_id, &info, &advertising_options, &response]() { - auto result = StartAdvertisingImpl( - client, service_id, client->GetLocalEndpointId(), - info.endpoint_info, advertising_options); - if (!result.status.Ok()) { - response.Set(result.status); - return; - } + RunOnPcpHandlerThread([this, client, &service_id, &info, &advertising_options, + &response]() { + auto result = + StartAdvertisingImpl(client, service_id, client->GetLocalEndpointId(), + info.endpoint_info, advertising_options); + if (!result.status.Ok()) { + response.Set(result.status); + return; + } - // Now that we've succeeded, mark the client as advertising. - advertising_options_ = advertising_options; - advertising_listener_ = info.listener; - client->StartedAdvertising(service_id, GetStrategy(), info.listener, - absl::MakeSpan(result.mediums)); - response.Set({Status::kSuccess}); - }); + // Now that we've succeeded, mark the client as advertising. + advertising_options_ = advertising_options; + advertising_listener_ = info.listener; + client->StartedAdvertising(service_id, GetStrategy(), info.listener, + absl::MakeSpan(result.mediums)); + response.Set({Status::kSuccess}); + }); return WaitForResult( absl::StrCat("StartAdvertising(", std::string(info.endpoint_info), ")"), client->GetClientId(), &response); @@ -246,8 +249,8 @@ void BasePcpHandler::OnEncryptionSuccessRunnable( .raw_authentication_token = raw_auth_token, .is_incoming_connection = connection_info.is_incoming, }, - connection_info.options, - std::move(connection_info.channel), connection_info.listener); + connection_info.options, std::move(connection_info.channel), + connection_info.listener); if (connection_info.result != nullptr) { NEARBY_LOG(INFO, "Connection established; Finalising future OK"); @@ -332,14 +335,20 @@ Status BasePcpHandler::RequestConnection(ClientProxy* client, OnEndpointFound(client, webrtc_endpoint); } - auto endpoints = GetDiscoveredEndpoints(endpoint_id); + auto discovered_endpoints = GetDiscoveredEndpoints(endpoint_id); std::unique_ptr channel; ConnectImplResult connect_impl_result; - // TODO(b/156634369): add GetRemoteBluetoothMacAddressEndpoint here for - // valid remote mac address. + auto remote_bluetooth_mac_address = + BluetoothUtils::ToString(options.remote_bluetooth_mac_address); + if (!remote_bluetooth_mac_address.empty()) { + auto additional_endpoint = GetRemoteBluetoothMacAddressEndpoint( + endpoint_id, remote_bluetooth_mac_address, discovered_endpoints); + if (additional_endpoint != nullptr) + discovered_endpoints.push_back(additional_endpoint.get()); + } - for (auto connect_endpoint : endpoints) { + for (auto connect_endpoint : discovered_endpoints) { connect_impl_result = ConnectImpl(client, connect_endpoint); if (connect_impl_result.status.Ok()) { channel = std::move(connect_impl_result.endpoint_channel); @@ -625,10 +634,6 @@ Status BasePcpHandler::RejectConnection(ClientProxy* client, client->GetClientId(), &response); } -// proto::connections::Medium BasePcpHandler::GetBandwidthUpgradeMedium() { -// return bandwidth_upgrade_medium_.Get(); -//} - void BasePcpHandler::OnIncomingFrame(OfflineFrame& frame, const std::string& endpoint_id, ClientProxy* client, @@ -942,7 +947,7 @@ void BasePcpHandler::ProcessTieBreakLoss( void BasePcpHandler::InitiateBandwidthUpgrade( ClientProxy* client, const std::string& endpoint_id, - const std::vector& supported_mediums) { + const std::vector& supported_mediums) { // When we successfully connect to a remote endpoint and a bandwidth upgrade // medium has not yet been decided, we'll pick the highest bandwidth medium // supported by both us and the remote endpoint. Once we pick a medium, all @@ -952,16 +957,14 @@ void BasePcpHandler::InitiateBandwidthUpgrade( // way to prevent mediums, like Wifi Hotspot, from interfering with active // connections (although it's suboptimal for bandwidth throughput). When all // endpoints disconnect, we reset the bandwidth upgrade medium. - if (bandwidth_upgrade_medium_.Get() == - proto::connections::Medium::UNKNOWN_MEDIUM) { - bandwidth_upgrade_medium_.Set(ChooseBestUpgradeMedium(supported_mediums)); + Medium bwu_medium = bwu_medium_.Get(); + if (bwu_medium == Medium::UNKNOWN_MEDIUM) { + bwu_medium = ChooseBestUpgradeMedium(supported_mediums); + bwu_medium_.Set(bwu_medium); } - if (AutoUpgradeBandwidth() && (bandwidth_upgrade_medium_.Get() != - proto::connections::Medium::UNKNOWN_MEDIUM)) { - // TODO(apolyudov): Bring bandwidth upgrade back, when it is ready. - // bandwidth_upgrade_->InitiateBandwidthUpgradeForEndpoint( - // client, endpoint_id, bandwidth_upgrade_medium_.Get()); + if (AutoUpgradeBandwidth() && bwu_medium != Medium::UNKNOWN_MEDIUM) { + bwu_manager_->InitiateBwuForEndpoint(client, endpoint_id, bwu_medium); } } @@ -989,6 +992,55 @@ proto::connections::Medium BasePcpHandler::ChooseBestUpgradeMedium( return proto::connections::Medium::UNKNOWN_MEDIUM; } +std::unique_ptr +BasePcpHandler::GetRemoteBluetoothMacAddressEndpoint( + std::string endpoint_id, std::string remote_bluetooth_mac_address, + std::vector endpoints) { + if (!discovery_options_.allowed.bluetooth) { + return nullptr; + } + + if (endpoints.empty()) { + NEARBY_LOGS(INFO) + << "Cannot append remote Bluetooth MAC Address, because endpointId " + << endpoint_id << " has not been discovered"; + return nullptr; + } + + for (auto endpoint : endpoints) { + if (endpoint->medium == proto::connections::Medium::BLUETOOTH) { + NEARBY_LOGS(INFO) + << "Cannot append remote Bluetooth MAC Address, because the " + "endpoint has already been found over Bluetooth."; + return nullptr; + } + } + + auto remote_bluetooth_device = + mediums_->GetBluetoothClassic().GetRemoteDevice( + remote_bluetooth_mac_address); + if (!remote_bluetooth_device.IsValid()) { + NEARBY_LOGS(INFO) + << "Cannot append remote Bluetooth MAC Address, because a valid " + "Bluetooth device could not be derived."; + return nullptr; + } + + auto bluetooth_endpoint = + std::make_unique(BluetoothEndpoint{ + { + endpoint_id, + endpoints[0]->endpoint_info, + endpoints[0]->service_id, + proto::connections::Medium::BLUETOOTH, + }, + remote_bluetooth_device, + }); + NEARBY_LOGS(INFO) << "Appended remote Bluetooth device " + << remote_bluetooth_mac_address; + return bluetooth_endpoint; +} + void BasePcpHandler::EvaluateConnectionResult(ClientProxy* client, const std::string& endpoint_id, bool can_close_immediately) { diff --git a/cpp/core_v2/internal/base_pcp_handler.h b/cpp/core_v2/internal/base_pcp_handler.h index 1c91f666..dfb9bde8 100644 --- a/cpp/core_v2/internal/base_pcp_handler.h +++ b/cpp/core_v2/internal/base_pcp_handler.h @@ -20,6 +20,10 @@ #include #include +#include "absl/container/btree_map.h" +#include "absl/container/flat_hash_map.h" +#include "absl/time/time.h" +#include "core_v2/internal/bwu_manager.h" #include "core_v2/internal/client_proxy.h" #include "core_v2/internal/encryption_runner.h" #include "core_v2/internal/endpoint_channel_manager.h" @@ -31,7 +35,6 @@ #include "core_v2/listeners.h" #include "core_v2/options.h" #include "core_v2/status.h" -#include "proto/connections/offline_wire_formats.pb.h" #include "platform_v2/base/byte_array.h" #include "platform_v2/base/prng.h" #include "platform_v2/public/atomic_boolean.h" @@ -42,12 +45,10 @@ #include "platform_v2/public/scheduled_executor.h" #include "platform_v2/public/single_thread_executor.h" #include "platform_v2/public/system_clock.h" +#include "proto/connections/offline_wire_formats.pb.h" #include "proto/connections_enums.pb.h" #include "securegcm/d2d_connection_context_v1.h" #include "securegcm/ukey2_handshake.h" -#include "absl/container/btree_map.h" -#include "absl/container/flat_hash_map.h" -#include "absl/time/time.h" namespace location { namespace nearby { @@ -95,17 +96,16 @@ class BasePcpHandler : public PcpHandler, // TODO(apolyudov): Add SecureRandom. BasePcpHandler(Mediums* mediums, EndpointManager* endpoint_manager, - EndpointChannelManager* channel_manager, Pcp pcp); + EndpointChannelManager* channel_manager, + BwuManager* bwu_manager, Pcp pcp); ~BasePcpHandler() override; BasePcpHandler(BasePcpHandler&&) = delete; BasePcpHandler& operator=(BasePcpHandler&&) = delete; // Starts advertising. Once successfully started, changes ClientProxy's state. // Notifies ConnectionListener (info.listener) in case of any event. - // See - // cpp/core_v2/listeners.h;l=78 - Status StartAdvertising(ClientProxy* client, - const std::string& service_id, + // See cpp/core_v2/listeners.h;l=78 + Status StartAdvertising(ClientProxy* client, const std::string& service_id, const ConnectionOptions& options, const ConnectionRequestInfo& info) override; @@ -116,8 +116,7 @@ class BasePcpHandler : public PcpHandler, // Starts discovery of endpoints that may be advertising. // Updates ClientProxy state once discovery started. // DiscoveryListener will get called in case of any event. - Status StartDiscovery(ClientProxy* client, - const std::string& service_id, + Status StartDiscovery(ClientProxy* client, const std::string& service_id, const ConnectionOptions& options, const DiscoveryListener& listener) override; @@ -127,16 +126,14 @@ class BasePcpHandler : public PcpHandler, // Requests a newly discovered remote endpoint it to form a connection. // Updates state on ClientProxy. - Status RequestConnection(ClientProxy* client, - const std::string& endpoint_id, + Status RequestConnection(ClientProxy* client, const std::string& endpoint_id, const ConnectionRequestInfo& info, const ConnectionOptions& options) override; // Called by either party to accept connection on their part. // Until both parties call it, connection will not reach a data phase. // Updates state in ClientProxy. - Status AcceptConnection(ClientProxy* client, - const std::string& endpoint_id, + Status AcceptConnection(ClientProxy* client, const std::string& endpoint_id, const PayloadListener& payload_listener) override; // Called by either party to reject connection on their part. @@ -153,12 +150,12 @@ class BasePcpHandler : public PcpHandler, // Called when an endpoint disconnects while we're waiting for both sides to // approve/reject the connection. // @EndpointManagerThread - void OnEndpointDisconnect(ClientProxy* client, - const std::string& endpoint_id, + void OnEndpointDisconnect(ClientProxy* client, const std::string& endpoint_id, CountDownLatch* barrier) override; Pcp GetPcp() const override { return pcp_; } Strategy GetStrategy() const override { return strategy_; } + Medium GetBwuMedium() const { return bwu_medium_.Get(); } void DisconnectFromEndpointManager(); protected: @@ -241,8 +238,7 @@ class BasePcpHandler : public PcpHandler, std::shared_ptr endpoint); // @PcpHandlerThread - void OnEndpointLost(ClientProxy* client, - const DiscoveredEndpoint& endpoint); + void OnEndpointLost(ClientProxy* client, const DiscoveredEndpoint& endpoint); Exception OnIncomingConnection( ClientProxy* client, const ByteArray& remote_endpoint_info, @@ -284,8 +280,8 @@ class BasePcpHandler : public PcpHandler, // Returns a vector of discovered endpoints, sorted in order of decreasing // preference. - std::vector - GetDiscoveredEndpoints(const std::string& endpoint_id); + std::vector GetDiscoveredEndpoints( + const std::string& endpoint_id); mediums::PeerId CreatePeerIdFromAdvertisement(const string& service_id, const string& endpoint_id, @@ -416,6 +412,11 @@ class BasePcpHandler : public PcpHandler, proto::connections::Medium ChooseBestUpgradeMedium( const std::vector& supported_mediums); + std::unique_ptr + GetRemoteBluetoothMacAddressEndpoint( + std::string endpoint_id, std::string remote_bluetooth_mac_address, + std::vector endpoints); + void ProcessPreConnectionInitiationFailure(const std::string& endpoint_id, EndpointChannel* channel, Status status, @@ -443,8 +444,7 @@ class BasePcpHandler : public PcpHandler, Status WaitForResult(const std::string& method_name, std::int64_t client_id, Future* future); - AtomicReference bandwidth_upgrade_medium_{ - proto::connections::Medium::UNKNOWN_MEDIUM}; + AtomicReference bwu_medium_{Medium::UNKNOWN_MEDIUM}; ScheduledExecutor alarm_executor_; SingleThreadExecutor serial_executor_; @@ -486,6 +486,7 @@ class BasePcpHandler : public PcpHandler, Strategy strategy_{PcpToStrategy(pcp_)}; Prng prng_; EncryptionRunner encryption_runner_; + BwuManager* bwu_manager_; EndpointManager::FrameProcessor::Handle handle_ = nullptr; }; diff --git a/cpp/core_v2/internal/base_pcp_handler_test.cc b/cpp/core_v2/internal/base_pcp_handler_test.cc index ae32ad85..4ef1f6c8 100644 --- a/cpp/core_v2/internal/base_pcp_handler_test.cc +++ b/cpp/core_v2/internal/base_pcp_handler_test.cc @@ -18,6 +18,7 @@ #include #include "core_v2/internal/base_endpoint_channel.h" +#include "core_v2/internal/bwu_manager.h" #include "core_v2/internal/client_proxy.h" #include "core_v2/internal/encryption_runner.h" #include "core_v2/internal/offline_frames.h" @@ -90,8 +91,9 @@ class MockPcpHandler : public BasePcpHandler { public: using DiscoveredEndpoint = BasePcpHandler::DiscoveredEndpoint; - MockPcpHandler(Mediums* m, EndpointManager* em, EndpointChannelManager* ecm) - : BasePcpHandler(m, em, ecm, Pcp::kP2pCluster) {} + MockPcpHandler(Mediums* m, EndpointManager* em, EndpointChannelManager* ecm, + BwuManager* bwu) + : BasePcpHandler(m, em, ecm, bwu, Pcp::kP2pCluster) {} // Expose protected inner types of a base type for mocking. using BasePcpHandler::ConnectImplResult; @@ -381,7 +383,8 @@ TEST_P(BasePcpHandlerTest, ConstructorDestructorWorks) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); SUCCEED(); } @@ -390,7 +393,8 @@ TEST_P(BasePcpHandlerTest, StartAdvertisingChangesState) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartAdvertising(&client, &pcp_handler); } @@ -399,7 +403,8 @@ TEST_P(BasePcpHandlerTest, StopAdvertisingChangesState) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartAdvertising(&client, &pcp_handler); EXPECT_CALL(pcp_handler, StopAdvertisingImpl(&client)).Times(1); EXPECT_TRUE(client.IsAdvertising()); @@ -412,7 +417,8 @@ TEST_P(BasePcpHandlerTest, StartDiscoveryChangesState) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(&client, &pcp_handler); } @@ -421,7 +427,8 @@ TEST_P(BasePcpHandlerTest, StopDiscoveryChangesState) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(&client, &pcp_handler); EXPECT_CALL(pcp_handler, StopDiscoveryImpl(&client)).Times(1); EXPECT_TRUE(client.IsDiscovering()); @@ -435,7 +442,8 @@ TEST_P(BasePcpHandlerTest, RequestConnectionChangesState) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(); auto connect_medium = mediums[mediums.size() - 1]; @@ -458,7 +466,8 @@ TEST_P(BasePcpHandlerTest, AcceptConnectionChangesState) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(); auto connect_medium = mediums[mediums.size() - 1]; @@ -485,7 +494,8 @@ TEST_P(BasePcpHandlerTest, RejectConnectionChangesState) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(); auto connect_medium = mediums[mediums.size() - 1]; @@ -508,7 +518,8 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(); auto connect_medium = mediums[mediums.size() - 1]; @@ -544,7 +555,8 @@ TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(); auto connect_medium = mediums[mediums.size() - 1]; @@ -583,7 +595,8 @@ TEST_P(BasePcpHandlerTest, MultipleMediumsProduceSingleEndpointLostEvent) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); - MockPcpHandler pcp_handler(&m, &em, &ecm); + BwuManager bwu(m, em, ecm, {}, {}); + MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(&client, &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(); auto connect_medium = mediums[mediums.size() - 1]; diff --git a/cpp/core_v2/internal/bwu_manager.cc b/cpp/core_v2/internal/bwu_manager.cc index 2ac7ed5d..6607d8a8 100644 --- a/cpp/core_v2/internal/bwu_manager.cc +++ b/cpp/core_v2/internal/bwu_manager.cc @@ -18,6 +18,7 @@ #include "core_v2/internal/bwu_handler.h" #include "core_v2/internal/offline_frames.h" +#include "core_v2/internal/webrtc_bwu_handler.h" #include "platform_v2/base/byte_array.h" #include "platform_v2/public/count_down_latch.h" #include "proto/connections_enums.pb.h" @@ -66,7 +67,11 @@ void BwuManager::InitBwuHandlers() { .incoming_connection_cb = absl::bind_front(&BwuManager::OnIncomingConnection, this), }; - // TODO(apolyudov): inject instances of supported upgrade medium handlers. + if (config_.allow_upgrade_to.web_rtc) { + handlers_.emplace(Medium::WEB_RTC, + std::make_unique( + *mediums_, *channel_manager_, notifications)); + } } void BwuManager::Shutdown() { @@ -104,12 +109,17 @@ void BwuManager::Shutdown() { } // This is the point on the Initiator side where the -// currentBwuMedium is set. +// medium_ is set. void BwuManager::InitiateBwuForEndpoint(ClientProxy* client, - const std::string& endpoint_id) { - RunOnBwuManagerThread([this, client, endpoint_id]() { - auto* handler = SetCurrentBwuHandler(ChooseBestUpgradeMedium( - client->GetUpgradeMediums(endpoint_id).GetMediums(true))); + const std::string& endpoint_id, + Medium new_medium) { + RunOnBwuManagerThread([this, client, endpoint_id, new_medium]() { + Medium proposed_medium = ChooseBestUpgradeMedium( + client->GetUpgradeMediums(endpoint_id).GetMediums(true)); + if (new_medium != Medium::UNKNOWN_MEDIUM) { + proposed_medium = new_medium; + } + auto* handler = SetCurrentBwuHandler(proposed_medium); if (!handler) return; diff --git a/cpp/core_v2/internal/bwu_manager.h b/cpp/core_v2/internal/bwu_manager.h index df5b5c58..3e552222 100644 --- a/cpp/core_v2/internal/bwu_manager.h +++ b/cpp/core_v2/internal/bwu_manager.h @@ -79,7 +79,8 @@ class BwuManager : public EndpointManager::FrameProcessor { // Function initiates the bandwidth upgrade and sends an // UPGRADE_PATH_AVAILABLE OfflineFrame. void InitiateBwuForEndpoint(ClientProxy* client_proxy, - const std::string& endpoint_id); + const std::string& endpoint_id, + Medium new_medium = Medium::UNKNOWN_MEDIUM); // == EndpointManager::FrameProcessor interface ==. // This is the point on the inbound BWU protocol where the handler_ is set. diff --git a/cpp/core_v2/internal/mediums/ble.cc b/cpp/core_v2/internal/mediums/ble.cc index 33bf376a..07ee3ad9 100644 --- a/cpp/core_v2/internal/mediums/ble.cc +++ b/cpp/core_v2/internal/mediums/ble.cc @@ -120,6 +120,7 @@ bool Ble::IsAdvertisingLocked(const std::string& service_id) { } bool Ble::StartScanning(const std::string& service_id, + const std::string& fast_advertisement_service_uuid, DiscoveredPeripheralCallback callback) { MutexLock lock(&mutex_); @@ -147,7 +148,8 @@ bool Ble::StartScanning(const std::string& service_id, return false; } - if (!medium_.StartScanning(service_id, callback)) { + if (!medium_.StartScanning(service_id, fast_advertisement_service_uuid, + callback)) { NEARBY_LOGS(INFO) << "Failed to start scan of BLE services."; return false; } diff --git a/cpp/core_v2/internal/mediums/ble.h b/cpp/core_v2/internal/mediums/ble.h index 6d225f26..7f12ceab 100644 --- a/cpp/core_v2/internal/mediums/ble.h +++ b/cpp/core_v2/internal/mediums/ble.h @@ -59,6 +59,7 @@ class Ble { // range through a callback. Returns true, if scanning mode was enabled, // false otherwise. bool StartScanning(const std::string& service_id, + const std::string& fast_advertisement_service_uuid, DiscoveredPeripheralCallback callback) ABSL_LOCKS_EXCLUDED(mutex_); diff --git a/cpp/core_v2/internal/mediums/ble_test.cc b/cpp/core_v2/internal/mediums/ble_test.cc index de6f8e11..277c2451 100644 --- a/cpp/core_v2/internal/mediums/ble_test.cc +++ b/cpp/core_v2/internal/mediums/ble_test.cc @@ -32,7 +32,7 @@ namespace { constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"}; constexpr absl::string_view kAdvertisementString{"\x0a\x0b\x0c\x0d"}; -constexpr absl::string_view kFastAdvertisementServiceUuid{"\xff\xfe"}; +constexpr absl::string_view kFastAdvertisementServiceUuid{"\xf3\xfe"}; class BleTest : public ::testing::Test { protected: @@ -75,6 +75,7 @@ TEST_F(BleTest, CanStartAdvertising) { ble_b.StartScanning( service_id, + fast_advertisement_service_uuid, DiscoveredPeripheralCallback{ .peripheral_discovered_cb = [&found_latch]( @@ -109,6 +110,7 @@ TEST_F(BleTest, CanStartDiscovery) { EXPECT_TRUE(ble_a.StartScanning( service_id, + fast_advertisement_service_uuid, DiscoveredPeripheralCallback{ .peripheral_discovered_cb = [&accept_latch]( @@ -153,6 +155,7 @@ TEST_F(BleTest, CanStartAcceptingConnectionsAndConnect) { BlePeripheral discovered_peripheral; ble_b.StartScanning( service_id, + fast_advertisement_service_uuid, { .peripheral_discovered_cb = [&found_latch, &discovered_peripheral]( diff --git a/cpp/core_v2/internal/mediums/bluetooth_classic.cc b/cpp/core_v2/internal/mediums/bluetooth_classic.cc index b478dc8a..a80f265d 100644 --- a/cpp/core_v2/internal/mediums/bluetooth_classic.cc +++ b/cpp/core_v2/internal/mediums/bluetooth_classic.cc @@ -382,10 +382,10 @@ BluetoothSocket BluetoothClassic::Connect(BluetoothDevice& bluetooth_device, return socket; } -BluetoothDevice BluetoothClassic::FindRemoteDevice( +BluetoothDevice BluetoothClassic::GetRemoteDevice( const std::string& mac_address) { MutexLock lock(&mutex_); - return medium_.FindRemoteDevice(mac_address); + return medium_.GetRemoteDevice(mac_address); } std::string BluetoothClassic::GetMacAddress() const { diff --git a/cpp/core_v2/internal/mediums/bluetooth_classic.h b/cpp/core_v2/internal/mediums/bluetooth_classic.h index 33c0436c..2fa47b69 100644 --- a/cpp/core_v2/internal/mediums/bluetooth_classic.h +++ b/cpp/core_v2/internal/mediums/bluetooth_classic.h @@ -116,7 +116,7 @@ class BluetoothClassic { std::string GetMacAddress() const ABSL_LOCKS_EXCLUDED(mutex_); - BluetoothDevice FindRemoteDevice(const std::string& mac_address) + BluetoothDevice GetRemoteDevice(const std::string& mac_address) ABSL_LOCKS_EXCLUDED(mutex_); private: diff --git a/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc b/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc index 92ed8f9f..ee1f3adb 100644 --- a/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc +++ b/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc @@ -247,8 +247,8 @@ bool ConnectionFlow::InitPeerConnection(WebRtcMedium& webrtc_medium) { Future success_future; webrtc_medium.CreatePeerConnection( &peer_connection_observer_, - [this, &success_future]( - rtc::scoped_refptr peer_connection) { + [this, success_future](rtc::scoped_refptr + peer_connection) mutable { if (!peer_connection) { success_future.Set(false); return; @@ -343,8 +343,7 @@ bool ConnectionFlow::CloseLocked() { state_ = State::kEnded; data_channel_future_.SetException({Exception::kInterrupted}); - if (peer_connection_) - peer_connection_->Close(); + if (peer_connection_) peer_connection_->Close(); data_channel_observer_.reset(); NEARBY_LOG(INFO, "Closed WebRTC connection."); diff --git a/cpp/core_v2/internal/offline_service_controller.h b/cpp/core_v2/internal/offline_service_controller.h index 0f1dc2f1..34288783 100644 --- a/cpp/core_v2/internal/offline_service_controller.h +++ b/cpp/core_v2/internal/offline_service_controller.h @@ -81,9 +81,10 @@ class OfflineServiceController : public ServiceController { EndpointChannelManager channel_manager_; EndpointManager endpoint_manager_{&channel_manager_}; PayloadManager payload_manager_{endpoint_manager_}; - PcpManager pcp_manager_{mediums_, channel_manager_, endpoint_manager_}; BwuManager bwu_manager_{ mediums_, endpoint_manager_, channel_manager_, {}, {}}; + PcpManager pcp_manager_{mediums_, channel_manager_, endpoint_manager_, + bwu_manager_}; }; } // namespace connections diff --git a/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc b/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc index 5c3ee5f8..e98d9220 100644 --- a/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc +++ b/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc @@ -18,6 +18,7 @@ #include "core_v2/internal/ble_advertisement.h" #include "core_v2/internal/ble_endpoint_channel.h" #include "core_v2/internal/bluetooth_endpoint_channel.h" +#include "core_v2/internal/bwu_manager.h" #include "core_v2/internal/mediums/utils.h" #include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h" #include "core_v2/internal/webrtc_endpoint_channel.h" @@ -37,10 +38,22 @@ ByteArray P2pClusterPcpHandler::GenerateHash(const std::string& source, return Utils::Sha256Hash(source, size); } +bool P2pClusterPcpHandler::ShouldAdvertiseBluetoothMacOverBle( + PowerLevel power_level) { + return power_level == PowerLevel::kHighPower; +} + +bool P2pClusterPcpHandler::ShouldAcceptBluetoothConnections( + const ConnectionOptions& options) { + return options.enable_bluetooth_listening; +} + P2pClusterPcpHandler::P2pClusterPcpHandler( Mediums* mediums, EndpointManager* endpoint_manager, - EndpointChannelManager* endpoint_channel_manager, Pcp pcp) - : BasePcpHandler(mediums, endpoint_manager, endpoint_channel_manager, pcp), + EndpointChannelManager* endpoint_channel_manager, BwuManager* bwu_manager, + Pcp pcp) + : BasePcpHandler(mediums, endpoint_manager, endpoint_channel_manager, + bwu_manager, pcp), bluetooth_radio_(mediums->GetBluetoothRadio()), bluetooth_medium_(mediums->GetBluetoothClassic()), ble_medium_(mediums->GetBle()), @@ -145,10 +158,12 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) { bluetooth_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); ble_medium_.StopAdvertising(client->GetAdvertisingServiceId()); + ble_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); webrtc_medium_.StopAcceptingConnections(); wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId()); + wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); return {Status::kSuccess}; } @@ -325,12 +340,11 @@ void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler( return; } - // Parse the Ble advertisement bytes. + // Parse the BLE advertisement bytes. BleAdvertisement advertisement( - fast_advertisement, - peripheral.GetAdvertisementBytes(service_id)); + fast_advertisement, peripheral.GetAdvertisementBytes(service_id)); - // Make sure the Ble advertisement points to a valid + // Make sure the BLE advertisement points to a valid // endpoint we're discovering. if (!IsRecognizedBleEndpoint(service_id, advertisement)) return; @@ -357,7 +371,34 @@ void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler( peripheral, })); - // TODO(b/156632928): Check for Bluetooth device with remote mac address. + // Make sure we can connect to this device via Classic Bluetooth. + std::string remote_bluetooth_mac_address = + advertisement.GetBluetoothMacAddress(); + if (remote_bluetooth_mac_address.empty()) { + NEARBY_LOGS(INFO) + << "No Bluetooth Classic MAC address found in advertisement"; + return; + } + + BluetoothDevice remote_bluetooth_device = + bluetooth_medium_.GetRemoteDevice(remote_bluetooth_mac_address); + if (!remote_bluetooth_device.IsValid()) { + NEARBY_LOGS(INFO) << "A valid Bluetooth device could not be derived from " + "the MAC address " + << remote_bluetooth_mac_address; + return; + } + + OnEndpointFound(client, + std::make_shared(BluetoothEndpoint{ + { + advertisement.GetEndpointId(), + advertisement.GetEndpointInfo(), + service_id, + proto::connections::Medium::BLUETOOTH, + }, + remote_bluetooth_device, + })); }); } @@ -561,7 +602,7 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( .peripheral_lost_cb = absl::bind_front( &P2pClusterPcpHandler::BlePeripheralLostHandler, this, client), }, - client, service_id); + client, service_id, options.fast_advertisement_service_uuid); if (ble_medium != proto::connections::UNKNOWN_MEDIUM) { NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: Ble added"); mediums_started_successfully.push_back(ble_medium); @@ -767,51 +808,90 @@ proto::connections::Medium P2pClusterPcpHandler::StartBleAdvertising( const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, const ConnectionOptions& options) { bool fast_advertisement = !options.fast_advertisement_service_uuid.empty(); + PowerLevel power_level = + options.low_power ? PowerLevel::kLowPower : PowerLevel::kHighPower; // Start listening for connections before advertising in case a connection - // request comes in very quickly. + // request comes in very quickly. BLE allows connecting over BLE itself, as + // well as advertising the Bluetooth MAC address to allow connecting over + // Bluetooth Classic. NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id=" << service_id << ": start"; - if (ble_medium_.IsAcceptingConnections(service_id)) { - NEARBY_LOGS(ERROR) << "Ble is already accepting connections for service_id=" - << service_id; - return proto::connections::UNKNOWN_MEDIUM; - } + if (!ble_medium_.IsAcceptingConnections(service_id)) { + if (!bluetooth_radio_.Enable() || + !ble_medium_.StartAcceptingConnections( + service_id, {.accepted_cb = [this, client, local_endpoint_info]( + BleSocket socket, + const std::string& service_id) { + if (!socket.IsValid()) { + NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s", + std::string(local_endpoint_info).c_str()); + return; + } + RunOnPcpHandlerThread([this, client, local_endpoint_info, + service_id, + socket = std::move(socket)]() mutable { + std::string remote_peripheral_name = + socket.GetRemotePeripheral().GetName(); + auto channel = absl::make_unique( + remote_peripheral_name, socket); + ByteArray remote_peripheral_info = + socket.GetRemotePeripheral().GetAdvertisementBytes( + service_id); - NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id=" - << service_id << ": invoking"; - if (!bluetooth_radio_.Enable() || - !ble_medium_.StartAcceptingConnections( - service_id, - {.accepted_cb = [this, client, local_endpoint_info]( - BleSocket socket, const std::string& service_id) { - if (!socket.IsValid()) { - NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s", - std::string(local_endpoint_info).c_str()); - return; - } - RunOnPcpHandlerThread([this, client, local_endpoint_info, - service_id, - socket = std::move(socket)]() mutable { - std::string remote_peripheral_name = - socket.GetRemotePeripheral().GetName(); - auto channel = absl::make_unique( - remote_peripheral_name, socket); - ByteArray remote_peripheral_info = - socket.GetRemotePeripheral().GetAdvertisementBytes( - service_id); - - OnIncomingConnection(client, remote_peripheral_info, - std::move(channel), - proto::connections::Medium::BLE); - }); - }})) { + OnIncomingConnection(client, remote_peripheral_info, + std::move(channel), + proto::connections::Medium::BLE); + }); + }})) { + NEARBY_LOGS(ERROR) + << "Ble failed to start accepting connections for service_id=" + << service_id; + return proto::connections::UNKNOWN_MEDIUM; + } NEARBY_LOGS(ERROR) - << "Ble failed to start accepting connections for service_id=" + << "Ble succeed to start accepting connections for service_id=" << service_id; - return proto::connections::UNKNOWN_MEDIUM; } - // TODO(b/156632928): Should check for Bluetooth connection here + + if (ShouldAdvertiseBluetoothMacOverBle(power_level) || + ShouldAcceptBluetoothConnections(options)) { + if (bluetooth_medium_.IsAvailable() && + !bluetooth_medium_.IsAcceptingConnections(service_id)) { + if (!bluetooth_radio_.Enable() || + !bluetooth_medium_.StartAcceptingConnections( + service_id, {.accepted_cb = [this, client, local_endpoint_info]( + BluetoothSocket socket) { + if (!socket.IsValid()) { + NEARBY_LOG(ERROR, + "Invalid socket in accept callback: name=%s", + std::string(local_endpoint_info).c_str()); + return; + } + RunOnPcpHandlerThread([this, client, local_endpoint_info, + socket = std::move(socket)]() mutable { + std::string remote_device_name = + socket.GetRemoteDevice().GetName(); + auto channel = absl::make_unique( + remote_device_name, socket); + ByteArray remote_device_info{remote_device_name}; + + OnIncomingConnection(client, remote_device_info, + std::move(channel), + proto::connections::Medium::BLUETOOTH); + }); + }})) { + NEARBY_LOGS(ERROR) + << "BT failed to start accepting connections for service_id=" + << service_id; + ble_medium_.StopAcceptingConnections(service_id); + return proto::connections::UNKNOWN_MEDIUM; + } + NEARBY_LOGS(ERROR) + << "BT succeed to start accepting connections for service_id=" + << service_id; + } + } NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartBleAdvertising: service=%s: " @@ -828,8 +908,10 @@ proto::connections::Medium P2pClusterPcpHandler::StartBleAdvertising( } else { const ByteArray service_id_hash = GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength); - // TODO(b/156632928): Should advertise Bluetooth MacAddress Over Ble std::string bluetooth_mac_address; + if (bluetooth_medium_.IsAvailable() && + ShouldAdvertiseBluetoothMacOverBle(power_level)) + bluetooth_mac_address = bluetooth_medium_.GetMacAddress(); advertisement_bytes = ByteArray(BleAdvertisement( kBleAdvertisementVersion, GetPcp(), service_id_hash, local_endpoint_id, @@ -866,9 +948,11 @@ proto::connections::Medium P2pClusterPcpHandler::StartBleAdvertising( proto::connections::Medium P2pClusterPcpHandler::StartBleScanning( BleDiscoveredPeripheralCallback callback, ClientProxy* client, - const std::string& service_id) { + const std::string& service_id, + const std::string& fast_advertisement_service_uuid) { if (bluetooth_radio_.Enable() && - ble_medium_.StartScanning(service_id, std::move(callback))) { + ble_medium_.StartScanning(service_id, fast_advertisement_service_uuid, + std::move(callback))) { NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleScanning: ok"; return proto::connections::BLE; } else { diff --git a/cpp/core_v2/internal/p2p_cluster_pcp_handler.h b/cpp/core_v2/internal/p2p_cluster_pcp_handler.h index b2222253..680f79f1 100644 --- a/cpp/core_v2/internal/p2p_cluster_pcp_handler.h +++ b/cpp/core_v2/internal/p2p_cluster_pcp_handler.h @@ -21,6 +21,7 @@ #include "core_v2/internal/base_pcp_handler.h" #include "core_v2/internal/ble_advertisement.h" #include "core_v2/internal/bluetooth_device_name.h" +#include "core_v2/internal/bwu_manager.h" #include "core_v2/internal/client_proxy.h" #include "core_v2/internal/endpoint_channel_manager.h" #include "core_v2/internal/endpoint_manager.h" @@ -52,6 +53,7 @@ class P2pClusterPcpHandler : public BasePcpHandler { public: P2pClusterPcpHandler(Mediums* mediums, EndpointManager* endpoint_manager, EndpointChannelManager* channel_manager, + BwuManager* bwu_manager, Pcp pcp = Pcp::kP2pCluster); ~P2pClusterPcpHandler() override = default; @@ -131,6 +133,9 @@ class P2pClusterPcpHandler : public BasePcpHandler { WifiLanServiceInfo::Version::kV1; static ByteArray GenerateHash(const std::string& source, size_t size); + static bool ShouldAdvertiseBluetoothMacOverBle(PowerLevel power_level); + static bool ShouldAcceptBluetoothConnections( + const ConnectionOptions& options); // Bluetooth bool IsRecognizedBluetoothEndpoint(const std::string& name_string, @@ -169,7 +174,8 @@ class P2pClusterPcpHandler : public BasePcpHandler { const ByteArray& local_endpoint_info, const ConnectionOptions& options); proto::connections::Medium StartBleScanning( BleDiscoveredPeripheralCallback callback, ClientProxy* client, - const std::string& service_id); + const std::string& service_id, + const std::string& fast_advertisement_service_uuid); BasePcpHandler::ConnectImplResult BleConnectImpl(ClientProxy* client, BleEndpoint* endpoint); diff --git a/cpp/core_v2/internal/p2p_cluster_pcp_handler_test.cc b/cpp/core_v2/internal/p2p_cluster_pcp_handler_test.cc index 50862910..718efbe4 100644 --- a/cpp/core_v2/internal/p2p_cluster_pcp_handler_test.cc +++ b/cpp/core_v2/internal/p2p_cluster_pcp_handler_test.cc @@ -16,6 +16,7 @@ #include +#include "core_v2/internal/bwu_manager.h" #include "core_v2/options.h" #include "platform_v2/base/medium_environment.h" #include "platform_v2/public/count_down_latch.h" @@ -75,7 +76,8 @@ TEST_P(P2pClusterPcpHandlerTest, CanConstructOne) { Mediums mediums; EndpointChannelManager ecm; EndpointManager em(&ecm); - P2pClusterPcpHandler handler(&mediums, &em, &ecm); + BwuManager bwu(mediums, em, ecm, {}, {}); + P2pClusterPcpHandler handler(&mediums, &em, &ecm, &bwu); env_.Stop(); } @@ -87,8 +89,10 @@ TEST_P(P2pClusterPcpHandlerTest, CanConstructMultiple) { EndpointChannelManager ecm_b; EndpointManager em_a(&ecm_a); EndpointManager em_b(&ecm_b); - P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a); - P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b); + BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, {}); + BwuManager bwu_b(mediums_b, em_b, ecm_b, {}, {}); + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a); + P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b); env_.Stop(); } @@ -98,7 +102,8 @@ TEST_P(P2pClusterPcpHandlerTest, CanAdvertise) { Mediums mediums_a; EndpointChannelManager ecm_a; EndpointManager em_a(&ecm_a); - P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a); + BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, {}); + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a); EXPECT_EQ( handler_a.StartAdvertising(&client_a_, service_id_, options_, {.endpoint_info = ByteArray{endpoint_name}}), @@ -115,8 +120,10 @@ TEST_P(P2pClusterPcpHandlerTest, CanDiscover) { EndpointChannelManager ecm_b; EndpointManager em_a(&ecm_a); EndpointManager em_b(&ecm_b); - P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a); - P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b); + BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, {}); + BwuManager bwu_b(mediums_b, em_b, ecm_b, {}, {}); + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a); + P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b); CountDownLatch latch(1); EXPECT_EQ( handler_a.StartAdvertising(&client_a_, service_id_, options_, @@ -155,8 +162,12 @@ TEST_P(P2pClusterPcpHandlerTest, CanConnect) { EndpointChannelManager ecm_b; EndpointManager em_a(&ecm_a); EndpointManager em_b(&ecm_b); - P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a); - P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b); + BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, + {.allow_upgrade_to = {.bluetooth = true}}); + BwuManager bwu_b(mediums_b, em_b, ecm_b, {}, + {.allow_upgrade_to = {.bluetooth = true}}); + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a); + P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b); CountDownLatch discover_latch(1); CountDownLatch connect_latch(2); struct DiscoveredInfo { @@ -221,6 +232,8 @@ TEST_P(P2pClusterPcpHandlerTest, CanConnect) { }, options_); EXPECT_TRUE(connect_latch.Await(absl::Milliseconds(1000)).result()); + bwu_a.Shutdown(); + bwu_b.Shutdown(); env_.Stop(); } diff --git a/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.cc b/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.cc index c0bdcb1e..8a69d2d0 100644 --- a/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.cc +++ b/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.cc @@ -20,8 +20,9 @@ namespace connections { P2pPointToPointPcpHandler::P2pPointToPointPcpHandler( Mediums& mediums, EndpointManager& endpoint_manager, - EndpointChannelManager& channel_manager, Pcp pcp) - : P2pStarPcpHandler(mediums, endpoint_manager, channel_manager, pcp) {} + EndpointChannelManager& channel_manager, BwuManager& bwu_manager, Pcp pcp) + : P2pStarPcpHandler(mediums, endpoint_manager, channel_manager, bwu_manager, + pcp) {} std::vector P2pPointToPointPcpHandler::GetConnectionMediumsByPriority() { diff --git a/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.h b/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.h index 4a9375e4..d4d0e3c8 100644 --- a/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.h +++ b/cpp/core_v2/internal/p2p_point_to_point_pcp_handler.h @@ -36,6 +36,7 @@ class P2pPointToPointPcpHandler : public P2pStarPcpHandler { public: P2pPointToPointPcpHandler(Mediums& mediums, EndpointManager& endpoint_manager, EndpointChannelManager& channel_manager, + BwuManager& bwu_manager, Pcp pcp = Pcp::kP2pPointToPoint); protected: diff --git a/cpp/core_v2/internal/p2p_star_pcp_handler.cc b/cpp/core_v2/internal/p2p_star_pcp_handler.cc index 707dd880..c7300c39 100644 --- a/cpp/core_v2/internal/p2p_star_pcp_handler.cc +++ b/cpp/core_v2/internal/p2p_star_pcp_handler.cc @@ -23,9 +23,9 @@ namespace connections { P2pStarPcpHandler::P2pStarPcpHandler(Mediums& mediums, EndpointManager& endpoint_manager, EndpointChannelManager& channel_manager, - Pcp pcp) - : P2pClusterPcpHandler(&mediums, &endpoint_manager, &channel_manager, pcp) { -} + BwuManager& bwu_manager, Pcp pcp) + : P2pClusterPcpHandler(&mediums, &endpoint_manager, &channel_manager, + &bwu_manager, pcp) {} std::vector P2pStarPcpHandler::GetConnectionMediumsByPriority() { diff --git a/cpp/core_v2/internal/p2p_star_pcp_handler.h b/cpp/core_v2/internal/p2p_star_pcp_handler.h index fa635ee2..a59d428e 100644 --- a/cpp/core_v2/internal/p2p_star_pcp_handler.h +++ b/cpp/core_v2/internal/p2p_star_pcp_handler.h @@ -39,6 +39,7 @@ class P2pStarPcpHandler : public P2pClusterPcpHandler { public: P2pStarPcpHandler(Mediums& mediums, EndpointManager& endpoint_manager, EndpointChannelManager& channel_manager, + BwuManager& bwu_manager, Pcp pcp = Pcp::kP2pStar); protected: diff --git a/cpp/core_v2/internal/pcp_manager.cc b/cpp/core_v2/internal/pcp_manager.cc index 2e9a1fd4..8a248a44 100644 --- a/cpp/core_v2/internal/pcp_manager.cc +++ b/cpp/core_v2/internal/pcp_manager.cc @@ -25,14 +25,15 @@ namespace connections { PcpManager::PcpManager(Mediums& mediums, EndpointChannelManager& channel_manager, - EndpointManager& endpoint_manager) { + EndpointManager& endpoint_manager, + BwuManager& bwu_manager) { handlers_[Pcp::kP2pCluster] = std::make_unique( - &mediums, &endpoint_manager, &channel_manager); + &mediums, &endpoint_manager, &channel_manager, &bwu_manager); handlers_[Pcp::kP2pStar] = std::make_unique( - mediums, endpoint_manager, channel_manager); + mediums, endpoint_manager, channel_manager, bwu_manager); handlers_[Pcp::kP2pPointToPoint] = std::make_unique(mediums, endpoint_manager, - channel_manager); + channel_manager, bwu_manager); } void PcpManager::DisconnectFromEndpointManager() { diff --git a/cpp/core_v2/internal/pcp_manager.h b/cpp/core_v2/internal/pcp_manager.h index 6573585b..97f13516 100644 --- a/cpp/core_v2/internal/pcp_manager.h +++ b/cpp/core_v2/internal/pcp_manager.h @@ -18,6 +18,7 @@ #include #include "core_v2/internal/base_pcp_handler.h" +#include "core_v2/internal/bwu_manager.h" #include "core_v2/internal/client_proxy.h" #include "core_v2/internal/endpoint_channel_manager.h" #include "core_v2/internal/endpoint_manager.h" @@ -43,7 +44,7 @@ namespace connections { class PcpManager { public: PcpManager(Mediums& mediums, EndpointChannelManager& channel_manager, - EndpointManager& endpoint_manager); + EndpointManager& endpoint_manager, BwuManager& bwu_manager); ~PcpManager(); Status StartAdvertising(ClientProxy* client, const string& service_id, diff --git a/cpp/core_v2/internal/simulation_user.h b/cpp/core_v2/internal/simulation_user.h index 609520d9..c120107a 100644 --- a/cpp/core_v2/internal/simulation_user.h +++ b/cpp/core_v2/internal/simulation_user.h @@ -17,6 +17,7 @@ #include +#include "core_v2/internal/bwu_manager.h" #include "core_v2/internal/client_proxy.h" #include "core_v2/internal/endpoint_channel_manager.h" #include "core_v2/internal/endpoint_manager.h" @@ -144,7 +145,8 @@ class SimulationUser { ClientProxy client_; EndpointChannelManager ecm_; EndpointManager em_{&ecm_}; - PcpManager mgr_{mediums_, ecm_, em_}; + BwuManager bwu_{mediums_, em_, ecm_, {}, {}}; + PcpManager mgr_{mediums_, ecm_, em_, bwu_}; PayloadManager pm_{em_}; }; diff --git a/cpp/core_v2/options.h b/cpp/core_v2/options.h index 063a0e29..a3f1b6ab 100644 --- a/cpp/core_v2/options.h +++ b/cpp/core_v2/options.h @@ -79,6 +79,13 @@ struct MediumSelector { // Feature On/Off switch for mediums. using BooleanMediumSelector = MediumSelector; +// Represents the various power levels that can be used, on mediums that support +// it. +enum class PowerLevel { + kHighPower = 0, + kLowPower = 1, +}; + // Connection Options: used for both Advertising and Discovery. // All fields are mutable, to make the type copy-assignable. struct ConnectionOptions { @@ -86,6 +93,8 @@ struct ConnectionOptions { BooleanMediumSelector allowed{BooleanMediumSelector().SetAll(true)}; bool auto_upgrade_bandwidth; bool enforce_topology_constraints; + bool low_power; + bool enable_bluetooth_listening; ByteArray remote_bluetooth_mac_address; std::string fast_advertisement_service_uuid; // Verify if ConnectionOptions is in a not-initialized (Empty) state. diff --git a/cpp/platform/BUILD b/cpp/platform/BUILD index df29ca67..c4bbf469 100644 --- a/cpp/platform/BUILD +++ b/cpp/platform/BUILD @@ -75,7 +75,6 @@ cc_library( visibility = [ "//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", "//core:__subpackages__", - "//platform_v2/base:__pkg__", ], deps = [ "//absl/base", diff --git a/cpp/platform_v2/api/ble.h b/cpp/platform_v2/api/ble.h index 8aaa210a..07e22e67 100644 --- a/cpp/platform_v2/api/ble.h +++ b/cpp/platform_v2/api/ble.h @@ -89,6 +89,7 @@ class BleMedium { // Returns true once the BLE scan has been initiated. virtual bool StartScanning(const std::string& service_id, + const std::string& fast_advertisement_service_uuid, DiscoveredPeripheralCallback callback) = 0; // Returns true once BLE scanning for service_id is well and truly stopped; diff --git a/cpp/platform_v2/api/bluetooth_classic.h b/cpp/platform_v2/api/bluetooth_classic.h index b80bc060..4e11a208 100644 --- a/cpp/platform_v2/api/bluetooth_classic.h +++ b/cpp/platform_v2/api/bluetooth_classic.h @@ -150,7 +150,7 @@ class BluetoothClassicMedium { virtual std::unique_ptr ListenForService( const std::string& service_name, const std::string& service_uuid) = 0; - virtual BluetoothDevice* FindRemoteDevice(const std::string& mac_address) = 0; + virtual BluetoothDevice* GetRemoteDevice(const std::string& mac_address) = 0; }; } // namespace api diff --git a/cpp/platform_v2/api/platform.h b/cpp/platform_v2/api/platform.h index 52adca19..7deb7185 100644 --- a/cpp/platform_v2/api/platform.h +++ b/cpp/platform_v2/api/platform.h @@ -56,7 +56,7 @@ class ImplementationPlatform { // - synchronization primitives: // - mutex (regular, and recursive) // - condition variable (must work with regular mutex only) - // - Future : to synchronize on Callable schduled to execute. + // - Future : to synchronize on Callable scheduled to execute. // - CountDownLatch : to ensure at least N threads are waiting. // - file I/O // - Logging @@ -72,8 +72,7 @@ class ImplementationPlatform { // Supports enums and integers up to 32-bit. // Does not use locking, if platform supports 32-bit atimics natively. // Does not use dynamic memory allocations in operations. - static std::unique_ptr - CreateAtomicUint32(std::uint32_t value); + static std::unique_ptr CreateAtomicUint32(std::uint32_t value); static std::unique_ptr CreateCountDownLatch( std::int32_t count); diff --git a/cpp/platform_v2/base/medium_environment.cc b/cpp/platform_v2/base/medium_environment.cc index 61900aed..baa59283 100644 --- a/cpp/platform_v2/base/medium_environment.cc +++ b/cpp/platform_v2/base/medium_environment.cc @@ -354,10 +354,12 @@ void MediumEnvironment::UpdateBleMediumForAdvertising( void MediumEnvironment::UpdateBleMediumForScanning( api::BleMedium& medium, const std::string& service_id, + const std::string& fast_advertisement_service_uuid, BleDiscoveredPeripheralCallback callback, bool enabled) { if (!enabled_) return; RunOnMediumEnvironmentThread( - [this, &medium, service_id, callback = std::move(callback), enabled]() { + [this, &medium, service_id, fast_advertisement_service_uuid, + callback = std::move(callback), enabled]() { auto item = ble_mediums_.find(&medium); if (item == ble_mediums_.end()) { NEARBY_LOG(INFO, @@ -367,10 +369,12 @@ void MediumEnvironment::UpdateBleMediumForScanning( } auto& context = item->second; context.discovery_callback = std::move(callback); - NEARBY_LOG(INFO, - "Update Ble medium for scanning: this=%p; medium=%p; " - "service_id=%s; enabled=%d ;", - this, &medium, service_id.c_str(), enabled); + NEARBY_LOG( + INFO, + "Update Ble medium for scanning: this=%p; medium=%p; " + "service_id=%s; fast_advertisement_service_uuid=%s; enabled=%d ;", + this, &medium, service_id.c_str(), + fast_advertisement_service_uuid.c_str(), enabled); for (auto& medium_info : ble_mediums_) { auto& local_medium = medium_info.first; auto& info = medium_info.second; diff --git a/cpp/platform_v2/base/medium_environment.h b/cpp/platform_v2/base/medium_environment.h index 87850251..863d817d 100644 --- a/cpp/platform_v2/base/medium_environment.h +++ b/cpp/platform_v2/base/medium_environment.h @@ -165,10 +165,10 @@ class MediumEnvironment { // This should be called when discoverable state changes. // with user-specified callback when discovery is enabled, and with default // (empty) callback otherwise. - void UpdateBleMediumForScanning(api::BleMedium& medium, - const std::string& service_id, - BleDiscoveredPeripheralCallback callback, - bool enabled); + void UpdateBleMediumForScanning( + api::BleMedium& medium, const std::string& service_id, + const std::string& fast_advertisement_service_uuid, + BleDiscoveredPeripheralCallback callback, bool enabled); // Updates Accepted connection callback info to allow for dispatch of // advertising events. diff --git a/cpp/platform_v2/impl/g3/ble.cc b/cpp/platform_v2/impl/g3/ble.cc index b1ca8ba3..063adfba 100644 --- a/cpp/platform_v2/impl/g3/ble.cc +++ b/cpp/platform_v2/impl/g3/ble.cc @@ -266,11 +266,15 @@ bool BleMedium::StopAdvertising(const std::string& service_id) { return true; } -bool BleMedium::StartScanning(const std::string& service_id, - DiscoveredPeripheralCallback callback) { +bool BleMedium::StartScanning( + const std::string& service_id, + const std::string& fast_advertisement_service_uuid, + DiscoveredPeripheralCallback callback) { NEARBY_LOGS(INFO) << "G3 Ble StartScanning: service_id=" << service_id; auto& env = MediumEnvironment::Instance(); - env.UpdateBleMediumForScanning(*this, service_id, std::move(callback), true); + env.UpdateBleMediumForScanning(*this, service_id, + fast_advertisement_service_uuid, + std::move(callback), true); { absl::MutexLock lock(&mutex_); scanning_info_.service_id = service_id; @@ -291,7 +295,7 @@ bool BleMedium::StopScanning(const std::string& service_id) { } auto& env = MediumEnvironment::Instance(); - env.UpdateBleMediumForScanning(*this, service_id, {}, false); + env.UpdateBleMediumForScanning(*this, service_id, {}, {}, false); return true; } diff --git a/cpp/platform_v2/impl/g3/ble.h b/cpp/platform_v2/impl/g3/ble.h index 3db4dcab..a6ff0fc1 100644 --- a/cpp/platform_v2/impl/g3/ble.h +++ b/cpp/platform_v2/impl/g3/ble.h @@ -160,6 +160,7 @@ class BleMedium : public api::BleMedium { // Returns true once the Ble scanning has been initiated. bool StartScanning(const std::string& service_id, + const std::string& fast_advertisement_service_uuid, DiscoveredPeripheralCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_); diff --git a/cpp/platform_v2/impl/g3/bluetooth_classic.cc b/cpp/platform_v2/impl/g3/bluetooth_classic.cc index d5fc5259..32704bf5 100644 --- a/cpp/platform_v2/impl/g3/bluetooth_classic.cc +++ b/cpp/platform_v2/impl/g3/bluetooth_classic.cc @@ -254,7 +254,7 @@ BluetoothClassicMedium::ListenForService(const std::string& service_name, return socket; } -api::BluetoothDevice* BluetoothClassicMedium::FindRemoteDevice( +api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice( const std::string& mac_address) { auto& env = MediumEnvironment::Instance(); return env.FindBluetoothDevice(mac_address); diff --git a/cpp/platform_v2/impl/g3/bluetooth_classic.h b/cpp/platform_v2/impl/g3/bluetooth_classic.h index ed3a813a..25d3e590 100644 --- a/cpp/platform_v2/impl/g3/bluetooth_classic.h +++ b/cpp/platform_v2/impl/g3/bluetooth_classic.h @@ -221,7 +221,7 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium { const std::string& service_name, const std::string& service_uuid) override ABSL_LOCKS_EXCLUDED(mutex_); - api::BluetoothDevice* FindRemoteDevice( + api::BluetoothDevice* GetRemoteDevice( const std::string& mac_address) override; private: diff --git a/cpp/platform_v2/public/ble.cc b/cpp/platform_v2/public/ble.cc index 2bc81dd8..c4ff0532 100644 --- a/cpp/platform_v2/public/ble.cc +++ b/cpp/platform_v2/public/ble.cc @@ -31,8 +31,10 @@ bool BleMedium::StopAdvertising(const std::string& service_id) { return impl_->StopAdvertising(service_id); } -bool BleMedium::StartScanning(const std::string& service_id, - DiscoveredPeripheralCallback callback) { +bool BleMedium::StartScanning( + const std::string& service_id, + const std::string& fast_advertisement_service_uuid, + DiscoveredPeripheralCallback callback) { { MutexLock lock(&mutex_); discovered_peripheral_callback_ = std::move(callback); @@ -40,6 +42,7 @@ bool BleMedium::StartScanning(const std::string& service_id, } return impl_->StartScanning( service_id, + fast_advertisement_service_uuid, { .peripheral_discovered_cb = [this](api::BlePeripheral& peripheral, diff --git a/cpp/platform_v2/public/ble.h b/cpp/platform_v2/public/ble.h index d73a0fea..2d25e6de 100644 --- a/cpp/platform_v2/public/ble.h +++ b/cpp/platform_v2/public/ble.h @@ -120,6 +120,7 @@ class BleMedium final { // Returns true once the BLE scan has been initiated. bool StartScanning(const std::string& service_id, + const std::string& fast_advertisement_service_uuid, DiscoveredPeripheralCallback callback); // Returns true once BLE scanning for service_id is well and truly stopped; diff --git a/cpp/platform_v2/public/ble_test.cc b/cpp/platform_v2/public/ble_test.cc index ed94d178..e58cd07e 100644 --- a/cpp/platform_v2/public/ble_test.cc +++ b/cpp/platform_v2/public/ble_test.cc @@ -29,7 +29,7 @@ namespace { constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"}; constexpr absl::string_view kAdvertisementString{"\x0a\x0b\x0c\x0d"}; -constexpr absl::string_view kFastAdvertisementServiceUuid{"\xff\xfe"}; +constexpr absl::string_view kFastAdvertisementServiceUuid{"\xf3\xfe"}; class BleMediumTest : public ::testing::Test { protected: @@ -73,6 +73,7 @@ TEST_F(BleMediumTest, CanStartAdvertising) { EXPECT_TRUE(ble_b.StartScanning( service_id, + fast_advertisement_service_uuid, DiscoveredPeripheralCallback{ .peripheral_discovered_cb = [&found_latch]( @@ -99,6 +100,7 @@ TEST_F(BleMediumTest, CanStartScanning) { ble_a.StartScanning( service_id, + fast_advertisement_service_uuid, DiscoveredPeripheralCallback{ .peripheral_discovered_cb = [&found_latch]( @@ -133,6 +135,7 @@ TEST_F(BleMediumTest, CanStopDiscovery) { ble_a.StartScanning( service_id, + fast_advertisement_service_uuid, DiscoveredPeripheralCallback{ .peripheral_discovered_cb = [&found_latch]( @@ -168,6 +171,7 @@ TEST_F(BleMediumTest, CanStartAcceptingConnectionsAndConnect) { BlePeripheral* discovered_peripheral = nullptr; ble_a.StartScanning( service_id, + fast_advertisement_service_uuid, DiscoveredPeripheralCallback{ .peripheral_discovered_cb = [&found_latch, &discovered_peripheral]( diff --git a/cpp/platform_v2/public/bluetooth_classic.h b/cpp/platform_v2/public/bluetooth_classic.h index e60af725..334ce51b 100644 --- a/cpp/platform_v2/public/bluetooth_classic.h +++ b/cpp/platform_v2/public/bluetooth_classic.h @@ -202,8 +202,8 @@ class BluetoothClassicMedium final { api::BluetoothClassicMedium& GetImpl() { return *impl_; } BluetoothAdapter& GetAdapter() { return adapter_; } std::string GetMacAddress() const { return adapter_.GetMacAddress(); } - BluetoothDevice FindRemoteDevice(const std::string& mac_address) { - return BluetoothDevice(impl_->FindRemoteDevice(mac_address)); + BluetoothDevice GetRemoteDevice(const std::string& mac_address) { + return BluetoothDevice(impl_->GetRemoteDevice(mac_address)); } private: diff --git a/proto/connections/offline_wire_formats.proto b/proto/connections/offline_wire_formats.proto index 4f289078..81a138a5 100644 --- a/proto/connections/offline_wire_formats.proto +++ b/proto/connections/offline_wire_formats.proto @@ -95,8 +95,19 @@ message ConnectionResponseFrame { // // - ConnectionsStatusCodes.STATUS_OK // - ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED. - optional int32 status = 1; + optional int32 status = 1 [deprecated = true]; optional bytes handshake_data = 2; + + // Used to replace the status integer parameter with a meaningful enum item. + // Map ConnectionsStatusCodes.STATUS_OK to ACCEPT and + // ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED to REJECT. + // Flag: connection_replace_status_with_response_connectionResponseFrame + enum ResponseStatus { + UNKNOWN_RESPONSE_STATUS = 0; + ACCEPT = 1; + REJECT = 2; + } + optional ResponseStatus response = 3; } message PayloadTransferFrame { diff --git a/proto/discovery_enums.proto b/proto/discovery_enums.proto index 0f72b5cd..bccc5737 100644 --- a/proto/discovery_enums.proto +++ b/proto/discovery_enums.proto @@ -20,7 +20,7 @@ option optimize_for = LITE_RUNTIME; option java_package = "com.google.location.nearby.proto"; option java_outer_classname = "DiscoveryEnums"; -// NEXT ID: 132 +// NEXT ID: 133 enum DiscoveryEvent { UNKNOWN_DISCOVERY_EVENT = 0; @@ -404,6 +404,10 @@ enum DiscoveryEvent { // User has seen a low battery notification. FAST_PAIR_LOW_BATTERY_NOTIFICATION_SHOWN = 131; + // Connection Tracker Manager (Baymax) recovered the connection of the + // companion app. + FAST_PAIR_CONNECTION_TRACKER_RECOVER_COMPANION_APP = 132; + // Deprecated. reserved 65, 67 to 72; } diff --git a/proto/error_code_enums.proto b/proto/error_code_enums.proto index fb15fe70..ae48c494 100644 --- a/proto/error_code_enums.proto +++ b/proto/error_code_enums.proto @@ -422,4 +422,9 @@ enum Description { SOCKET_NOT_BOUND = 141; INVALID_REMOTE_ADDRESS = 142; SOCKET_ALREADY_BOUND = 143; + HOTSPOT_NOT_STARTED = 144; + WEBRTC_ALREADY_INITIALIZED = 145; + INVALID_WEBRTC_STATE = 146; + NULL_DATA_CHANNEL = 147; + CREATE_OFFER_FAILED = 148; }