Loading system/gd/cert/py_le_acl_manager.py +17 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ from cert.closable import Closable from cert.closable import safeClose from bluetooth_packets_python3 import hci_packets from cert.truth import assertThat from datetime import timedelta from hci.facade import le_acl_manager_facade_pb2 as le_acl_manager_facade Loading Loading @@ -98,6 +99,14 @@ class PyLeAclManager(Closable): self.listen_for_incoming_connections() return self.complete_incoming_connection() def wait_for_connection_fail(self, token): assertThat(self.outgoing_connection_event_streams[token]).isNotNone() event_stream = self.outgoing_connection_event_streams[token][0] connection_fail = HciCaptures.LeConnectionCompleteCapture() assertThat(event_stream).emits(connection_fail, timeout=timedelta(seconds=35)) complete = connection_fail.get() assertThat(complete.GetStatus() == hci_packets.ErrorCode.CONNECTION_ACCEPT_TIMEOUT).isTrue() def cancel_connection(self, token): assertThat(token in self.outgoing_connection_event_streams).isTrue() pair = self.outgoing_connection_event_streams.pop(token) Loading @@ -112,6 +121,14 @@ class PyLeAclManager(Closable): self.next_token += 1 return token def initiate_background_and_direct_connection(self, remote_addr): assertThat(self.next_token in self.outgoing_connection_event_streams).isFalse() self.outgoing_connection_event_streams[self.next_token] = EventStream( self.le_acl_manager.CreateBackgroundAndDirectConnection(remote_addr)), remote_addr token = self.next_token self.next_token += 1 return token def complete_connection(self, event_stream): connection_complete = HciCaptures.LeConnectionCompleteCapture() assertThat(event_stream).emits(connection_complete) Loading system/gd/hci/cert/le_acl_manager_test_lib.py +63 −0 Original line number Diff line number Diff line Loading @@ -285,3 +285,66 @@ class LeAclManagerTestBase(): hci_packets.BroadcastFlag.POINT_TO_POINT, bytes(b'!')) assertThat(self.dut_le_acl).emits(lambda packet: b'Hello!' in packet.payload) def test_background_connection(self): self.register_for_le_event(hci_packets.SubeventCode.CONNECTION_COMPLETE) self.register_for_le_event(hci_packets.SubeventCode.ENHANCED_CONNECTION_COMPLETE) self.set_privacy_policy_static() # Start background and direct connection token = self.dut_le_acl_manager.initiate_background_and_direct_connection( remote_addr=common.BluetoothAddressWithType( address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:01', 'utf8')), type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS))) # Wait for direct connection timeout self.dut_le_acl_manager.wait_for_connection_fail(token) # Cert Advertises advertising_handle = 0 self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingLegacyParametersBuilder( advertising_handle, hci_packets.LegacyAdvertisingProperties.ADV_IND, 400, 450, 7, hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS, hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS, '00:00:00:00:00:00', hci_packets.AdvertisingFilterPolicy.ALL_DEVICES, 0xF8, 1, #SID hci_packets.Enable.DISABLED # Scan request notification )) self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingRandomAddressBuilder(advertising_handle, '0C:05:04:03:02:01')) gap_name = hci_packets.GapData() gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME gap_name.data = list(bytes(b'Im_A_Cert')) self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingDataBuilder( advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT, hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_name])) gap_short_name = hci_packets.GapData() gap_short_name.data_type = hci_packets.GapDataType.SHORTENED_LOCAL_NAME gap_short_name.data = list(bytes(b'Im_A_C')) self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingScanResponseBuilder( advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT, hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_short_name])) enabled_set = hci_packets.EnabledSet() enabled_set.advertising_handle = advertising_handle enabled_set.duration = 0 enabled_set.max_extended_advertising_events = 0 self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingEnableBuilder(hci_packets.Enable.ENABLED, [enabled_set])) # Check background connection complete self.dut_le_acl_manager.complete_outgoing_connection(token) No newline at end of file system/gd/hci/facade/le_acl_manager_facade.cc +24 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,25 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC return per_connection_events_[current_connection_request_]->RunLoop(context, writer); } ::grpc::Status CreateBackgroundAndDirectConnection( ::grpc::ServerContext* context, const ::bluetooth::facade::BluetoothAddressWithType* request, ::grpc::ServerWriter<LeConnectionEvent>* writer) override { Address peer_address; ASSERT(Address::FromString(request->address().address(), peer_address)); AddressWithType peer(peer_address, static_cast<AddressType>(request->type())); // Create background connection first acl_manager_->CreateLeConnection(peer, /* is_direct */ false); acl_manager_->CreateLeConnection(peer, /* is_direct */ true); wait_for_background_connection_complete = true; if (per_connection_events_.size() > current_connection_request_) { return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding request is supported"); } per_connection_events_.emplace_back(std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>( std::string("connection attempt ") + std::to_string(current_connection_request_))); return per_connection_events_[current_connection_request_]->RunLoop(context, writer); } ::grpc::Status CancelConnection( ::grpc::ServerContext* context, const ::bluetooth::facade::BluetoothAddressWithType* request, Loading Loading @@ -243,6 +262,7 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC success.set_payload(builder_to_string(std::move(builder))); per_connection_events_[current_connection_request_]->OnIncomingEvent(success); } wait_for_background_connection_complete = false; current_connection_request_++; } Loading @@ -252,8 +272,10 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC LeConnectionEvent fail; fail.set_payload(builder_to_string(std::move(builder))); per_connection_events_[current_connection_request_]->OnIncomingEvent(fail); if (!wait_for_background_connection_complete) { current_connection_request_++; } } class Connection : public LeConnectionManagementCallbacks { public: Loading Loading @@ -310,6 +332,7 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC std::vector<std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>> per_connection_events_; std::map<uint16_t, Connection> acl_connections_; uint32_t current_connection_request_{0}; bool wait_for_background_connection_complete = false; }; void LeAclManagerFacadeModule::ListDependencies(ModuleList* list) const { Loading system/gd/hci/facade/le_acl_manager_facade.proto +2 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ import "facade/common.proto"; service LeAclManagerFacade { rpc CreateConnection(bluetooth.facade.BluetoothAddressWithType) returns (stream LeConnectionEvent) {} rpc CreateBackgroundAndDirectConnection(bluetooth.facade.BluetoothAddressWithType) returns (stream LeConnectionEvent) {} rpc CancelConnection(bluetooth.facade.BluetoothAddressWithType) returns (google.protobuf.Empty) {} rpc Disconnect(LeHandleMsg) returns (google.protobuf.Empty) {} rpc ConnectionCommand(LeConnectionCommandMsg) returns (google.protobuf.Empty) {} Loading Loading
system/gd/cert/py_le_acl_manager.py +17 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ from cert.closable import Closable from cert.closable import safeClose from bluetooth_packets_python3 import hci_packets from cert.truth import assertThat from datetime import timedelta from hci.facade import le_acl_manager_facade_pb2 as le_acl_manager_facade Loading Loading @@ -98,6 +99,14 @@ class PyLeAclManager(Closable): self.listen_for_incoming_connections() return self.complete_incoming_connection() def wait_for_connection_fail(self, token): assertThat(self.outgoing_connection_event_streams[token]).isNotNone() event_stream = self.outgoing_connection_event_streams[token][0] connection_fail = HciCaptures.LeConnectionCompleteCapture() assertThat(event_stream).emits(connection_fail, timeout=timedelta(seconds=35)) complete = connection_fail.get() assertThat(complete.GetStatus() == hci_packets.ErrorCode.CONNECTION_ACCEPT_TIMEOUT).isTrue() def cancel_connection(self, token): assertThat(token in self.outgoing_connection_event_streams).isTrue() pair = self.outgoing_connection_event_streams.pop(token) Loading @@ -112,6 +121,14 @@ class PyLeAclManager(Closable): self.next_token += 1 return token def initiate_background_and_direct_connection(self, remote_addr): assertThat(self.next_token in self.outgoing_connection_event_streams).isFalse() self.outgoing_connection_event_streams[self.next_token] = EventStream( self.le_acl_manager.CreateBackgroundAndDirectConnection(remote_addr)), remote_addr token = self.next_token self.next_token += 1 return token def complete_connection(self, event_stream): connection_complete = HciCaptures.LeConnectionCompleteCapture() assertThat(event_stream).emits(connection_complete) Loading
system/gd/hci/cert/le_acl_manager_test_lib.py +63 −0 Original line number Diff line number Diff line Loading @@ -285,3 +285,66 @@ class LeAclManagerTestBase(): hci_packets.BroadcastFlag.POINT_TO_POINT, bytes(b'!')) assertThat(self.dut_le_acl).emits(lambda packet: b'Hello!' in packet.payload) def test_background_connection(self): self.register_for_le_event(hci_packets.SubeventCode.CONNECTION_COMPLETE) self.register_for_le_event(hci_packets.SubeventCode.ENHANCED_CONNECTION_COMPLETE) self.set_privacy_policy_static() # Start background and direct connection token = self.dut_le_acl_manager.initiate_background_and_direct_connection( remote_addr=common.BluetoothAddressWithType( address=common.BluetoothAddress(address=bytes('0C:05:04:03:02:01', 'utf8')), type=int(hci_packets.AddressType.RANDOM_DEVICE_ADDRESS))) # Wait for direct connection timeout self.dut_le_acl_manager.wait_for_connection_fail(token) # Cert Advertises advertising_handle = 0 self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingLegacyParametersBuilder( advertising_handle, hci_packets.LegacyAdvertisingProperties.ADV_IND, 400, 450, 7, hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS, hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS, '00:00:00:00:00:00', hci_packets.AdvertisingFilterPolicy.ALL_DEVICES, 0xF8, 1, #SID hci_packets.Enable.DISABLED # Scan request notification )) self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingRandomAddressBuilder(advertising_handle, '0C:05:04:03:02:01')) gap_name = hci_packets.GapData() gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME gap_name.data = list(bytes(b'Im_A_Cert')) self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingDataBuilder( advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT, hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_name])) gap_short_name = hci_packets.GapData() gap_short_name.data_type = hci_packets.GapDataType.SHORTENED_LOCAL_NAME gap_short_name.data = list(bytes(b'Im_A_C')) self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingScanResponseBuilder( advertising_handle, hci_packets.Operation.COMPLETE_ADVERTISEMENT, hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_short_name])) enabled_set = hci_packets.EnabledSet() enabled_set.advertising_handle = advertising_handle enabled_set.duration = 0 enabled_set.max_extended_advertising_events = 0 self.enqueue_hci_command( hci_packets.LeSetExtendedAdvertisingEnableBuilder(hci_packets.Enable.ENABLED, [enabled_set])) # Check background connection complete self.dut_le_acl_manager.complete_outgoing_connection(token) No newline at end of file
system/gd/hci/facade/le_acl_manager_facade.cc +24 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,25 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC return per_connection_events_[current_connection_request_]->RunLoop(context, writer); } ::grpc::Status CreateBackgroundAndDirectConnection( ::grpc::ServerContext* context, const ::bluetooth::facade::BluetoothAddressWithType* request, ::grpc::ServerWriter<LeConnectionEvent>* writer) override { Address peer_address; ASSERT(Address::FromString(request->address().address(), peer_address)); AddressWithType peer(peer_address, static_cast<AddressType>(request->type())); // Create background connection first acl_manager_->CreateLeConnection(peer, /* is_direct */ false); acl_manager_->CreateLeConnection(peer, /* is_direct */ true); wait_for_background_connection_complete = true; if (per_connection_events_.size() > current_connection_request_) { return ::grpc::Status(::grpc::StatusCode::RESOURCE_EXHAUSTED, "Only one outstanding request is supported"); } per_connection_events_.emplace_back(std::make_unique<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>( std::string("connection attempt ") + std::to_string(current_connection_request_))); return per_connection_events_[current_connection_request_]->RunLoop(context, writer); } ::grpc::Status CancelConnection( ::grpc::ServerContext* context, const ::bluetooth::facade::BluetoothAddressWithType* request, Loading Loading @@ -243,6 +262,7 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC success.set_payload(builder_to_string(std::move(builder))); per_connection_events_[current_connection_request_]->OnIncomingEvent(success); } wait_for_background_connection_complete = false; current_connection_request_++; } Loading @@ -252,8 +272,10 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC LeConnectionEvent fail; fail.set_payload(builder_to_string(std::move(builder))); per_connection_events_[current_connection_request_]->OnIncomingEvent(fail); if (!wait_for_background_connection_complete) { current_connection_request_++; } } class Connection : public LeConnectionManagementCallbacks { public: Loading Loading @@ -310,6 +332,7 @@ class LeAclManagerFacadeService : public LeAclManagerFacade::Service, public LeC std::vector<std::shared_ptr<::bluetooth::grpc::GrpcEventQueue<LeConnectionEvent>>> per_connection_events_; std::map<uint16_t, Connection> acl_connections_; uint32_t current_connection_request_{0}; bool wait_for_background_connection_complete = false; }; void LeAclManagerFacadeModule::ListDependencies(ModuleList* list) const { Loading
system/gd/hci/facade/le_acl_manager_facade.proto +2 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ import "facade/common.proto"; service LeAclManagerFacade { rpc CreateConnection(bluetooth.facade.BluetoothAddressWithType) returns (stream LeConnectionEvent) {} rpc CreateBackgroundAndDirectConnection(bluetooth.facade.BluetoothAddressWithType) returns (stream LeConnectionEvent) {} rpc CancelConnection(bluetooth.facade.BluetoothAddressWithType) returns (google.protobuf.Empty) {} rpc Disconnect(LeHandleMsg) returns (google.protobuf.Empty) {} rpc ConnectionCommand(LeConnectionCommandMsg) returns (google.protobuf.Empty) {} Loading