xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/fuchsia/host/fidl/profile_server_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/profile_server.h"
16 
17 #include <fuchsia/bluetooth/bredr/cpp/fidl_test_base.h>
18 #include <gmock/gmock.h>
19 #include <zircon/errors.h>
20 
21 #include <memory>
22 
23 #include "fuchsia/bluetooth/bredr/cpp/fidl.h"
24 #include "fuchsia/bluetooth/cpp/fidl.h"
25 #include "lib/fidl/cpp/vector.h"
26 #include "lib/zx/socket.h"
27 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/adapter_test_fixture.h"
28 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/fake_adapter_test_fixture.h"
29 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/helpers.h"
30 #include "pw_bluetooth_sapphire/internal/host/common/host_error.h"
31 #include "pw_bluetooth_sapphire/internal/host/gap/fake_pairing_delegate.h"
32 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_channel.h"
33 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_l2cap.h"
34 #include "pw_bluetooth_sapphire/internal/host/sdp/data_element.h"
35 #include "pw_bluetooth_sapphire/internal/host/sdp/sdp.h"
36 #include "pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
37 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
38 #include "pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
39 #include "pw_unit_test/framework.h"
40 
41 namespace bthost {
42 namespace {
43 
44 namespace fbt = fuchsia::bluetooth;
45 namespace fidlbredr = fuchsia::bluetooth::bredr;
46 namespace android_emb = pw::bluetooth::vendor::android_hci;
47 
48 using bt::l2cap::testing::FakeChannel;
49 using pw::bluetooth::AclPriority;
50 using FeaturesBits = pw::bluetooth::Controller::FeaturesBits;
51 
NopAdvertiseCallback(fidlbredr::Profile_Advertise_Result)52 void NopAdvertiseCallback(fidlbredr::Profile_Advertise_Result) {}
53 
54 const bt::DeviceAddress kTestDevAddr(bt::DeviceAddress::Type::kBREDR, {1});
55 constexpr bt::l2cap::Psm kPsm = bt::l2cap::kAVDTP;
56 
57 constexpr uint16_t kSynchronousDataPacketLength = 64;
58 constexpr uint8_t kTotalNumSynchronousDataPackets = 1;
59 
CreateScoConnectionParameters(fidlbredr::HfpParameterSet param_set=fidlbredr::HfpParameterSet::T2)60 fidlbredr::ScoConnectionParameters CreateScoConnectionParameters(
61     fidlbredr::HfpParameterSet param_set = fidlbredr::HfpParameterSet::T2) {
62   fidlbredr::ScoConnectionParameters params;
63   params.set_parameter_set(param_set);
64   params.set_air_coding_format(fbt::AssignedCodingFormat::MSBC);
65   params.set_air_frame_size(8u);
66   params.set_io_bandwidth(32000);
67   params.set_io_coding_format(fbt::AssignedCodingFormat::LINEAR_PCM);
68   params.set_io_frame_size(16u);
69   params.set_io_pcm_data_format(
70       fuchsia::hardware::audio::SampleFormat::PCM_SIGNED);
71   params.set_io_pcm_sample_payload_msb_position(3u);
72   params.set_path(fidlbredr::DataPath::OFFLOAD);
73   return params;
74 }
75 
MakeFIDLServiceDefinition()76 fidlbredr::ServiceDefinition MakeFIDLServiceDefinition() {
77   fidlbredr::ServiceDefinition def;
78   def.mutable_service_class_uuids()->emplace_back(
79       fidl_helpers::UuidToFidl(bt::sdp::profile::kAudioSink));
80 
81   fidlbredr::ProtocolDescriptor l2cap_proto;
82   l2cap_proto.set_protocol(fidlbredr::ProtocolIdentifier::L2CAP);
83   fidlbredr::DataElement l2cap_data_el;
84   l2cap_data_el.set_uint16(fidlbredr::PSM_AVDTP);
85   std::vector<fidlbredr::DataElement> l2cap_params;
86   l2cap_params.emplace_back(std::move(l2cap_data_el));
87   l2cap_proto.set_params(std::move(l2cap_params));
88 
89   def.mutable_protocol_descriptor_list()->emplace_back(std::move(l2cap_proto));
90 
91   fidlbredr::ProtocolDescriptor avdtp_proto;
92   avdtp_proto.set_protocol(fidlbredr::ProtocolIdentifier::AVDTP);
93   fidlbredr::DataElement avdtp_data_el;
94   avdtp_data_el.set_uint16(0x0103);  // Version 1.3
95   std::vector<fidlbredr::DataElement> avdtp_params;
96   avdtp_params.emplace_back(std::move(avdtp_data_el));
97   avdtp_proto.set_params(std::move(avdtp_params));
98 
99   def.mutable_protocol_descriptor_list()->emplace_back(std::move(avdtp_proto));
100 
101   fidlbredr::ProfileDescriptor prof_desc;
102   prof_desc.set_profile_id(
103       fidlbredr::ServiceClassProfileIdentifier::ADVANCED_AUDIO_DISTRIBUTION);
104   prof_desc.set_major_version(1);
105   prof_desc.set_minor_version(3);
106   def.mutable_profile_descriptors()->emplace_back(std::move(prof_desc));
107 
108   // Additional attributes are also OK.
109   fidlbredr::Attribute addl_attr;
110   addl_attr.set_id(0x000A);  // Documentation URL ID
111   fidlbredr::DataElement doc_url_el;
112   doc_url_el.set_url("fuchsia.dev");
113   addl_attr.set_element(std::move(doc_url_el));
114   def.mutable_additional_attributes()->emplace_back(std::move(addl_attr));
115 
116   return def;
117 }
118 
MakeMapMceServiceDefinition()119 fidlbredr::ServiceDefinition MakeMapMceServiceDefinition() {
120   // MAP MCE service definition requires RFCOMM and OBEX.
121   fidlbredr::ServiceDefinition def;
122   def.mutable_service_class_uuids()->emplace_back(
123       fidl_helpers::UuidToFidl(bt::sdp::profile::kMessageNotificationServer));
124 
125   // [[L2CAP], [RFCOMM, Channel#], [OBEX]]
126   fidlbredr::ProtocolDescriptor l2cap_proto;
127   l2cap_proto.set_protocol(fidlbredr::ProtocolIdentifier::L2CAP);
128   std::vector<fidlbredr::DataElement> l2cap_params;
129   l2cap_proto.set_params(std::move(l2cap_params));
130   def.mutable_protocol_descriptor_list()->emplace_back(std::move(l2cap_proto));
131   fidlbredr::ProtocolDescriptor rfcomm_proto;
132   rfcomm_proto.set_protocol(fidlbredr::ProtocolIdentifier::RFCOMM);
133   fidlbredr::DataElement rfcomm_data_el;
134   rfcomm_data_el.set_uint8(5);  // Random RFCOMM channel
135   std::vector<fidlbredr::DataElement> rfcomm_params;
136   rfcomm_params.emplace_back(std::move(rfcomm_data_el));
137   rfcomm_proto.set_params(std::move(rfcomm_params));
138   def.mutable_protocol_descriptor_list()->emplace_back(std::move(rfcomm_proto));
139   fidlbredr::ProtocolDescriptor obex_proto;
140   obex_proto.set_protocol(fidlbredr::ProtocolIdentifier::OBEX);
141   std::vector<fidlbredr::DataElement> obex_params;
142   obex_proto.set_params(std::move(obex_params));
143   def.mutable_protocol_descriptor_list()->emplace_back(std::move(obex_proto));
144 
145   // Additional protocols. NOTE: This is fictional and not part of a real MCE
146   // definition.
147   std::vector<fidlbredr::ProtocolDescriptor> additional_proto;
148   fidlbredr::ProtocolDescriptor additional_l2cap_proto;
149   additional_l2cap_proto.set_protocol(fidlbredr::ProtocolIdentifier::L2CAP);
150   fidlbredr::DataElement additional_l2cap_data_el;
151   additional_l2cap_data_el.set_uint16(fidlbredr::PSM_DYNAMIC);
152   std::vector<fidlbredr::DataElement> additional_l2cap_params;
153   additional_l2cap_params.emplace_back(std::move(additional_l2cap_data_el));
154   additional_l2cap_proto.set_params(std::move(additional_l2cap_params));
155   additional_proto.emplace_back(std::move(additional_l2cap_proto));
156   fidlbredr::ProtocolDescriptor additional_obex_proto;
157   additional_obex_proto.set_protocol(fidlbredr::ProtocolIdentifier::OBEX);
158   std::vector<fidlbredr::DataElement> additional_obex_params;
159   additional_obex_proto.set_params(std::move(additional_obex_params));
160   additional_proto.emplace_back(std::move(additional_obex_proto));
161   def.mutable_additional_protocol_descriptor_lists()->emplace_back(
162       std::move(additional_proto));
163 
164   fidlbredr::Information info;
165   info.set_language("en");
166   info.set_name("foo_test");
167   def.mutable_information()->emplace_back(std::move(info));
168 
169   fidlbredr::ProfileDescriptor prof_desc;
170   prof_desc.set_profile_id(
171       fidlbredr::ServiceClassProfileIdentifier::MESSAGE_ACCESS_PROFILE);
172   prof_desc.set_major_version(1);
173   prof_desc.set_minor_version(4);
174   def.mutable_profile_descriptors()->emplace_back(std::move(prof_desc));
175 
176   // Additional attributes - one requests a dynamic PSM.
177   fidlbredr::Attribute goep_attr;
178   goep_attr.set_id(0x200);  // GoepL2capPsm
179   fidlbredr::DataElement goep_el;
180   goep_el.set_uint16(fidlbredr::PSM_DYNAMIC);
181   goep_attr.set_element(std::move(goep_el));
182   def.mutable_additional_attributes()->emplace_back(std::move(goep_attr));
183 
184   fidlbredr::Attribute addl_attr;
185   addl_attr.set_id(0x317);  // MAP supported features
186   fidlbredr::DataElement addl_el;
187   addl_el.set_uint32(1);  // Random features
188   addl_attr.set_element(std::move(addl_el));
189   def.mutable_additional_attributes()->emplace_back(std::move(addl_attr));
190 
191   return def;
192 }
193 
194 // Returns a basic protocol list element with a protocol descriptor list that
195 // only contains an L2CAP descriptor.
MakeL2capProtocolListElement()196 bt::sdp::DataElement MakeL2capProtocolListElement() {
197   bt::sdp::DataElement l2cap_uuid_el;
198   l2cap_uuid_el.Set(bt::UUID(bt::sdp::protocol::kL2CAP));
199   std::vector<bt::sdp::DataElement> l2cap_descriptor_list;
200   l2cap_descriptor_list.emplace_back(std::move(l2cap_uuid_el));
201   std::vector<bt::sdp::DataElement> protocols;
202   protocols.emplace_back(std::move(l2cap_descriptor_list));
203   bt::sdp::DataElement protocol_list_el;
204   protocol_list_el.Set(std::move(protocols));
205   return protocol_list_el;
206 }
207 
208 using TestingBase = bthost::testing::AdapterTestFixture;
209 class ProfileServerTest : public TestingBase {
210  public:
211   ProfileServerTest() = default;
212   ~ProfileServerTest() override = default;
213 
214  protected:
SetUp(FeaturesBits features)215   void SetUp(FeaturesBits features) {
216     bt::testing::FakeController::Settings settings;
217     settings.ApplyDualModeDefaults();
218     settings.synchronous_data_packet_length = kSynchronousDataPacketLength;
219     settings.total_num_synchronous_data_packets =
220         kTotalNumSynchronousDataPackets;
221     TestingBase::SetUp(settings, features);
222 
223     fidlbredr::ProfileHandle profile_handle;
224     client_.Bind(std::move(profile_handle));
225     server_ = std::make_unique<ProfileServer>(adapter()->AsWeakPtr(),
226                                               client_.NewRequest(dispatcher()));
227   }
SetUp()228   void SetUp() override { SetUp(FeaturesBits{0}); }
229 
TearDown()230   void TearDown() override {
231     RunLoopUntilIdle();
232     client_ = nullptr;
233     server_ = nullptr;
234     TestingBase::TearDown();
235   }
236 
server() const237   ProfileServer* server() const { return server_.get(); }
238 
client()239   fidlbredr::ProfilePtr& client() { return client_; }
240 
peer_cache() const241   bt::gap::PeerCache* peer_cache() const { return adapter()->peer_cache(); }
242 
243  private:
244   std::unique_ptr<ProfileServer> server_;
245   fidlbredr::ProfilePtr client_;
246 
247   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ProfileServerTest);
248 };
249 
250 class FakeConnectionReceiver
251     : public fidlbredr::testing::ConnectionReceiver_TestBase {
252  public:
FakeConnectionReceiver(fidl::InterfaceRequest<ConnectionReceiver> request,async_dispatcher_t * dispatcher)253   FakeConnectionReceiver(fidl::InterfaceRequest<ConnectionReceiver> request,
254                          async_dispatcher_t* dispatcher)
255       : binding_(this, std::move(request), dispatcher),
256         connected_count_(0),
257         closed_(false) {
258     binding_.set_error_handler([&](zx_status_t /*status*/) { closed_ = true; });
259   }
260 
Connected(fuchsia::bluetooth::PeerId peer_id,fidlbredr::Channel channel,std::vector<fidlbredr::ProtocolDescriptor> protocol)261   void Connected(fuchsia::bluetooth::PeerId peer_id,
262                  fidlbredr::Channel channel,
263                  std::vector<fidlbredr::ProtocolDescriptor> protocol) override {
264     peer_id_ = peer_id;
265     channel_ = std::move(channel);
266     protocol_ = std::move(protocol);
267     connected_count_++;
268   }
269 
Revoke()270   void Revoke() { binding_.events().OnRevoke(); }
271 
connected_count() const272   size_t connected_count() const { return connected_count_; }
peer_id() const273   const std::optional<fuchsia::bluetooth::PeerId>& peer_id() const {
274     return peer_id_;
275   }
channel() const276   const std::optional<fidlbredr::Channel>& channel() const { return channel_; }
protocol() const277   const std::optional<std::vector<fidlbredr::ProtocolDescriptor>>& protocol()
278       const {
279     return protocol_;
280   }
closed()281   bool closed() { return closed_; }
282 
bind_ext_direction()283   std::optional<fidlbredr::AudioDirectionExtPtr> bind_ext_direction() {
284     if (!channel().has_value()) {
285       return std::nullopt;
286     }
287     fidlbredr::AudioDirectionExtPtr client =
288         channel_.value().mutable_ext_direction()->Bind();
289     return client;
290   }
291 
take_channel()292   fidlbredr::Channel take_channel() {
293     fidlbredr::Channel channel = std::move(channel_.value());
294     channel_.reset();
295     return channel;
296   }
297 
298  private:
299   fidl::Binding<ConnectionReceiver> binding_;
300   size_t connected_count_;
301   std::optional<fuchsia::bluetooth::PeerId> peer_id_;
302   std::optional<fidlbredr::Channel> channel_;
303   std::optional<std::vector<fidlbredr::ProtocolDescriptor>> protocol_;
304   bool closed_;
305 
NotImplemented_(const std::string & name)306   void NotImplemented_(const std::string& name) override {
307     FAIL() << name << " is not implemented";
308   }
309 };
310 
311 class FakeSearchResults : public fidlbredr::testing::SearchResults_TestBase {
312  public:
FakeSearchResults(fidl::InterfaceRequest<SearchResults> request,async_dispatcher_t * dispatcher)313   FakeSearchResults(fidl::InterfaceRequest<SearchResults> request,
314                     async_dispatcher_t* dispatcher)
315       : binding_(this, std::move(request), dispatcher),
316         service_found_count_(0) {
317     binding_.set_error_handler([this](zx_status_t) { closed_ = true; });
318   }
319 
ServiceFound(fuchsia::bluetooth::PeerId peer_id,fidl::VectorPtr<fidlbredr::ProtocolDescriptor> protocol,std::vector<fidlbredr::Attribute> attributes,ServiceFoundCallback callback)320   void ServiceFound(fuchsia::bluetooth::PeerId peer_id,
321                     fidl::VectorPtr<fidlbredr::ProtocolDescriptor> protocol,
322                     std::vector<fidlbredr::Attribute> attributes,
323                     ServiceFoundCallback callback) override {
324     peer_id_ = peer_id;
325     attributes_ = std::move(attributes);
326     callback(fidlbredr::SearchResults_ServiceFound_Result::WithResponse(
327         fidlbredr::SearchResults_ServiceFound_Response()));
328     service_found_count_++;
329   }
330 
closed() const331   bool closed() const { return closed_; }
service_found_count() const332   size_t service_found_count() const { return service_found_count_; }
peer_id() const333   const std::optional<fuchsia::bluetooth::PeerId>& peer_id() const {
334     return peer_id_;
335   }
attributes() const336   const std::optional<std::vector<fidlbredr::Attribute>>& attributes() const {
337     return attributes_;
338   }
339 
340  private:
341   bool closed_ = false;
342   fidl::Binding<SearchResults> binding_;
343   std::optional<fuchsia::bluetooth::PeerId> peer_id_;
344   std::optional<std::vector<fidlbredr::Attribute>> attributes_;
345   size_t service_found_count_;
346 
NotImplemented_(const std::string & name)347   void NotImplemented_(const std::string& name) override {
348     FAIL() << name << " is not implemented";
349   }
350 };
351 
TEST_F(ProfileServerTest,ErrorOnInvalidDefinition)352 TEST_F(ProfileServerTest, ErrorOnInvalidDefinition) {
353   fidlbredr::ConnectionReceiverHandle receiver_handle;
354   fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request =
355       receiver_handle.NewRequest();
356 
357   std::vector<fidlbredr::ServiceDefinition> services;
358   fidlbredr::ServiceDefinition def;
359   // Empty service definition is not allowed - it must contain at least a
360   // service UUID.
361 
362   services.emplace_back(std::move(def));
363 
364   size_t cb_count = 0;
365   auto cb = [&](fidlbredr::Profile_Advertise_Result result) {
366     cb_count++;
367     EXPECT_TRUE(result.is_err());
368     EXPECT_EQ(result.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
369   };
370 
371   fidlbredr::ProfileAdvertiseRequest adv_request;
372   adv_request.set_services(std::move(services));
373   adv_request.set_receiver(std::move(receiver_handle));
374   client()->Advertise(std::move(adv_request), std::move(cb));
375 
376   RunLoopUntilIdle();
377 
378   ASSERT_EQ(cb_count, 1u);
379   // Server should close because it's an invalid definition.
380   zx_signals_t signals;
381   request.channel().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time(0), &signals);
382   EXPECT_TRUE(signals & ZX_CHANNEL_PEER_CLOSED);
383 }
384 
TEST_F(ProfileServerTest,ErrorOnMultipleAdvertiseRequests)385 TEST_F(ProfileServerTest, ErrorOnMultipleAdvertiseRequests) {
386   fidlbredr::ConnectionReceiverHandle receiver_handle1;
387   fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request1 =
388       receiver_handle1.NewRequest();
389 
390   std::vector<fidlbredr::ServiceDefinition> services1;
391   services1.emplace_back(MakeFIDLServiceDefinition());
392 
393   size_t cb1_count = 0;
394   auto cb1 = [&](fidlbredr::Profile_Advertise_Result result) {
395     cb1_count++;
396     EXPECT_TRUE(result.is_response());
397   };
398 
399   fidlbredr::ProfileAdvertiseRequest adv_request1;
400   adv_request1.set_services(std::move(services1));
401   adv_request1.set_receiver(std::move(receiver_handle1));
402   client()->Advertise(std::move(adv_request1), std::move(cb1));
403 
404   RunLoopUntilIdle();
405 
406   // First callback should be invoked with success since the advertisement is
407   // valid.
408   ASSERT_EQ(cb1_count, 1u);
409 
410   fidlbredr::ConnectionReceiverHandle receiver_handle2;
411   fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request2 =
412       receiver_handle2.NewRequest();
413 
414   std::vector<fidlbredr::ServiceDefinition> services2;
415   services2.emplace_back(MakeFIDLServiceDefinition());
416 
417   // Second callback should error because the second advertisement is requesting
418   // a taken PSM.
419   size_t cb2_count = 0;
420   auto cb2 = [&](fidlbredr::Profile_Advertise_Result response) {
421     cb2_count++;
422     EXPECT_TRUE(response.is_err());
423     EXPECT_EQ(response.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
424   };
425 
426   fidlbredr::ProfileAdvertiseRequest adv_request2;
427   adv_request2.set_services(std::move(services2));
428   adv_request2.set_receiver(std::move(receiver_handle2));
429   client()->Advertise(std::move(adv_request2), std::move(cb2));
430 
431   RunLoopUntilIdle();
432 
433   ASSERT_EQ(cb1_count, 1u);
434   ASSERT_EQ(cb2_count, 1u);
435 
436   // Second channel should close.
437   zx_signals_t signals;
438   request2.channel().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time(0), &signals);
439   EXPECT_TRUE(signals & ZX_CHANNEL_PEER_CLOSED);
440 }
441 
TEST_F(ProfileServerTest,ErrorOnInvalidConnectParametersNoPsm)442 TEST_F(ProfileServerTest, ErrorOnInvalidConnectParametersNoPsm) {
443   // Random peer, since we don't expect the connection.
444   fuchsia::bluetooth::PeerId peer_id{123};
445 
446   // No PSM provided - this is invalid.
447   fidlbredr::L2capParameters l2cap_params;
448   fidlbredr::ConnectParameters conn_params;
449   l2cap_params.set_parameters(fbt::ChannelParameters());
450   conn_params.set_l2cap(std::move(l2cap_params));
451 
452   // Expect an error result.
453   auto sock_cb = [](fidlbredr::Profile_Connect_Result result) {
454     EXPECT_TRUE(result.is_err());
455     EXPECT_EQ(result.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
456   };
457 
458   client()->Connect(peer_id, std::move(conn_params), std::move(sock_cb));
459   RunLoopUntilIdle();
460 }
461 
TEST_F(ProfileServerTest,ErrorOnInvalidConnectParametersRfcomm)462 TEST_F(ProfileServerTest, ErrorOnInvalidConnectParametersRfcomm) {
463   // Random peer, since we don't expect the connection.
464   fuchsia::bluetooth::PeerId peer_id{123};
465 
466   // RFCOMM Parameters are provided - this is not supported.
467   fidlbredr::RfcommParameters rfcomm_params;
468   fidlbredr::ConnectParameters conn_params;
469   conn_params.set_rfcomm(std::move(rfcomm_params));
470 
471   // Expect an error result.
472   auto sock_cb = [](fidlbredr::Profile_Connect_Result result) {
473     EXPECT_TRUE(result.is_err());
474     EXPECT_EQ(result.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
475   };
476 
477   client()->Connect(peer_id, std::move(conn_params), std::move(sock_cb));
478   RunLoopUntilIdle();
479 }
480 
TEST_F(ProfileServerTest,DynamicPsmAdvertisementIsUpdated)481 TEST_F(ProfileServerTest, DynamicPsmAdvertisementIsUpdated) {
482   fidlbredr::ConnectionReceiverHandle receiver_handle;
483   fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request =
484       receiver_handle.NewRequest();
485 
486   std::vector<fidlbredr::ServiceDefinition> services;
487   services.emplace_back(MakeMapMceServiceDefinition());
488 
489   size_t cb_count = 0;
490   auto cb = [&](fidlbredr::Profile_Advertise_Result result) {
491     cb_count++;
492     EXPECT_TRUE(result.is_response());
493     EXPECT_EQ(result.response().services().size(), 1u);
494     const auto registered_def =
495         std::move(result.response().mutable_services()->front());
496     const auto original_def = MakeMapMceServiceDefinition();
497     // The UUIDs, primary protocol list, & profile descriptors should be
498     // unchanged.
499     ASSERT_TRUE(::fidl::Equals(registered_def.service_class_uuids(),
500                                original_def.service_class_uuids()));
501     ASSERT_TRUE(::fidl::Equals(registered_def.protocol_descriptor_list(),
502                                original_def.protocol_descriptor_list()));
503     ASSERT_TRUE(::fidl::Equals(registered_def.profile_descriptors(),
504                                original_def.profile_descriptors()));
505     // The additional protocol list should be updated with a randomly assigned
506     // dynamic PSM.
507     EXPECT_EQ(registered_def.additional_protocol_descriptor_lists().size(), 1u);
508     EXPECT_NE(registered_def.additional_protocol_descriptor_lists()
509                   .front()
510                   .front()
511                   .params()
512                   .front()
513                   .uint16(),
514               fidlbredr::PSM_DYNAMIC);
515     // TODO(b/327758656): Verify information and additional attributes once
516     // implemented.
517   };
518 
519   fidlbredr::ProfileAdvertiseRequest adv_request;
520   adv_request.set_services(std::move(services));
521   adv_request.set_receiver(std::move(receiver_handle));
522   client()->Advertise(std::move(adv_request), std::move(cb));
523 
524   RunLoopUntilIdle();
525   EXPECT_EQ(cb_count, 1u);
526 }
527 
TEST_F(ProfileServerTest,RevokeConnectionReceiverUnregistersAdvertisement)528 TEST_F(ProfileServerTest, RevokeConnectionReceiverUnregistersAdvertisement) {
529   fidlbredr::ConnectionReceiverHandle receiver_handle;
530   FakeConnectionReceiver connect_receiver(receiver_handle.NewRequest(),
531                                           dispatcher());
532 
533   std::vector<fidlbredr::ServiceDefinition> services;
534   services.emplace_back(MakeFIDLServiceDefinition());
535 
536   size_t cb_count = 0;
537   auto cb = [&](fidlbredr::Profile_Advertise_Result result) {
538     cb_count++;
539     EXPECT_TRUE(result.is_response());
540   };
541 
542   fidlbredr::ProfileAdvertiseRequest adv_request;
543   adv_request.set_services(std::move(services));
544   adv_request.set_receiver(std::move(receiver_handle));
545   client()->Advertise(std::move(adv_request), std::move(cb));
546   RunLoopUntilIdle();
547 
548   // Advertisement should be registered. The callback should be invoked with the
549   // advertised set of services, and the `ConnectionReceiver` should still be
550   // open.
551   ASSERT_EQ(cb_count, 1u);
552   ASSERT_FALSE(connect_receiver.closed());
553 
554   // Server end of `ConnectionReceiver` revokes the advertisement.
555   connect_receiver.Revoke();
556   RunLoopUntilIdle();
557 
558   // Profile server should drop the advertisement - the `connect_receiver`
559   // should be closed.
560   ASSERT_TRUE(connect_receiver.closed());
561 }
562 
563 class ProfileServerTestConnectedPeer : public ProfileServerTest {
564  public:
565   ProfileServerTestConnectedPeer() = default;
566   ~ProfileServerTestConnectedPeer() override = default;
567 
568  protected:
SetUp(FeaturesBits features)569   void SetUp(FeaturesBits features) {
570     ProfileServerTest::SetUp(features);
571     peer_ = peer_cache()->NewPeer(kTestDevAddr, /*connectable=*/true);
572     std::unique_ptr<bt::testing::FakePeer> fake_peer =
573         std::make_unique<bt::testing::FakePeer>(kTestDevAddr, pw_dispatcher());
574     test_device()->AddPeer(std::move(fake_peer));
575 
576     std::optional<bt::hci::Result<>> status;
577     auto connect_cb = [this, &status](auto cb_status, auto cb_conn_ref) {
578       ASSERT_TRUE(cb_conn_ref);
579       status = cb_status;
580       connection_ = std::move(cb_conn_ref);
581     };
582 
583     EXPECT_TRUE(adapter()->bredr()->Connect(peer_->identifier(), connect_cb));
584     EXPECT_EQ(bt::gap::Peer::ConnectionState::kInitializing,
585               peer_->bredr()->connection_state());
586 
587     RunLoopUntilIdle();
588     ASSERT_TRUE(status.has_value());
589     EXPECT_EQ(fit::ok(), status.value());
590     ASSERT_TRUE(connection_);
591     EXPECT_EQ(peer_->identifier(), connection_->peer_id());
592     EXPECT_NE(bt::gap::Peer::ConnectionState::kNotConnected,
593               peer_->bredr()->connection_state());
594   }
595 
SetUp()596   void SetUp() override { SetUp(FeaturesBits::kHciSco); }
597 
TearDown()598   void TearDown() override {
599     connection_ = nullptr;
600     peer_ = nullptr;
601     ProfileServerTest::TearDown();
602   }
603 
connection() const604   bt::gap::BrEdrConnection* connection() const { return connection_; }
605 
peer() const606   bt::gap::Peer* peer() const { return peer_; }
607 
608  private:
609   bt::gap::BrEdrConnection* connection_;
610   bt::gap::Peer* peer_;
611 
612   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ProfileServerTestConnectedPeer);
613 };
614 
615 class ProfileServerTestScoConnected : public ProfileServerTestConnectedPeer {
616  public:
SetUp()617   void SetUp() override {
618     fidlbredr::ScoConnectionParameters params =
619         CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0);
620     params.set_path(fidlbredr::DataPath::HOST);
621     SetUp(std::move(params));
622   }
623 
SetUp(fidlbredr::ScoConnectionParameters conn_params)624   void SetUp(fidlbredr::ScoConnectionParameters conn_params) {
625     ProfileServerTestConnectedPeer::SetUp(FeaturesBits::kHciSco);
626 
627     test_device()->set_configure_sco_cb(
628         [](auto, auto, auto, auto cb) { cb(PW_STATUS_OK); });
629     test_device()->set_reset_sco_cb([](auto cb) { cb(PW_STATUS_OK); });
630 
631     std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
632     sco_params_list.emplace_back(std::move(conn_params));
633 
634     fidlbredr::ProfileConnectScoRequest request;
635     request.set_peer_id(
636         fuchsia::bluetooth::PeerId{peer()->identifier().value()});
637     request.set_initiator(false);
638     request.set_params(std::move(sco_params_list));
639     fidlbredr::ScoConnectionHandle connection_handle;
640     request.set_connection(connection_handle.NewRequest());
641 
642     sco_connection_ = connection_handle.Bind();
643     sco_connection_.set_error_handler([this](zx_status_t status) {
644       sco_connection_ = nullptr;
645       sco_conn_error_ = status;
646     });
647 
648     std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
649         connection_complete;
650     sco_connection_.events().OnConnectionComplete =
651         [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
652           connection_complete = std::move(request);
653         };
654 
655     client()->ConnectSco(std::move(request));
656     RunLoopUntilIdle();
657     test_device()->SendConnectionRequest(peer()->address(),
658                                          pw::bluetooth::emboss::LinkType::SCO);
659     RunLoopUntilIdle();
660     ASSERT_TRUE(connection_complete.has_value());
661     ASSERT_TRUE(connection_complete->is_connected_params());
662 
663     // OnConnectionComplete should never be called again.
664     sco_connection_.events().OnConnectionComplete =
665         [](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
666           FAIL();
667         };
668 
669     // Find the link handle used for the SCO connection.
670     bt::testing::FakePeer* fake_peer =
671         test_device()->FindPeer(peer()->address());
672     ASSERT_TRUE(fake_peer);
673     // There are 2 connections: BR/EDR, SCO
674     ASSERT_EQ(fake_peer->logical_links().size(), 2u);
675     bt::testing::FakePeer::HandleSet links = fake_peer->logical_links();
676     // The link that is not the BR/EDR connection link must be the SCO link.
677     links.erase(connection()->link().handle());
678     sco_conn_handle_ = *links.begin();
679   }
680 
TearDown()681   void TearDown() override { ProfileServerTestConnectedPeer::TearDown(); }
682 
sco_connection()683   fidlbredr::ScoConnectionPtr& sco_connection() { return sco_connection_; }
684 
sco_conn_error() const685   std::optional<zx_status_t> sco_conn_error() const { return sco_conn_error_; }
686 
sco_handle() const687   bt::hci_spec::ConnectionHandle sco_handle() const { return sco_conn_handle_; }
688 
689  private:
690   fidlbredr::ScoConnectionPtr sco_connection_;
691   bt::hci_spec::ConnectionHandle sco_conn_handle_;
692   std::optional<zx_status_t> sco_conn_error_;
693 };
694 
695 class ProfileServerTestOffloadedScoConnected
696     : public ProfileServerTestScoConnected {
697  public:
SetUp()698   void SetUp() override {
699     fidlbredr::ScoConnectionParameters params =
700         CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0);
701     params.set_path(fidlbredr::DataPath::OFFLOAD);
702     ProfileServerTestScoConnected::SetUp(std::move(params));
703   }
704 };
705 
TEST_F(ProfileServerTestConnectedPeer,ConnectL2capChannelParametersUseSocket)706 TEST_F(ProfileServerTestConnectedPeer, ConnectL2capChannelParametersUseSocket) {
707   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
708       std::make_unique<bt::gap::FakePairingDelegate>(
709           bt::sm::IOCapability::kDisplayYesNo);
710   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
711   // Approve pairing requests.
712   pairing_delegate->SetConfirmPairingCallback(
713       [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
714   pairing_delegate->SetCompletePairingCallback(
715       [&](bt::PeerId, bt::sm::Result<> status) {
716         EXPECT_EQ(fit::ok(), status);
717       });
718 
719   bt::l2cap::ChannelParameters expected_params;
720   expected_params.mode =
721       bt::l2cap::RetransmissionAndFlowControlMode::kEnhancedRetransmission;
722   expected_params.max_rx_sdu_size = bt::l2cap::kMinACLMTU;
723   l2cap()->ExpectOutboundL2capChannel(
724       connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
725 
726   // Expect a non-empty channel result.
727   std::optional<fidlbredr::Channel> channel;
728   auto chan_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
729     EXPECT_TRUE(result.is_response());
730     channel = std::move(result.response().channel);
731   };
732   // Initiates pairing
733 
734   fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
735 
736   // Set L2CAP channel parameters
737   fbt::ChannelParameters chan_params;
738   fidlbredr::L2capParameters l2cap_params;
739   fidlbredr::ConnectParameters conn_params;
740   chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
741   chan_params.set_max_rx_packet_size(bt::l2cap::kMinACLMTU);
742   l2cap_params.set_psm(kPsm);
743   l2cap_params.set_parameters(std::move(chan_params));
744   conn_params.set_l2cap(std::move(l2cap_params));
745 
746   client()->Connect(peer_id, std::move(conn_params), std::move(chan_cb));
747   RunLoopUntilIdle();
748 
749   ASSERT_TRUE(channel.has_value());
750   EXPECT_TRUE(channel->has_socket());
751   EXPECT_FALSE(channel->IsEmpty());
752   EXPECT_EQ(channel->channel_mode(), chan_params.channel_mode());
753   // FakeL2cap returns channels with max tx sdu size of kDefaultMTU.
754   EXPECT_EQ(channel->max_tx_sdu_size(), bt::l2cap::kDefaultMTU);
755   EXPECT_FALSE(channel->has_ext_direction());
756   EXPECT_FALSE(channel->has_flush_timeout());
757 }
758 
TEST_F(ProfileServerTestConnectedPeer,ConnectL2capChannelParametersUseConnection)759 TEST_F(ProfileServerTestConnectedPeer,
760        ConnectL2capChannelParametersUseConnection) {
761   server()->set_use_sockets(false);
762 
763   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
764       std::make_unique<bt::gap::FakePairingDelegate>(
765           bt::sm::IOCapability::kDisplayYesNo);
766   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
767   // Approve pairing requests.
768   pairing_delegate->SetConfirmPairingCallback(
769       [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
770   pairing_delegate->SetCompletePairingCallback(
771       [&](bt::PeerId, bt::sm::Result<> status) {
772         EXPECT_EQ(fit::ok(), status);
773       });
774 
775   bt::l2cap::ChannelParameters expected_params;
776   expected_params.mode =
777       bt::l2cap::RetransmissionAndFlowControlMode::kEnhancedRetransmission;
778   expected_params.max_rx_sdu_size = bt::l2cap::kMinACLMTU;
779   l2cap()->ExpectOutboundL2capChannel(
780       connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
781 
782   // Expect a non-empty channel result.
783   std::optional<fidlbredr::Channel> channel;
784   auto chan_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
785     EXPECT_TRUE(result.is_response());
786     channel = std::move(result.response().channel);
787   };
788   // Initiates pairing
789 
790   fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
791 
792   // Set L2CAP channel parameters
793   fbt::ChannelParameters chan_params;
794   fidlbredr::L2capParameters l2cap_params;
795   fidlbredr::ConnectParameters conn_params;
796   chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
797   chan_params.set_max_rx_packet_size(bt::l2cap::kMinACLMTU);
798   l2cap_params.set_psm(kPsm);
799   l2cap_params.set_parameters(std::move(chan_params));
800   conn_params.set_l2cap(std::move(l2cap_params));
801 
802   client()->Connect(peer_id, std::move(conn_params), std::move(chan_cb));
803   RunLoopUntilIdle();
804 
805   ASSERT_TRUE(channel.has_value());
806   EXPECT_TRUE(channel->has_connection());
807   EXPECT_FALSE(channel->IsEmpty());
808   EXPECT_EQ(channel->channel_mode(), chan_params.channel_mode());
809   // FakeL2cap returns channels with max tx sdu size of kDefaultMTU.
810   EXPECT_EQ(channel->max_tx_sdu_size(), bt::l2cap::kDefaultMTU);
811   EXPECT_FALSE(channel->has_ext_direction());
812   EXPECT_FALSE(channel->has_flush_timeout());
813 }
814 
TEST_F(ProfileServerTestConnectedPeer,ConnectWithAuthenticationRequiredButLinkKeyNotAuthenticatedFails)815 TEST_F(ProfileServerTestConnectedPeer,
816        ConnectWithAuthenticationRequiredButLinkKeyNotAuthenticatedFails) {
817   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
818       std::make_unique<bt::gap::FakePairingDelegate>(
819           bt::sm::IOCapability::kNoInputNoOutput);
820   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
821   pairing_delegate->SetCompletePairingCallback(
822       [&](bt::PeerId, bt::sm::Result<> status) {
823         EXPECT_EQ(fit::ok(), status);
824       });
825 
826   fbt::SecurityRequirements security;
827   security.set_authentication_required(true);
828 
829   // Set L2CAP channel parameters
830   fbt::ChannelParameters chan_params;
831   fidlbredr::L2capParameters l2cap_params;
832   fidlbredr::ConnectParameters conn_params;
833   chan_params.set_security_requirements(std::move(security));
834   l2cap_params.set_psm(kPsm);
835   l2cap_params.set_parameters(std::move(chan_params));
836   conn_params.set_l2cap(std::move(l2cap_params));
837 
838   size_t sock_cb_count = 0;
839   auto sock_cb = [&](fidlbredr::Profile_Connect_Result result) {
840     sock_cb_count++;
841     ASSERT_TRUE(result.is_err());
842     EXPECT_EQ(fuchsia::bluetooth::ErrorCode::FAILED, result.err());
843   };
844 
845   fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
846 
847   // Initiates pairing.
848   // FakeController will create an unauthenticated key.
849   client()->Connect(peer_id, std::move(conn_params), std::move(sock_cb));
850   RunLoopUntilIdle();
851 
852   EXPECT_EQ(1u, sock_cb_count);
853 }
854 
855 // Tests receiving an empty Channel results in an error propagated through the
856 // callback.
TEST_F(ProfileServerTestConnectedPeer,ConnectEmptyChannelResponse)857 TEST_F(ProfileServerTestConnectedPeer, ConnectEmptyChannelResponse) {
858   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
859       std::make_unique<bt::gap::FakePairingDelegate>(
860           bt::sm::IOCapability::kDisplayYesNo);
861   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
862   // Approve pairing requests.
863   pairing_delegate->SetConfirmPairingCallback(
864       [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
865   pairing_delegate->SetCompletePairingCallback(
866       [&](bt::PeerId, bt::sm::Result<> status) {
867         EXPECT_EQ(fit::ok(), status);
868       });
869 
870   // Make the l2cap channel creation fail.
871   l2cap()->set_simulate_open_channel_failure(true);
872 
873   bt::l2cap::ChannelParameters expected_params;
874   expected_params.mode =
875       bt::l2cap::RetransmissionAndFlowControlMode::kEnhancedRetransmission;
876   expected_params.max_rx_sdu_size = bt::l2cap::kMinACLMTU;
877   l2cap()->ExpectOutboundL2capChannel(
878       connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
879 
880   fbt::ChannelParameters chan_params;
881   chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
882   chan_params.set_max_rx_packet_size(bt::l2cap::kMinACLMTU);
883   auto sock_cb = [](fidlbredr::Profile_Connect_Result result) {
884     EXPECT_TRUE(result.is_err());
885     EXPECT_EQ(fuchsia::bluetooth::ErrorCode::FAILED, result.err());
886   };
887   // Initiates pairing
888 
889   fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
890 
891   // Set L2CAP channel parameters
892   fidlbredr::L2capParameters l2cap_params;
893   fidlbredr::ConnectParameters conn_params;
894   l2cap_params.set_psm(kPsm);
895   l2cap_params.set_parameters(std::move(chan_params));
896   conn_params.set_l2cap(std::move(l2cap_params));
897 
898   client()->Connect(peer_id, std::move(conn_params), std::move(sock_cb));
899   RunLoopUntilIdle();
900 }
901 
TEST_F(ProfileServerTestConnectedPeer,AdvertiseChannelParametersReceivedInOnChannelConnectedCallbackUseSocket)902 TEST_F(
903     ProfileServerTestConnectedPeer,
904     AdvertiseChannelParametersReceivedInOnChannelConnectedCallbackUseSocket) {
905   constexpr uint16_t kTxMtu = bt::l2cap::kMinACLMTU;
906 
907   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
908       std::make_unique<bt::gap::FakePairingDelegate>(
909           bt::sm::IOCapability::kDisplayYesNo);
910   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
911 
912   fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
913   FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
914                                           dispatcher());
915 
916   std::vector<fidlbredr::ServiceDefinition> services;
917   services.emplace_back(MakeFIDLServiceDefinition());
918   fbt::ChannelParameters chan_params;
919   chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
920 
921   fidlbredr::ProfileAdvertiseRequest adv_request;
922   adv_request.set_services(std::move(services));
923   adv_request.set_parameters(std::move(chan_params));
924   adv_request.set_receiver(std::move(connect_receiver_handle));
925   client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
926   RunLoopUntilIdle();
927 
928   ASSERT_EQ(connect_receiver.connected_count(), 0u);
929   EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
930       connection()->link().handle(), kPsm, 0x40, 0x41, kTxMtu));
931   RunLoopUntilIdle();
932 
933   ASSERT_EQ(connect_receiver.connected_count(), 1u);
934   ASSERT_EQ(connect_receiver.peer_id().value().value,
935             peer()->identifier().value());
936   ASSERT_TRUE(connect_receiver.channel().value().has_socket());
937   EXPECT_EQ(connect_receiver.channel().value().channel_mode(),
938             fbt::ChannelMode::ENHANCED_RETRANSMISSION);
939   EXPECT_EQ(connect_receiver.channel().value().max_tx_sdu_size(), kTxMtu);
940   EXPECT_FALSE(connect_receiver.channel().value().has_ext_direction());
941   EXPECT_FALSE(connect_receiver.channel().value().has_flush_timeout());
942 }
943 
TEST_F(ProfileServerTestConnectedPeer,AdvertiseChannelParametersReceivedInOnChannelConnectedCallbackUseConnection)944 TEST_F(
945     ProfileServerTestConnectedPeer,
946     AdvertiseChannelParametersReceivedInOnChannelConnectedCallbackUseConnection) {
947   server()->set_use_sockets(false);
948 
949   constexpr uint16_t kTxMtu = bt::l2cap::kMinACLMTU;
950 
951   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
952       std::make_unique<bt::gap::FakePairingDelegate>(
953           bt::sm::IOCapability::kDisplayYesNo);
954   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
955 
956   fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
957   FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
958                                           dispatcher());
959 
960   std::vector<fidlbredr::ServiceDefinition> services;
961   services.emplace_back(MakeFIDLServiceDefinition());
962   fbt::ChannelParameters chan_params;
963   chan_params.set_channel_mode(fbt::ChannelMode::ENHANCED_RETRANSMISSION);
964 
965   fidlbredr::ProfileAdvertiseRequest adv_request;
966   adv_request.set_services(std::move(services));
967   adv_request.set_parameters(std::move(chan_params));
968   adv_request.set_receiver(std::move(connect_receiver_handle));
969   client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
970   RunLoopUntilIdle();
971 
972   ASSERT_EQ(connect_receiver.connected_count(), 0u);
973   EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
974       connection()->link().handle(), kPsm, 0x40, 0x41, kTxMtu));
975   RunLoopUntilIdle();
976 
977   ASSERT_EQ(connect_receiver.connected_count(), 1u);
978   ASSERT_EQ(connect_receiver.peer_id().value().value,
979             peer()->identifier().value());
980   ASSERT_TRUE(connect_receiver.channel().value().has_connection());
981   EXPECT_EQ(connect_receiver.channel().value().channel_mode(),
982             fbt::ChannelMode::ENHANCED_RETRANSMISSION);
983   EXPECT_EQ(connect_receiver.channel().value().max_tx_sdu_size(), kTxMtu);
984   EXPECT_FALSE(connect_receiver.channel().value().has_ext_direction());
985   EXPECT_FALSE(connect_receiver.channel().value().has_flush_timeout());
986 }
987 
988 class AclPrioritySupportedTest : public ProfileServerTestConnectedPeer {
989  public:
SetUp()990   void SetUp() override {
991     ProfileServerTestConnectedPeer::SetUp(FeaturesBits::kSetAclPriorityCommand);
992   }
993 };
994 
995 class PriorityTest : public AclPrioritySupportedTest,
996                      public ::testing::WithParamInterface<
997                          std::pair<fidlbredr::A2dpDirectionPriority, bool>> {};
998 
TEST_P(PriorityTest,OutboundConnectAndSetPriority)999 TEST_P(PriorityTest, OutboundConnectAndSetPriority) {
1000   const fidlbredr::A2dpDirectionPriority kPriority = GetParam().first;
1001   const bool kExpectSuccess = GetParam().second;
1002 
1003   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1004       std::make_unique<bt::gap::FakePairingDelegate>(
1005           bt::sm::IOCapability::kDisplayYesNo);
1006   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1007   // Approve pairing requests.
1008   pairing_delegate->SetConfirmPairingCallback(
1009       [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
1010   pairing_delegate->SetCompletePairingCallback(
1011       [&](bt::PeerId, bt::sm::Result<> status) {
1012         EXPECT_EQ(fit::ok(), status);
1013       });
1014 
1015   l2cap()->ExpectOutboundL2capChannel(connection()->link().handle(),
1016                                       kPsm,
1017                                       0x40,
1018                                       0x41,
1019                                       bt::l2cap::ChannelParameters());
1020 
1021   FakeChannel::WeakPtr fake_channel;
1022   l2cap()->set_channel_callback(
1023       [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
1024 
1025   // Expect a non-empty channel result.
1026   std::optional<fidlbredr::Channel> channel;
1027   auto chan_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
1028     ASSERT_TRUE(result.is_response());
1029     channel = std::move(result.response().channel);
1030   };
1031 
1032   fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
1033 
1034   // Set L2CAP channel parameters
1035   fidlbredr::L2capParameters l2cap_params;
1036   fidlbredr::ConnectParameters conn_params;
1037   l2cap_params.set_psm(kPsm);
1038   conn_params.set_l2cap(std::move(l2cap_params));
1039 
1040   // Initiates pairing
1041   client()->Connect(peer_id, std::move(conn_params), std::move(chan_cb));
1042   RunLoopUntilIdle();
1043   ASSERT_TRUE(fake_channel.is_alive());
1044   ASSERT_TRUE(channel.has_value());
1045   ASSERT_TRUE(channel->has_ext_direction());
1046   fidlbredr::AudioDirectionExtPtr client =
1047       channel->mutable_ext_direction()->Bind();
1048 
1049   size_t priority_cb_count = 0;
1050   fake_channel->set_acl_priority_fails(!kExpectSuccess);
1051   client->SetPriority(
1052       kPriority, [&](fidlbredr::AudioDirectionExt_SetPriority_Result result) {
1053         EXPECT_EQ(result.is_response(), kExpectSuccess);
1054         priority_cb_count++;
1055       });
1056 
1057   RunLoopUntilIdle();
1058   EXPECT_EQ(priority_cb_count, 1u);
1059   client = nullptr;
1060   RunLoopUntilIdle();
1061 
1062   if (kExpectSuccess) {
1063     switch (kPriority) {
1064       case fidlbredr::A2dpDirectionPriority::SOURCE:
1065         EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kSource);
1066         break;
1067       case fidlbredr::A2dpDirectionPriority::SINK:
1068         EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kSink);
1069         break;
1070       default:
1071         EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kNormal);
1072     }
1073   } else {
1074     EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kNormal);
1075   }
1076 }
1077 
1078 const std::array<std::pair<fidlbredr::A2dpDirectionPriority, bool>, 4>
1079     kPriorityParams = {{{fidlbredr::A2dpDirectionPriority::SOURCE, false},
1080                         {fidlbredr::A2dpDirectionPriority::SOURCE, true},
1081                         {fidlbredr::A2dpDirectionPriority::SINK, true},
1082                         {fidlbredr::A2dpDirectionPriority::NORMAL, true}}};
1083 INSTANTIATE_TEST_SUITE_P(ProfileServerTestConnectedPeer,
1084                          PriorityTest,
1085                          ::testing::ValuesIn(kPriorityParams));
1086 
TEST_F(AclPrioritySupportedTest,InboundConnectAndSetPriority)1087 TEST_F(AclPrioritySupportedTest, InboundConnectAndSetPriority) {
1088   constexpr uint16_t kTxMtu = bt::l2cap::kMinACLMTU;
1089 
1090   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1091       std::make_unique<bt::gap::FakePairingDelegate>(
1092           bt::sm::IOCapability::kDisplayYesNo);
1093   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1094 
1095   FakeChannel::WeakPtr fake_channel;
1096   l2cap()->set_channel_callback(
1097       [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
1098 
1099   fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
1100   FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
1101                                           dispatcher());
1102 
1103   std::vector<fidlbredr::ServiceDefinition> services;
1104   services.emplace_back(MakeFIDLServiceDefinition());
1105   fidlbredr::ProfileAdvertiseRequest adv_request;
1106   adv_request.set_services(std::move(services));
1107   adv_request.set_receiver(std::move(connect_receiver_handle));
1108   client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
1109   RunLoopUntilIdle();
1110 
1111   ASSERT_EQ(connect_receiver.connected_count(), 0u);
1112   EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
1113       connection()->link().handle(), kPsm, 0x40, 0x41, kTxMtu));
1114 
1115   RunLoopUntilIdle();
1116   ASSERT_EQ(connect_receiver.connected_count(), 1u);
1117   ASSERT_TRUE(connect_receiver.channel().has_value());
1118   ASSERT_TRUE(connect_receiver.channel().value().has_ext_direction());
1119   // Taking value() is safe because of the has_ext_direction() check.
1120   fidlbredr::AudioDirectionExtPtr client =
1121       connect_receiver.bind_ext_direction().value();
1122 
1123   size_t priority_cb_count = 0;
1124   client->SetPriority(
1125       fidlbredr::A2dpDirectionPriority::SINK,
1126       [&](fidlbredr::AudioDirectionExt_SetPriority_Result result) {
1127         EXPECT_TRUE(result.is_response());
1128         priority_cb_count++;
1129       });
1130 
1131   RunLoopUntilIdle();
1132   EXPECT_EQ(priority_cb_count, 1u);
1133   ASSERT_TRUE(fake_channel.is_alive());
1134   EXPECT_EQ(fake_channel->requested_acl_priority(), AclPriority::kSink);
1135 }
1136 
1137 // Verifies that a socket channel relay is correctly set up such that bytes
1138 // written to the socket are sent to the channel.
TEST_F(ProfileServerTestConnectedPeer,ConnectReturnsValidSocket)1139 TEST_F(ProfileServerTestConnectedPeer, ConnectReturnsValidSocket) {
1140   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1141       std::make_unique<bt::gap::FakePairingDelegate>(
1142           bt::sm::IOCapability::kDisplayYesNo);
1143   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1144   // Approve pairing requests.
1145   pairing_delegate->SetConfirmPairingCallback(
1146       [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
1147   pairing_delegate->SetCompletePairingCallback(
1148       [&](bt::PeerId, bt::sm::Result<> status) {
1149         EXPECT_EQ(fit::ok(), status);
1150       });
1151 
1152   bt::l2cap::ChannelParameters expected_params;
1153   l2cap()->ExpectOutboundL2capChannel(
1154       connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
1155 
1156   std::optional<FakeChannel::WeakPtr> fake_chan;
1157   l2cap()->set_channel_callback(
1158       [&fake_chan](FakeChannel::WeakPtr chan) { fake_chan = std::move(chan); });
1159 
1160   // Expect a non-empty channel result.
1161   std::optional<fidlbredr::Channel> channel;
1162   auto result_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
1163     EXPECT_TRUE(result.is_response());
1164     channel = std::move(result.response().channel);
1165   };
1166 
1167   fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
1168 
1169   // Set L2CAP channel parameters
1170   fidlbredr::L2capParameters l2cap_params;
1171   fidlbredr::ConnectParameters conn_params;
1172   l2cap_params.set_psm(kPsm);
1173   l2cap_params.set_parameters(fbt::ChannelParameters());
1174   conn_params.set_l2cap(std::move(l2cap_params));
1175 
1176   // Initiates pairing
1177   client()->Connect(peer_id, std::move(conn_params), std::move(result_cb));
1178   RunLoopUntilIdle();
1179 
1180   ASSERT_TRUE(channel.has_value());
1181   ASSERT_TRUE(channel->has_socket());
1182   auto& socket = channel->socket();
1183 
1184   ASSERT_TRUE(fake_chan.has_value());
1185   FakeChannel::WeakPtr fake_chan_ptr = fake_chan.value();
1186   size_t send_count = 0;
1187   fake_chan_ptr->SetSendCallback([&send_count](auto buffer) { send_count++; },
1188                                  pw_dispatcher());
1189 
1190   const char write_data[2] = "a";
1191   size_t bytes_written = 0;
1192   auto status =
1193       socket.write(0, write_data, sizeof(write_data) - 1, &bytes_written);
1194   EXPECT_EQ(ZX_OK, status);
1195   EXPECT_EQ(1u, bytes_written);
1196   RunLoopUntilIdle();
1197   EXPECT_EQ(1u, send_count);
1198 }
1199 
1200 // Verifies that a BrEdrConnectionServer is correctly set up such that bytes
1201 // written to the Connection are sent to the channel.
TEST_F(ProfileServerTestConnectedPeer,ConnectReturnsValidConnection)1202 TEST_F(ProfileServerTestConnectedPeer, ConnectReturnsValidConnection) {
1203   server()->set_use_sockets(false);
1204 
1205   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1206       std::make_unique<bt::gap::FakePairingDelegate>(
1207           bt::sm::IOCapability::kDisplayYesNo);
1208   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1209   // Approve pairing requests.
1210   pairing_delegate->SetConfirmPairingCallback(
1211       [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
1212   pairing_delegate->SetCompletePairingCallback(
1213       [&](bt::PeerId, bt::sm::Result<> status) {
1214         EXPECT_EQ(fit::ok(), status);
1215       });
1216 
1217   bt::l2cap::ChannelParameters expected_params;
1218   l2cap()->ExpectOutboundL2capChannel(
1219       connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
1220 
1221   std::optional<FakeChannel::WeakPtr> fake_chan;
1222   l2cap()->set_channel_callback(
1223       [&fake_chan](FakeChannel::WeakPtr chan) { fake_chan = std::move(chan); });
1224 
1225   // Expect a non-empty channel result.
1226   std::optional<fidlbredr::Channel> channel;
1227   auto result_cb = [&channel](fidlbredr::Profile_Connect_Result result) {
1228     EXPECT_TRUE(result.is_response());
1229     channel = std::move(result.response().channel);
1230   };
1231 
1232   fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
1233 
1234   // Set L2CAP channel parameters
1235   fidlbredr::L2capParameters l2cap_params;
1236   fidlbredr::ConnectParameters conn_params;
1237   l2cap_params.set_psm(kPsm);
1238   l2cap_params.set_parameters(fbt::ChannelParameters());
1239   conn_params.set_l2cap(std::move(l2cap_params));
1240 
1241   // Initiates pairing
1242   client()->Connect(peer_id, std::move(conn_params), std::move(result_cb));
1243   RunLoopUntilIdle();
1244 
1245   ASSERT_TRUE(channel.has_value());
1246   ASSERT_TRUE(channel->has_connection());
1247 
1248   ASSERT_TRUE(fake_chan.has_value());
1249   ASSERT_TRUE(fake_chan.value()->activated());
1250   FakeChannel::WeakPtr fake_chan_ptr = fake_chan.value();
1251   int send_count = 0;
1252   fake_chan_ptr->SetSendCallback([&send_count](auto buffer) { send_count++; },
1253                                  pw_dispatcher());
1254 
1255   fidl::InterfacePtr<fbt::Channel> conn = channel->mutable_connection()->Bind();
1256   int send_cb_count = 0;
1257   std::vector<fbt::Packet> packets{fbt::Packet{std::vector<uint8_t>{0x02}}};
1258   conn->Send(std::move(packets), [&](fbt::Channel_Send_Result result) {
1259     EXPECT_TRUE(result.is_response());
1260     send_cb_count++;
1261   });
1262   RunLoopUntilIdle();
1263   EXPECT_EQ(1, send_count);
1264   EXPECT_EQ(1, send_cb_count);
1265 }
1266 
TEST_F(ProfileServerTestConnectedPeer,ConnectFailsDueToChannelActivationFailure)1267 TEST_F(ProfileServerTestConnectedPeer,
1268        ConnectFailsDueToChannelActivationFailure) {
1269   server()->set_use_sockets(false);
1270 
1271   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1272       std::make_unique<bt::gap::FakePairingDelegate>(
1273           bt::sm::IOCapability::kDisplayYesNo);
1274   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1275   // Approve pairing requests.
1276   pairing_delegate->SetConfirmPairingCallback(
1277       [](bt::PeerId, auto confirm_cb) { confirm_cb(true); });
1278   pairing_delegate->SetCompletePairingCallback(
1279       [&](bt::PeerId, bt::sm::Result<> status) {
1280         EXPECT_EQ(fit::ok(), status);
1281       });
1282 
1283   bt::l2cap::ChannelParameters expected_params;
1284   l2cap()->ExpectOutboundL2capChannel(
1285       connection()->link().handle(), kPsm, 0x40, 0x41, expected_params);
1286 
1287   std::optional<FakeChannel::WeakPtr> fake_chan;
1288   l2cap()->set_channel_callback([&fake_chan](FakeChannel::WeakPtr chan) {
1289     chan->set_activate_fails(true);
1290     fake_chan = std::move(chan);
1291   });
1292 
1293   int connect_cb_count = 0;
1294   auto connect_cb = [&](fidlbredr::Profile_Connect_Result result) {
1295     EXPECT_TRUE(result.is_err());
1296     connect_cb_count++;
1297   };
1298 
1299   fuchsia::bluetooth::PeerId peer_id{peer()->identifier().value()};
1300 
1301   fidlbredr::L2capParameters l2cap_params;
1302   fidlbredr::ConnectParameters conn_params;
1303   l2cap_params.set_psm(kPsm);
1304   l2cap_params.set_parameters(fbt::ChannelParameters());
1305   conn_params.set_l2cap(std::move(l2cap_params));
1306 
1307   client()->Connect(peer_id, std::move(conn_params), std::move(connect_cb));
1308   RunLoopUntilIdle();
1309   EXPECT_EQ(connect_cb_count, 1);
1310   EXPECT_FALSE(fake_chan.value()->activated());
1311 }
1312 
1313 // Verifies that a socket channel relay is correctly set up such that bytes
1314 // written to the socket are sent to the channel.
TEST_F(ProfileServerTestConnectedPeer,ConnectionReceiverReturnsValidSocket)1315 TEST_F(ProfileServerTestConnectedPeer, ConnectionReceiverReturnsValidSocket) {
1316   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1317       std::make_unique<bt::gap::FakePairingDelegate>(
1318           bt::sm::IOCapability::kDisplayYesNo);
1319   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1320 
1321   fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
1322   FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
1323                                           dispatcher());
1324 
1325   std::optional<FakeChannel::WeakPtr> fake_chan;
1326   l2cap()->set_channel_callback(
1327       [&fake_chan](FakeChannel::WeakPtr chan) { fake_chan = std::move(chan); });
1328 
1329   std::vector<fidlbredr::ServiceDefinition> services;
1330   services.emplace_back(MakeFIDLServiceDefinition());
1331 
1332   fidlbredr::ProfileAdvertiseRequest adv_request;
1333   adv_request.set_services(std::move(services));
1334   adv_request.set_receiver(std::move(connect_receiver_handle));
1335   client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
1336   RunLoopUntilIdle();
1337 
1338   ASSERT_EQ(connect_receiver.connected_count(), 0u);
1339   EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
1340       connection()->link().handle(), kPsm, 0x40, 0x41));
1341   RunLoopUntilIdle();
1342 
1343   ASSERT_EQ(connect_receiver.connected_count(), 1u);
1344   ASSERT_EQ(connect_receiver.peer_id().value().value,
1345             peer()->identifier().value());
1346   ASSERT_TRUE(connect_receiver.channel().has_value());
1347   ASSERT_TRUE(connect_receiver.channel().value().has_socket());
1348   // Taking channel is safe because of the previous checks.
1349   fidlbredr::Channel channel = connect_receiver.take_channel();
1350 
1351   ASSERT_TRUE(fake_chan.has_value());
1352   FakeChannel::WeakPtr fake_chan_ptr = fake_chan.value();
1353   size_t send_count = 0;
1354   fake_chan_ptr->SetSendCallback([&send_count](auto buffer) { send_count++; },
1355                                  pw_dispatcher());
1356 
1357   const char write_data[2] = "a";
1358   size_t bytes_written = 0;
1359   int status = channel.socket().write(
1360       0, write_data, sizeof(write_data) - 1, &bytes_written);
1361   EXPECT_EQ(ZX_OK, status);
1362   EXPECT_EQ(1u, bytes_written);
1363   RunLoopUntilIdle();
1364   EXPECT_EQ(1u, send_count);
1365 }
1366 
1367 // Verifies that a BrEdrConnectionServer is correctly set up such that bytes
1368 // written to the Connection are sent to the channel.
TEST_F(ProfileServerTestConnectedPeer,ConnectionReceiverReturnsValidConnection)1369 TEST_F(ProfileServerTestConnectedPeer,
1370        ConnectionReceiverReturnsValidConnection) {
1371   server()->set_use_sockets(false);
1372 
1373   std::unique_ptr<bt::gap::FakePairingDelegate> pairing_delegate =
1374       std::make_unique<bt::gap::FakePairingDelegate>(
1375           bt::sm::IOCapability::kDisplayYesNo);
1376   adapter()->SetPairingDelegate(pairing_delegate->GetWeakPtr());
1377 
1378   fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
1379   FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
1380                                           dispatcher());
1381 
1382   std::optional<FakeChannel::WeakPtr> fake_chan;
1383   l2cap()->set_channel_callback(
1384       [&fake_chan](FakeChannel::WeakPtr chan) { fake_chan = std::move(chan); });
1385 
1386   std::vector<fidlbredr::ServiceDefinition> services;
1387   services.emplace_back(MakeFIDLServiceDefinition());
1388 
1389   fidlbredr::ProfileAdvertiseRequest adv_request;
1390   adv_request.set_services(std::move(services));
1391   adv_request.set_receiver(std::move(connect_receiver_handle));
1392   client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
1393   RunLoopUntilIdle();
1394 
1395   ASSERT_EQ(connect_receiver.connected_count(), 0u);
1396   EXPECT_TRUE(l2cap()->TriggerInboundL2capChannel(
1397       connection()->link().handle(), kPsm, 0x40, 0x41));
1398   RunLoopUntilIdle();
1399 
1400   ASSERT_EQ(connect_receiver.connected_count(), 1u);
1401   ASSERT_EQ(connect_receiver.peer_id().value().value,
1402             peer()->identifier().value());
1403   ASSERT_TRUE(connect_receiver.channel().has_value());
1404   ASSERT_TRUE(connect_receiver.channel().value().has_connection());
1405   // Taking channel is safe because of the previous checks.
1406   fidlbredr::Channel channel = connect_receiver.take_channel();
1407 
1408   ASSERT_TRUE(fake_chan.has_value());
1409   FakeChannel::WeakPtr fake_chan_ptr = fake_chan.value();
1410   int send_count = 0;
1411   fake_chan_ptr->SetSendCallback([&send_count](auto buffer) { send_count++; },
1412                                  pw_dispatcher());
1413 
1414   fidl::InterfacePtr<fbt::Channel> conn = channel.mutable_connection()->Bind();
1415   int send_cb_count = 0;
1416   std::vector<fbt::Packet> packets{fbt::Packet{std::vector<uint8_t>{0x02}}};
1417   conn->Send(std::move(packets), [&](fbt::Channel_Send_Result result) {
1418     EXPECT_TRUE(result.is_response());
1419     send_cb_count++;
1420   });
1421   RunLoopUntilIdle();
1422   EXPECT_EQ(1, send_count);
1423   EXPECT_EQ(1, send_cb_count);
1424 }
1425 
TEST_F(ProfileServerTest,ConnectScoWithInvalidParameters)1426 TEST_F(ProfileServerTest, ConnectScoWithInvalidParameters) {
1427   std::vector<fidlbredr::ScoConnectionParameters> bad_sco_params;
1428   bad_sco_params.emplace_back();
1429   fidlbredr::ProfileConnectScoRequest request;
1430   request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1431   request.set_initiator(true);
1432   request.set_params(std::move(bad_sco_params));
1433   fidlbredr::ScoConnectionHandle connection_handle;
1434   request.set_connection(connection_handle.NewRequest());
1435 
1436   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1437   std::optional<zx_status_t> sco_connection_status;
1438   sco_connection.set_error_handler(
1439       [&](zx_status_t status) { sco_connection_status = status; });
1440   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1441       connection_complete;
1442   sco_connection.events().OnConnectionComplete =
1443       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1444         connection_complete = std::move(request);
1445       };
1446 
1447   client()->ConnectSco(std::move(request));
1448   RunLoopUntilIdle();
1449   ASSERT_TRUE(connection_complete);
1450   ASSERT_TRUE(connection_complete->is_error());
1451   EXPECT_EQ(connection_complete->error(),
1452             fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
1453   EXPECT_FALSE(sco_connection.is_bound());
1454 }
1455 
TEST_F(ProfileServerTest,ConnectScoWithMissingPeerId)1456 TEST_F(ProfileServerTest, ConnectScoWithMissingPeerId) {
1457   fidlbredr::ScoConnectionParameters sco_params =
1458       CreateScoConnectionParameters();
1459   EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1460   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1461   sco_params_list.emplace_back(std::move(sco_params));
1462   fidlbredr::ProfileConnectScoRequest request;
1463   request.set_initiator(true);
1464   request.set_params(std::move(sco_params_list));
1465   fidlbredr::ScoConnectionHandle connection_handle;
1466   request.set_connection(connection_handle.NewRequest());
1467 
1468   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1469   std::optional<zx_status_t> sco_connection_status;
1470   sco_connection.set_error_handler(
1471       [&](zx_status_t status) { sco_connection_status = status; });
1472   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1473       connection_complete;
1474   sco_connection.events().OnConnectionComplete =
1475       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1476         connection_complete = std::move(request);
1477       };
1478 
1479   client()->ConnectSco(std::move(request));
1480   RunLoopUntilIdle();
1481   ASSERT_TRUE(connection_complete);
1482   ASSERT_TRUE(connection_complete->is_error());
1483   EXPECT_EQ(connection_complete->error(),
1484             fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
1485   EXPECT_FALSE(sco_connection.is_bound());
1486 }
1487 
TEST_F(ProfileServerTest,ConnectScoWithMissingConnectionDoesNotCrash)1488 TEST_F(ProfileServerTest, ConnectScoWithMissingConnectionDoesNotCrash) {
1489   fidlbredr::ScoConnectionParameters sco_params =
1490       CreateScoConnectionParameters();
1491   EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1492   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1493   sco_params_list.emplace_back(std::move(sco_params));
1494   fidlbredr::ProfileConnectScoRequest request;
1495   request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1496   request.set_initiator(true);
1497   request.set_params(std::move(sco_params_list));
1498   client()->ConnectSco(std::move(request));
1499   RunLoopUntilIdle();
1500 }
1501 
TEST_F(ProfileServerTest,ConnectScoWithEmptyParameters)1502 TEST_F(ProfileServerTest, ConnectScoWithEmptyParameters) {
1503   fidlbredr::ScoConnectionHandle connection_handle;
1504   fidlbredr::ProfileConnectScoRequest request;
1505   request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1506   request.set_initiator(true);
1507   request.set_params({});
1508   request.set_connection(connection_handle.NewRequest());
1509 
1510   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1511   std::optional<zx_status_t> sco_connection_status;
1512   sco_connection.set_error_handler(
1513       [&](zx_status_t status) { sco_connection_status = status; });
1514   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1515       connection_complete;
1516   sco_connection.events().OnConnectionComplete =
1517       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1518         connection_complete = std::move(request);
1519       };
1520 
1521   client()->ConnectSco(std::move(request));
1522   RunLoopUntilIdle();
1523   ASSERT_TRUE(connection_complete);
1524   ASSERT_TRUE(connection_complete->is_error());
1525   EXPECT_EQ(connection_complete->error(),
1526             fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
1527   EXPECT_FALSE(sco_connection.is_bound());
1528   ASSERT_TRUE(sco_connection_status);
1529   EXPECT_EQ(sco_connection_status.value(), ZX_ERR_PEER_CLOSED);
1530 }
1531 
TEST_F(ProfileServerTest,ConnectScoInitiatorWithTooManyParameters)1532 TEST_F(ProfileServerTest, ConnectScoInitiatorWithTooManyParameters) {
1533   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1534   sco_params_list.emplace_back(CreateScoConnectionParameters());
1535   sco_params_list.emplace_back(CreateScoConnectionParameters());
1536 
1537   fidlbredr::ScoConnectionHandle connection_handle;
1538   fidlbredr::ProfileConnectScoRequest request;
1539   request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1540   request.set_initiator(true);
1541   request.set_params(std::move(sco_params_list));
1542   request.set_connection(connection_handle.NewRequest());
1543 
1544   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1545   std::optional<zx_status_t> sco_connection_status;
1546   sco_connection.set_error_handler(
1547       [&](zx_status_t status) { sco_connection_status = status; });
1548   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1549       connection_complete;
1550   sco_connection.events().OnConnectionComplete =
1551       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1552         connection_complete = std::move(request);
1553       };
1554 
1555   client()->ConnectSco(std::move(request));
1556   RunLoopUntilIdle();
1557   ASSERT_TRUE(connection_complete);
1558   ASSERT_TRUE(connection_complete->is_error());
1559   EXPECT_EQ(connection_complete->error(),
1560             fidlbredr::ScoErrorCode::INVALID_ARGUMENTS);
1561   EXPECT_FALSE(sco_connection.is_bound());
1562   ASSERT_TRUE(sco_connection_status);
1563   EXPECT_EQ(sco_connection_status.value(), ZX_ERR_PEER_CLOSED);
1564 }
1565 
TEST_F(ProfileServerTest,ConnectScoWithUnconnectedPeerReturnsError)1566 TEST_F(ProfileServerTest, ConnectScoWithUnconnectedPeerReturnsError) {
1567   fidlbredr::ScoConnectionParameters sco_params =
1568       CreateScoConnectionParameters();
1569   EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1570   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1571   sco_params_list.emplace_back(std::move(sco_params));
1572 
1573   fidlbredr::ScoConnectionHandle connection_handle;
1574   fidlbredr::ProfileConnectScoRequest request;
1575   request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1576   request.set_initiator(true);
1577   request.set_params(std::move(sco_params_list));
1578   request.set_connection(connection_handle.NewRequest());
1579 
1580   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1581   std::optional<zx_status_t> sco_connection_status;
1582   sco_connection.set_error_handler(
1583       [&](zx_status_t status) { sco_connection_status = status; });
1584   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1585       connection_complete;
1586   sco_connection.events().OnConnectionComplete =
1587       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1588         connection_complete = std::move(request);
1589       };
1590 
1591   client()->ConnectSco(std::move(request));
1592   RunLoopUntilIdle();
1593   ASSERT_TRUE(connection_complete);
1594   ASSERT_TRUE(connection_complete->is_error());
1595   EXPECT_EQ(connection_complete->error(), fidlbredr::ScoErrorCode::FAILURE);
1596   EXPECT_FALSE(sco_connection.is_bound());
1597   ASSERT_TRUE(sco_connection_status);
1598   EXPECT_EQ(sco_connection_status.value(), ZX_ERR_PEER_CLOSED);
1599 }
1600 
TEST_F(ProfileServerTestConnectedPeer,ConnectScoInitiatorSuccess)1601 TEST_F(ProfileServerTestConnectedPeer, ConnectScoInitiatorSuccess) {
1602   fidlbredr::ScoConnectionParameters sco_params =
1603       CreateScoConnectionParameters(fidlbredr::HfpParameterSet::T1);
1604   EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1605   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1606   sco_params_list.emplace_back(std::move(sco_params));
1607 
1608   fidlbredr::ScoConnectionHandle connection_handle;
1609   fidlbredr::ProfileConnectScoRequest request;
1610   request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1611   request.set_initiator(true);
1612   request.set_params(std::move(sco_params_list));
1613   request.set_connection(connection_handle.NewRequest());
1614 
1615   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1616   std::optional<zx_status_t> sco_connection_status;
1617   sco_connection.set_error_handler(
1618       [&](zx_status_t status) { sco_connection_status = status; });
1619   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1620       connection_complete;
1621   sco_connection.events().OnConnectionComplete =
1622       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1623         connection_complete = std::move(request);
1624       };
1625 
1626   client()->ConnectSco(std::move(request));
1627   RunLoopUntilIdle();
1628   ASSERT_TRUE(connection_complete);
1629   ASSERT_TRUE(connection_complete->is_connected_params());
1630   EXPECT_TRUE(sco_connection.is_bound());
1631   ASSERT_TRUE(connection_complete->connected_params().has_parameter_set());
1632   EXPECT_EQ(connection_complete->connected_params().parameter_set(),
1633             fidlbredr::HfpParameterSet::T1);
1634   ASSERT_TRUE(connection_complete->connected_params().has_max_tx_data_size());
1635   EXPECT_EQ(connection_complete->connected_params().max_tx_data_size(),
1636             kSynchronousDataPacketLength);
1637 }
1638 
TEST_F(ProfileServerTestConnectedPeer,ConnectScoResponderSuccess)1639 TEST_F(ProfileServerTestConnectedPeer, ConnectScoResponderSuccess) {
1640   // Use 2 parameter sets to test that the profile server returns the second set
1641   // when a SCO connection request is received (T2 is ESCO only and D0 is SCO
1642   // only, so D0 will be used to accept the connection).
1643   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1644   sco_params_list.emplace_back(
1645       CreateScoConnectionParameters(fidlbredr::HfpParameterSet::T2));
1646   sco_params_list.emplace_back(
1647       CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0));
1648 
1649   fidlbredr::ScoConnectionHandle connection_handle;
1650   fidlbredr::ProfileConnectScoRequest request;
1651   request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1652   request.set_initiator(false);
1653   request.set_params(std::move(sco_params_list));
1654   request.set_connection(connection_handle.NewRequest());
1655 
1656   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1657   std::optional<zx_status_t> sco_connection_status;
1658   sco_connection.set_error_handler(
1659       [&](zx_status_t status) { sco_connection_status = status; });
1660   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1661       connection_complete;
1662   sco_connection.events().OnConnectionComplete =
1663       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1664         connection_complete = std::move(request);
1665       };
1666 
1667   client()->ConnectSco(std::move(request));
1668   RunLoopUntilIdle();
1669   // Receive a SCO connection request. The D0 parameters will be used to accept
1670   // the request.
1671   test_device()->SendConnectionRequest(peer()->address(),
1672                                        pw::bluetooth::emboss::LinkType::SCO);
1673   RunLoopUntilIdle();
1674   ASSERT_TRUE(connection_complete);
1675   ASSERT_TRUE(connection_complete->is_connected_params());
1676   EXPECT_TRUE(sco_connection.is_bound());
1677   ASSERT_TRUE(connection_complete->connected_params().has_parameter_set());
1678   EXPECT_EQ(connection_complete->connected_params().parameter_set(),
1679             fidlbredr::HfpParameterSet::D0);
1680 }
1681 
TEST_F(ProfileServerTestConnectedPeer,ScoConnectionReadBeforeConnectionComplete)1682 TEST_F(ProfileServerTestConnectedPeer,
1683        ScoConnectionReadBeforeConnectionComplete) {
1684   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1685   sco_params_list.emplace_back(
1686       CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0));
1687 
1688   fidlbredr::ScoConnectionHandle connection_handle;
1689   fidlbredr::ProfileConnectScoRequest request;
1690   request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1691   request.set_initiator(false);
1692   request.set_params(std::move(sco_params_list));
1693   request.set_connection(connection_handle.NewRequest());
1694 
1695   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1696   std::optional<zx_status_t> sco_connection_status;
1697   sco_connection.set_error_handler(
1698       [&](zx_status_t status) { sco_connection_status = status; });
1699   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1700       connection_complete;
1701   sco_connection.events().OnConnectionComplete =
1702       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1703         connection_complete = std::move(request);
1704       };
1705 
1706   client()->ConnectSco(std::move(request));
1707   RunLoopUntilIdle();
1708   ASSERT_FALSE(connection_complete);
1709 
1710   sco_connection->Read(
1711       [](fidlbredr::ScoConnection_Read_Result result) { FAIL(); });
1712   RunLoopUntilIdle();
1713   ASSERT_TRUE(sco_connection_status);
1714   EXPECT_EQ(sco_connection_status.value(), ZX_ERR_IO_REFUSED);
1715 }
1716 
TEST_F(ProfileServerTestConnectedPeer,ScoConnectionWriteBeforeConnectionComplete)1717 TEST_F(ProfileServerTestConnectedPeer,
1718        ScoConnectionWriteBeforeConnectionComplete) {
1719   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1720   sco_params_list.emplace_back(
1721       CreateScoConnectionParameters(fidlbredr::HfpParameterSet::D0));
1722 
1723   fidlbredr::ScoConnectionHandle connection_handle;
1724   fidlbredr::ProfileConnectScoRequest request;
1725   request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1726   request.set_initiator(false);
1727   request.set_params(std::move(sco_params_list));
1728   request.set_connection(connection_handle.NewRequest());
1729 
1730   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1731   std::optional<zx_status_t> sco_connection_status;
1732   sco_connection.set_error_handler(
1733       [&](zx_status_t status) { sco_connection_status = status; });
1734   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1735       connection_complete;
1736   sco_connection.events().OnConnectionComplete =
1737       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1738         connection_complete = std::move(request);
1739       };
1740 
1741   client()->ConnectSco(std::move(request));
1742   RunLoopUntilIdle();
1743   ASSERT_FALSE(connection_complete);
1744 
1745   ::fuchsia::bluetooth::bredr::ScoConnectionWriteRequest write;
1746   write.set_data({0x00});
1747   sco_connection->Write(
1748       std::move(write),
1749       [](::fuchsia::bluetooth::bredr::ScoConnection_Write_Result result) {
1750         FAIL();
1751       });
1752   RunLoopUntilIdle();
1753   ASSERT_TRUE(sco_connection_status);
1754   EXPECT_EQ(sco_connection_status.value(), ZX_ERR_IO_REFUSED);
1755 }
1756 
TEST_F(ProfileServerTestConnectedPeer,ConnectScoResponderUnconnectedPeerReturnsError)1757 TEST_F(ProfileServerTestConnectedPeer,
1758        ConnectScoResponderUnconnectedPeerReturnsError) {
1759   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1760   sco_params_list.emplace_back(CreateScoConnectionParameters());
1761 
1762   fidlbredr::ScoConnectionHandle connection_handle;
1763   fidlbredr::ProfileConnectScoRequest request;
1764   request.set_peer_id(fuchsia::bluetooth::PeerId{1});
1765   request.set_initiator(false);
1766   request.set_params(std::move(sco_params_list));
1767   request.set_connection(connection_handle.NewRequest());
1768 
1769   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1770   std::optional<zx_status_t> sco_connection_status;
1771   sco_connection.set_error_handler(
1772       [&](zx_status_t status) { sco_connection_status = status; });
1773   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1774       connection_complete;
1775   sco_connection.events().OnConnectionComplete =
1776       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1777         connection_complete = std::move(request);
1778       };
1779 
1780   client()->ConnectSco(std::move(request));
1781   RunLoopUntilIdle();
1782   ASSERT_TRUE(connection_complete);
1783   ASSERT_TRUE(connection_complete->is_error());
1784   EXPECT_EQ(connection_complete->error(), fidlbredr::ScoErrorCode::FAILURE);
1785   EXPECT_FALSE(sco_connection.is_bound());
1786   ASSERT_TRUE(sco_connection_status);
1787   EXPECT_EQ(sco_connection_status.value(), ZX_ERR_PEER_CLOSED);
1788 }
1789 
TEST_F(ProfileServerTestConnectedPeer,ConnectScoInitiatorAndCloseProtocol)1790 TEST_F(ProfileServerTestConnectedPeer, ConnectScoInitiatorAndCloseProtocol) {
1791   fidlbredr::ScoConnectionParameters sco_params =
1792       CreateScoConnectionParameters();
1793   EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1794   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1795   sco_params_list.emplace_back(std::move(sco_params));
1796 
1797   fidlbredr::ProfileConnectScoRequest request;
1798   request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1799   request.set_initiator(true);
1800   request.set_params(std::move(sco_params_list));
1801   fidlbredr::ScoConnectionHandle connection_handle;
1802   request.set_connection(connection_handle.NewRequest());
1803 
1804   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1805   std::optional<zx_status_t> sco_connection_status;
1806   sco_connection.set_error_handler(
1807       [&](zx_status_t status) { sco_connection_status = status; });
1808   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1809       connection_complete;
1810   sco_connection.events().OnConnectionComplete =
1811       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1812         connection_complete = std::move(request);
1813       };
1814 
1815   client()->ConnectSco(std::move(request));
1816   sco_connection.Unbind();
1817   RunLoopUntilIdle();
1818   ASSERT_FALSE(connection_complete);
1819 }
1820 
1821 // Verifies that the profile server gracefully ignores connection results after
1822 // the receiver has closed.
TEST_F(ProfileServerTestConnectedPeer,ConnectScoInitiatorAndCloseReceiverBeforeCompleteEvent)1823 TEST_F(ProfileServerTestConnectedPeer,
1824        ConnectScoInitiatorAndCloseReceiverBeforeCompleteEvent) {
1825   fidlbredr::ScoConnectionParameters sco_params =
1826       CreateScoConnectionParameters();
1827   EXPECT_TRUE(fidl_helpers::FidlToScoParameters(sco_params).is_ok());
1828   std::vector<fidlbredr::ScoConnectionParameters> sco_params_list;
1829   sco_params_list.emplace_back(std::move(sco_params));
1830 
1831   test_device()->SetDefaultCommandStatus(
1832       bt::hci_spec::kEnhancedSetupSynchronousConnection,
1833       pw::bluetooth::emboss::StatusCode::SUCCESS);
1834   fidlbredr::ProfileConnectScoRequest request;
1835   request.set_peer_id(fuchsia::bluetooth::PeerId{peer()->identifier().value()});
1836   request.set_initiator(true);
1837   request.set_params(std::move(sco_params_list));
1838   fidlbredr::ScoConnectionHandle connection_handle;
1839   request.set_connection(connection_handle.NewRequest());
1840 
1841   fidlbredr::ScoConnectionPtr sco_connection = connection_handle.Bind();
1842   std::optional<zx_status_t> sco_connection_status;
1843   sco_connection.set_error_handler(
1844       [&](zx_status_t status) { sco_connection_status = status; });
1845   std::optional<fidlbredr::ScoConnectionOnConnectionCompleteRequest>
1846       connection_complete;
1847   sco_connection.events().OnConnectionComplete =
1848       [&](fidlbredr::ScoConnectionOnConnectionCompleteRequest request) {
1849         connection_complete = std::move(request);
1850       };
1851 
1852   client()->ConnectSco(std::move(request));
1853   sco_connection.Unbind();
1854   RunLoopUntilIdle();
1855   ASSERT_FALSE(connection_complete);
1856   test_device()->SendCommandChannelPacket(
1857       bt::testing::SynchronousConnectionCompletePacket(
1858           0x00,
1859           peer()->address(),
1860           bt::hci_spec::LinkType::kSCO,
1861           pw::bluetooth::emboss::StatusCode::CONNECTION_TIMEOUT));
1862   RunLoopUntilIdle();
1863   ASSERT_FALSE(connection_complete);
1864 }
1865 
1866 class ProfileServerTestFakeAdapter
1867     : public bt::fidl::testing::FakeAdapterTestFixture {
1868  public:
1869   ProfileServerTestFakeAdapter() = default;
1870   ~ProfileServerTestFakeAdapter() override = default;
1871 
SetUp()1872   void SetUp() override {
1873     FakeAdapterTestFixture::SetUp();
1874 
1875     fidlbredr::ProfileHandle profile_handle;
1876     client_.Bind(std::move(profile_handle));
1877     server_ = std::make_unique<ProfileServer>(adapter()->AsWeakPtr(),
1878                                               client_.NewRequest(dispatcher()));
1879   }
1880 
TearDown()1881   void TearDown() override { FakeAdapterTestFixture::TearDown(); }
1882 
client()1883   fidlbredr::ProfilePtr& client() { return client_; }
1884 
1885  private:
1886   std::unique_ptr<ProfileServer> server_;
1887   fidlbredr::ProfilePtr client_;
1888   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ProfileServerTestFakeAdapter);
1889 };
1890 
TEST_F(ProfileServerTestFakeAdapter,ConnectChannelParametersContainsFlushTimeout)1891 TEST_F(ProfileServerTestFakeAdapter,
1892        ConnectChannelParametersContainsFlushTimeout) {
1893   const bt::PeerId kPeerId;
1894   const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
1895   const pw::chrono::SystemClock::duration kFlushTimeout(
1896       std::chrono::milliseconds(100));
1897 
1898   FakeChannel::WeakPtr last_channel;
1899   adapter()->fake_bredr()->set_l2cap_channel_callback(
1900       [&](FakeChannel::WeakPtr chan) { last_channel = std::move(chan); });
1901 
1902   // Set L2CAP channel parameters
1903   fbt::ChannelParameters chan_params;
1904   fidlbredr::L2capParameters l2cap_params;
1905   fidlbredr::ConnectParameters conn_params;
1906   chan_params.set_flush_timeout(kFlushTimeout.count());
1907   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
1908   l2cap_params.set_parameters(std::move(chan_params));
1909   conn_params.set_l2cap(std::move(l2cap_params));
1910 
1911   std::optional<fidlbredr::Channel> response_channel;
1912   client()->Connect(kFidlPeerId,
1913                     std::move(conn_params),
1914                     [&](fidlbredr::Profile_Connect_Result result) {
1915                       ASSERT_TRUE(result.is_response());
1916                       response_channel = std::move(result.response().channel);
1917                     });
1918   RunLoopUntilIdle();
1919   ASSERT_TRUE(last_channel.is_alive());
1920   EXPECT_EQ(last_channel->info().flush_timeout, std::optional(kFlushTimeout));
1921   ASSERT_TRUE(response_channel.has_value());
1922   ASSERT_TRUE(response_channel->has_flush_timeout());
1923   ASSERT_EQ(response_channel->flush_timeout(), kFlushTimeout.count());
1924 }
1925 
TEST_F(ProfileServerTestFakeAdapter,AdvertiseChannelParametersContainsFlushTimeout)1926 TEST_F(ProfileServerTestFakeAdapter,
1927        AdvertiseChannelParametersContainsFlushTimeout) {
1928   const pw::chrono::SystemClock::duration kFlushTimeout(
1929       std::chrono::milliseconds(100));
1930   const bt::hci_spec::ConnectionHandle kHandle(1);
1931 
1932   std::vector<fidlbredr::ServiceDefinition> services;
1933   services.emplace_back(MakeFIDLServiceDefinition());
1934   fbt::ChannelParameters chan_params;
1935   chan_params.set_flush_timeout(kFlushTimeout.count());
1936 
1937   fidlbredr::ConnectionReceiverHandle connect_receiver_handle;
1938   FakeConnectionReceiver connect_receiver(connect_receiver_handle.NewRequest(),
1939                                           dispatcher());
1940 
1941   fidlbredr::ProfileAdvertiseRequest adv_request;
1942   adv_request.set_services(std::move(services));
1943   adv_request.set_parameters(std::move(chan_params));
1944   adv_request.set_receiver(std::move(connect_receiver_handle));
1945   client()->Advertise(std::move(adv_request), NopAdvertiseCallback);
1946   RunLoopUntilIdle();
1947 
1948   ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 1u);
1949   auto service_iter = adapter()->fake_bredr()->registered_services().begin();
1950   EXPECT_EQ(service_iter->second.channel_params.flush_timeout,
1951             std::optional(kFlushTimeout));
1952 
1953   bt::l2cap::ChannelInfo chan_info =
1954       bt::l2cap::ChannelInfo::MakeBasicMode(bt::l2cap::kDefaultMTU,
1955                                             bt::l2cap::kDefaultMTU,
1956                                             bt::l2cap::kAVDTP,
1957                                             kFlushTimeout);
1958   auto channel =
1959       std::make_unique<FakeChannel>(bt::l2cap::kFirstDynamicChannelId,
1960                                     bt::l2cap::kFirstDynamicChannelId,
1961                                     kHandle,
1962                                     bt::LinkType::kACL,
1963                                     chan_info);
1964   service_iter->second.connect_callback(channel->GetWeakPtr(),
1965                                         MakeL2capProtocolListElement());
1966   RunLoopUntilIdle();
1967   ASSERT_TRUE(connect_receiver.channel().has_value());
1968   fidlbredr::Channel fidl_channel = connect_receiver.take_channel();
1969   ASSERT_TRUE(fidl_channel.has_flush_timeout());
1970   EXPECT_EQ(fidl_channel.flush_timeout(), kFlushTimeout.count());
1971 
1972   channel->Close();
1973   RunLoopUntilIdle();
1974 }
1975 
TEST_F(ProfileServerTestFakeAdapter,ClientClosesAdvertisement)1976 TEST_F(ProfileServerTestFakeAdapter, ClientClosesAdvertisement) {
1977   fidlbredr::ConnectionReceiverHandle receiver_handle;
1978   fidl::InterfaceRequest<fidlbredr::ConnectionReceiver> request =
1979       receiver_handle.NewRequest();
1980 
1981   std::vector<fidlbredr::ServiceDefinition> services;
1982   services.emplace_back(MakeFIDLServiceDefinition());
1983 
1984   size_t cb_count = 0;
1985   auto cb = [&](fidlbredr::Profile_Advertise_Result result) {
1986     cb_count++;
1987     EXPECT_TRUE(result.is_response());
1988   };
1989 
1990   fidlbredr::ProfileAdvertiseRequest adv_request;
1991   adv_request.set_services(std::move(services));
1992   adv_request.set_receiver(std::move(receiver_handle));
1993   client()->Advertise(std::move(adv_request), std::move(cb));
1994   RunLoopUntilIdle();
1995   ASSERT_EQ(cb_count, 1u);
1996   ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 1u);
1997 
1998   // Client closes Advertisement by dropping the `ConnectionReceiver`. This is
1999   // OK, and the profile server should handle this by unregistering the
2000   // advertisement.
2001   request = receiver_handle.NewRequest();
2002   RunLoopUntilIdle();
2003   ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 0u);
2004 }
2005 
TEST_F(ProfileServerTestFakeAdapter,AdvertiseWithMissingFields)2006 TEST_F(ProfileServerTestFakeAdapter, AdvertiseWithMissingFields) {
2007   size_t cb_ok_count = 0;
2008   auto adv_ok_cb = [&](fidlbredr::Profile_Advertise_Result result) {
2009     cb_ok_count++;
2010     EXPECT_TRUE(result.is_response());
2011   };
2012   size_t cb_err_count = 0;
2013   auto adv_err_cb = [&](fidlbredr::Profile_Advertise_Result result) {
2014     cb_err_count++;
2015     ASSERT_TRUE(result.is_err());
2016     EXPECT_EQ(result.err(), fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
2017   };
2018 
2019   fidlbredr::ProfileAdvertiseRequest adv_request_missing_receiver;
2020   std::vector<fidlbredr::ServiceDefinition> services1;
2021   services1.emplace_back(MakeFIDLServiceDefinition());
2022   adv_request_missing_receiver.set_services(std::move(services1));
2023   adv_request_missing_receiver.set_parameters(
2024       ::fuchsia::bluetooth::ChannelParameters());
2025   client()->Advertise(std::move(adv_request_missing_receiver), adv_err_cb);
2026   RunLoopUntilIdle();
2027   ASSERT_EQ(cb_err_count, 1u);
2028   ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 0u);
2029 
2030   fidlbredr::ConnectionReceiverHandle connect_receiver_handle1;
2031   FakeConnectionReceiver connect_receiver1(
2032       connect_receiver_handle1.NewRequest(), dispatcher());
2033 
2034   fidlbredr::ProfileAdvertiseRequest adv_request_missing_services;
2035   adv_request_missing_services.set_receiver(
2036       std::move(connect_receiver_handle1));
2037   adv_request_missing_services.set_parameters(
2038       ::fuchsia::bluetooth::ChannelParameters());
2039   client()->Advertise(std::move(adv_request_missing_services), adv_err_cb);
2040   RunLoopUntilIdle();
2041   ASSERT_EQ(cb_err_count, 2u);
2042   ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 0u);
2043 
2044   // Missing parameters is allowed.
2045   fidlbredr::ProfileAdvertiseRequest adv_request_missing_parameters;
2046   std::vector<fidlbredr::ServiceDefinition> services2;
2047   services2.emplace_back(MakeFIDLServiceDefinition());
2048   adv_request_missing_parameters.set_services(std::move(services2));
2049   fidlbredr::ConnectionReceiverHandle connect_receiver_handle2;
2050   FakeConnectionReceiver connect_receiver2(
2051       connect_receiver_handle2.NewRequest(), dispatcher());
2052   adv_request_missing_parameters.set_receiver(
2053       std::move(connect_receiver_handle2));
2054   client()->Advertise(std::move(adv_request_missing_parameters), adv_ok_cb);
2055   RunLoopUntilIdle();
2056   ASSERT_EQ(cb_ok_count, 1u);
2057   ASSERT_EQ(adapter()->fake_bredr()->registered_services().size(), 1u);
2058 }
2059 
TEST_F(ProfileServerTestFakeAdapter,L2capParametersExtRequestParametersSucceeds)2060 TEST_F(ProfileServerTestFakeAdapter,
2061        L2capParametersExtRequestParametersSucceeds) {
2062   const bt::PeerId kPeerId;
2063   const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2064   const zx::duration kFlushTimeout(zx::msec(100));
2065   const uint16_t kMaxRxSduSize(200);
2066 
2067   FakeChannel::WeakPtr last_channel;
2068   adapter()->fake_bredr()->set_l2cap_channel_callback(
2069       [&](FakeChannel::WeakPtr chan) { last_channel = chan; });
2070 
2071   // Set L2CAP channel parameters
2072   fbt::ChannelParameters chan_params;
2073   fidlbredr::L2capParameters l2cap_params;
2074   fidlbredr::ConnectParameters conn_params;
2075   chan_params.set_channel_mode(fbt::ChannelMode::BASIC);
2076   chan_params.set_max_rx_packet_size(kMaxRxSduSize);
2077   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2078   l2cap_params.set_parameters(std::move(chan_params));
2079   conn_params.set_l2cap(std::move(l2cap_params));
2080 
2081   std::optional<fidlbredr::Channel> response_channel;
2082   client()->Connect(kFidlPeerId,
2083                     std::move(conn_params),
2084                     [&](fidlbredr::Profile_Connect_Result result) {
2085                       ASSERT_TRUE(result.is_response());
2086                       response_channel = std::move(result.response().channel);
2087                     });
2088   RunLoopUntilIdle();
2089   ASSERT_TRUE(last_channel.is_alive());
2090   EXPECT_FALSE(last_channel->info().flush_timeout.has_value());
2091   ASSERT_TRUE(response_channel.has_value());
2092   ASSERT_FALSE(response_channel->has_flush_timeout());
2093   ASSERT_TRUE(response_channel->has_ext_l2cap());
2094 
2095   fbt::ChannelParameters request_chan_params;
2096   request_chan_params.set_flush_timeout(kFlushTimeout.get());
2097 
2098   std::optional<fbt::ChannelParameters> result_chan_params;
2099   fidlbredr::L2capParametersExtPtr l2cap_client =
2100       response_channel->mutable_ext_l2cap()->Bind();
2101   l2cap_client->RequestParameters(
2102       std::move(request_chan_params),
2103       [&](fidlbredr::L2capParametersExt_RequestParameters_Result new_params) {
2104         result_chan_params = new_params.response().ResultValue_();
2105       });
2106   RunLoopUntilIdle();
2107   ASSERT_TRUE(result_chan_params.has_value());
2108   ASSERT_TRUE(result_chan_params->has_channel_mode());
2109   ASSERT_TRUE(result_chan_params->has_max_rx_packet_size());
2110   // TODO(fxbug.dev/42152567): set current security requirements in returned
2111   // channel parameters
2112   ASSERT_FALSE(result_chan_params->has_security_requirements());
2113   ASSERT_TRUE(result_chan_params->has_flush_timeout());
2114   EXPECT_EQ(result_chan_params->channel_mode(), fbt::ChannelMode::BASIC);
2115   EXPECT_EQ(result_chan_params->max_rx_packet_size(), kMaxRxSduSize);
2116   EXPECT_EQ(result_chan_params->flush_timeout(), kFlushTimeout.get());
2117   l2cap_client.Unbind();
2118   RunLoopUntilIdle();
2119 }
2120 
TEST_F(ProfileServerTestFakeAdapter,L2capParametersExtRequestParametersFails)2121 TEST_F(ProfileServerTestFakeAdapter, L2capParametersExtRequestParametersFails) {
2122   const bt::PeerId kPeerId;
2123   const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2124   const zx::duration kFlushTimeout(zx::msec(100));
2125 
2126   FakeChannel::WeakPtr last_channel;
2127   adapter()->fake_bredr()->set_l2cap_channel_callback(
2128       [&](FakeChannel::WeakPtr chan) { last_channel = chan; });
2129 
2130   // Set L2CAP channel parameters
2131   fidlbredr::L2capParameters l2cap_params;
2132   fidlbredr::ConnectParameters conn_params;
2133   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2134   conn_params.set_l2cap(std::move(l2cap_params));
2135 
2136   std::optional<fidlbredr::Channel> response_channel;
2137   client()->Connect(kFidlPeerId,
2138                     std::move(conn_params),
2139                     [&](fidlbredr::Profile_Connect_Result result) {
2140                       ASSERT_TRUE(result.is_response());
2141                       response_channel = std::move(result.response().channel);
2142                     });
2143   RunLoopUntilIdle();
2144   ASSERT_TRUE(last_channel.is_alive());
2145   EXPECT_FALSE(last_channel->info().flush_timeout.has_value());
2146   ASSERT_TRUE(response_channel.has_value());
2147   ASSERT_FALSE(response_channel->has_flush_timeout());
2148   ASSERT_TRUE(response_channel->has_ext_l2cap());
2149 
2150   last_channel->set_flush_timeout_succeeds(false);
2151 
2152   fbt::ChannelParameters request_chan_params;
2153   request_chan_params.set_flush_timeout(kFlushTimeout.get());
2154   std::optional<fbt::ChannelParameters> result_chan_params;
2155   fidlbredr::L2capParametersExtPtr l2cap_client =
2156       response_channel->mutable_ext_l2cap()->Bind();
2157   l2cap_client->RequestParameters(
2158       std::move(request_chan_params),
2159       [&](fidlbredr::L2capParametersExt_RequestParameters_Result new_params) {
2160         result_chan_params = new_params.response().ResultValue_();
2161       });
2162   RunLoopUntilIdle();
2163   ASSERT_TRUE(result_chan_params.has_value());
2164   EXPECT_FALSE(result_chan_params->has_flush_timeout());
2165   l2cap_client.Unbind();
2166   RunLoopUntilIdle();
2167 }
2168 
TEST_F(ProfileServerTestFakeAdapter,L2capParametersExtRequestParametersClosedOnChannelClosed)2169 TEST_F(ProfileServerTestFakeAdapter,
2170        L2capParametersExtRequestParametersClosedOnChannelClosed) {
2171   const bt::PeerId kPeerId;
2172   const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2173 
2174   FakeChannel::WeakPtr last_channel;
2175   adapter()->fake_bredr()->set_l2cap_channel_callback(
2176       [&](FakeChannel::WeakPtr chan) { last_channel = chan; });
2177 
2178   // Set L2CAP channel parameters
2179   fidlbredr::L2capParameters l2cap_params;
2180   fidlbredr::ConnectParameters conn_params;
2181   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2182   conn_params.set_l2cap(std::move(l2cap_params));
2183 
2184   std::optional<fidlbredr::Channel> response_channel;
2185   client()->Connect(kFidlPeerId,
2186                     std::move(conn_params),
2187                     [&](fidlbredr::Profile_Connect_Result result) {
2188                       ASSERT_TRUE(result.is_response());
2189                       response_channel = std::move(result.response().channel);
2190                     });
2191   RunLoopUntilIdle();
2192   ASSERT_TRUE(last_channel.is_alive());
2193   ASSERT_TRUE(response_channel.has_value());
2194 
2195   fidlbredr::L2capParametersExtPtr l2cap_client =
2196       response_channel->mutable_ext_l2cap()->Bind();
2197   bool l2cap_client_closed = false;
2198   l2cap_client.set_error_handler(
2199       [&](zx_status_t /*status*/) { l2cap_client_closed = true; });
2200 
2201   // Closing the channel should close l2cap_client (after running the loop).
2202   last_channel->Close();
2203   // Destroy the channel (like the real LogicalLink would) to verify that
2204   // ProfileServer doesn't try to use channel pointers.
2205   EXPECT_TRUE(adapter()->fake_bredr()->DestroyChannel(last_channel->id()));
2206 
2207   // Any request for the closed channel should be ignored.
2208   fbt::ChannelParameters request_chan_params;
2209   std::optional<fbt::ChannelParameters> result_chan_params;
2210   l2cap_client->RequestParameters(
2211       std::move(request_chan_params),
2212       [&](fidlbredr::L2capParametersExt_RequestParameters_Result new_params) {
2213         result_chan_params = new_params.response().ResultValue_();
2214       });
2215   RunLoopUntilIdle();
2216   EXPECT_TRUE(l2cap_client_closed);
2217   EXPECT_FALSE(result_chan_params.has_value());
2218   l2cap_client.Unbind();
2219   RunLoopUntilIdle();
2220 }
2221 
TEST_F(ProfileServerTestFakeAdapter,AudioDirectionExtRequestParametersClosedOnChannelClosed)2222 TEST_F(ProfileServerTestFakeAdapter,
2223        AudioDirectionExtRequestParametersClosedOnChannelClosed) {
2224   const bt::PeerId kPeerId;
2225   const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2226 
2227   FakeChannel::WeakPtr last_channel;
2228   adapter()->fake_bredr()->set_l2cap_channel_callback(
2229       [&](FakeChannel::WeakPtr chan) { last_channel = chan; });
2230 
2231   // Set L2CAP channel parameters
2232   fidlbredr::L2capParameters l2cap_params;
2233   fidlbredr::ConnectParameters conn_params;
2234   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2235   conn_params.set_l2cap(std::move(l2cap_params));
2236 
2237   std::optional<fidlbredr::Channel> response_channel;
2238   client()->Connect(kFidlPeerId,
2239                     std::move(conn_params),
2240                     [&](fidlbredr::Profile_Connect_Result result) {
2241                       ASSERT_TRUE(result.is_response());
2242                       response_channel = std::move(result.response().channel);
2243                     });
2244   RunLoopUntilIdle();
2245   ASSERT_TRUE(last_channel.is_alive());
2246   ASSERT_TRUE(response_channel.has_value());
2247 
2248   fidlbredr::AudioDirectionExtPtr audio_client =
2249       response_channel->mutable_ext_direction()->Bind();
2250   bool audio_client_closed = false;
2251   audio_client.set_error_handler(
2252       [&](zx_status_t /*status*/) { audio_client_closed = true; });
2253 
2254   // Closing the channel should close audio_client (after running the loop).
2255   last_channel->Close();
2256   // Destroy the channel (like the real LogicalLink would) to verify that
2257   // ProfileServer doesn't try to use channel pointers.
2258   EXPECT_TRUE(adapter()->fake_bredr()->DestroyChannel(last_channel->id()));
2259 
2260   // Any request for the closed channel should be ignored.
2261   size_t priority_cb_count = 0;
2262   audio_client->SetPriority(
2263       fidlbredr::A2dpDirectionPriority::NORMAL,
2264       [&](fidlbredr::AudioDirectionExt_SetPriority_Result result) {
2265         priority_cb_count++;
2266       });
2267 
2268   RunLoopUntilIdle();
2269   EXPECT_TRUE(audio_client_closed);
2270   EXPECT_EQ(priority_cb_count, 0u);
2271   audio_client.Unbind();
2272   RunLoopUntilIdle();
2273 }
2274 
TEST_F(ProfileServerTestFakeAdapter,AudioOffloadExtRequestParametersClosedOnChannelClosed)2275 TEST_F(ProfileServerTestFakeAdapter,
2276        AudioOffloadExtRequestParametersClosedOnChannelClosed) {
2277   const bt::PeerId kPeerId;
2278   const fuchsia::bluetooth::PeerId kFidlPeerId{kPeerId.value()};
2279 
2280   FakeChannel::WeakPtr last_channel;
2281   adapter()->fake_bredr()->set_l2cap_channel_callback(
2282       [&](FakeChannel::WeakPtr chan) { last_channel = std::move(chan); });
2283 
2284   // Support Android Vendor Extensions to enable Audio Offload Extension
2285   adapter()->mutable_state().controller_features |=
2286       FeaturesBits::kAndroidVendorExtensions;
2287   bt::StaticPacket<
2288       android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2289       params;
2290   params.SetToZeros();
2291   params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2292   params.view().version_supported().major_number().Write(0);
2293   params.view().version_supported().minor_number().Write(98);
2294   params.view().a2dp_source_offload_capability_mask().aac().Write(true);
2295   adapter()->mutable_state().android_vendor_capabilities =
2296       bt::gap::AndroidVendorCapabilities::New(params.view());
2297 
2298   // Set L2CAP channel parameters
2299   fidlbredr::L2capParameters l2cap_params;
2300   fidlbredr::ConnectParameters conn_params;
2301   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2302   conn_params.set_l2cap(std::move(l2cap_params));
2303 
2304   std::optional<fidlbredr::Channel> response_channel;
2305   client()->Connect(kFidlPeerId,
2306                     std::move(conn_params),
2307                     [&](fidlbredr::Profile_Connect_Result result) {
2308                       ASSERT_TRUE(result.is_response());
2309                       response_channel = std::move(result.response().channel);
2310                     });
2311   RunLoopUntilIdle();
2312   ASSERT_TRUE(last_channel.is_alive());
2313   ASSERT_TRUE(response_channel.has_value());
2314   ASSERT_TRUE(response_channel->has_ext_audio_offload());
2315 
2316   fidlbredr::AudioOffloadExtPtr audio_client =
2317       response_channel->mutable_ext_audio_offload()->Bind();
2318   bool audio_client_closed = false;
2319   audio_client.set_error_handler(
2320       [&](zx_status_t /*status*/) { audio_client_closed = true; });
2321 
2322   // Closing the channel should close |audio_client| (after running the loop).
2323   last_channel->Close();
2324   // Destroy the channel (like the real LogicalLink would) to verify that
2325   // ProfileServer doesn't try to use channel pointers.
2326   EXPECT_TRUE(adapter()->fake_bredr()->DestroyChannel(last_channel->id()));
2327 
2328   // Any request for the closed channel should be ignored.
2329   std::optional<fidlbredr::AudioOffloadExt_GetSupportedFeatures_Response>
2330       result_features;
2331   audio_client->GetSupportedFeatures(
2332       [&result_features](
2333           fidlbredr::AudioOffloadExt_GetSupportedFeatures_Result features) {
2334         result_features = std::move(features.response());
2335       });
2336 
2337   RunLoopUntilIdle();
2338   EXPECT_TRUE(audio_client_closed);
2339   EXPECT_FALSE(result_features.has_value());
2340   audio_client.Unbind();
2341   RunLoopUntilIdle();
2342 }
2343 
2344 class ProfileServerInvalidSamplingFrequencyTest
2345     : public ProfileServerTestFakeAdapter,
2346       public ::testing::WithParamInterface<fidlbredr::AudioSamplingFrequency> {
2347 };
2348 
2349 const std::vector<fidlbredr::AudioSamplingFrequency>
2350     kInvalidSamplingFrequencies = {
2351         fidlbredr::AudioSamplingFrequency::HZ_88200,
2352         fidlbredr::AudioSamplingFrequency::HZ_96000,
2353 };
2354 
2355 INSTANTIATE_TEST_SUITE_P(ProfileServerTestFakeAdapter,
2356                          ProfileServerInvalidSamplingFrequencyTest,
2357                          ::testing::ValuesIn(kInvalidSamplingFrequencies));
2358 
TEST_P(ProfileServerInvalidSamplingFrequencyTest,SbcInvalidSamplingFrequency)2359 TEST_P(ProfileServerInvalidSamplingFrequencyTest, SbcInvalidSamplingFrequency) {
2360   // enable a2dp offloading
2361   adapter()->mutable_state().controller_features |=
2362       FeaturesBits::kAndroidVendorExtensions;
2363 
2364   // enable offloaded sbc encoding
2365   bt::StaticPacket<
2366       android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2367       params;
2368   params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2369   params.view().version_supported().major_number().Write(0);
2370   params.view().version_supported().minor_number().Write(98);
2371   params.view().a2dp_source_offload_capability_mask().sbc().Write(true);
2372   adapter()->mutable_state().android_vendor_capabilities =
2373       bt::gap::AndroidVendorCapabilities::New(params.view());
2374 
2375   // set up a fake channel and connection
2376   FakeChannel::WeakPtr fake_channel;
2377   adapter()->fake_bredr()->set_l2cap_channel_callback(
2378       [&](auto chan) { fake_channel = std::move(chan); });
2379 
2380   const bt::PeerId peer_id(1);
2381   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2382 
2383   fidlbredr::L2capParameters l2cap_params;
2384   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2385 
2386   fbt::ChannelParameters chan_params;
2387   l2cap_params.set_parameters(std::move(chan_params));
2388 
2389   fidlbredr::ConnectParameters conn_params;
2390   conn_params.set_l2cap(std::move(l2cap_params));
2391 
2392   std::optional<fidlbredr::Channel> response_channel;
2393   client()->Connect(
2394       fidl_peer_id,
2395       std::move(conn_params),
2396       [&response_channel](fidlbredr::Profile_Connect_Result result) {
2397         ASSERT_TRUE(result.is_response());
2398         response_channel = std::move(result.response().channel);
2399       });
2400   RunLoopUntilIdle();
2401   ASSERT_TRUE(response_channel.has_value());
2402   ASSERT_TRUE(response_channel->has_ext_audio_offload());
2403 
2404   // set up the bad configuration
2405   std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2406       fidlbredr::AudioOffloadFeatures::New();
2407   std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2408       fidlbredr::AudioSbcSupport::New();
2409   codec->set_sbc(std::move(*codec_value));
2410 
2411   std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2412       std::make_unique<fidlbredr::AudioEncoderSettings>();
2413   std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2414       fuchsia::media::SbcEncoderSettings::New();
2415   encoder_settings->set_sbc(*encoder_settings_value);
2416 
2417   std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2418       std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2419   config->set_codec(std::move(*codec));
2420   config->set_max_latency(10);
2421   config->set_scms_t_enable(true);
2422   config->set_sampling_frequency(GetParam());
2423   config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2424   config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2425   config->set_encoded_bit_rate(10);
2426   config->set_encoder_settings(std::move(*encoder_settings));
2427 
2428   // attempt to start the audio offload
2429   fidl::InterfaceHandle<fidlbredr::AudioOffloadController> controller_handle;
2430   fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2431       controller_handle.NewRequest();
2432   fidl::InterfacePtr<fidlbredr::AudioOffloadExt> audio_offload_ext_client =
2433       response_channel->mutable_ext_audio_offload()->Bind();
2434   audio_offload_ext_client->StartAudioOffload(std::move(*config),
2435                                               std::move(controller_request));
2436 
2437   fidl::InterfacePtr<fidlbredr::AudioOffloadController>
2438       audio_offload_controller_client;
2439   audio_offload_controller_client.Bind(std::move(controller_handle));
2440 
2441   std::optional<zx_status_t> audio_offload_controller_epitaph;
2442   audio_offload_controller_client.set_error_handler(
2443       [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2444 
2445   RunLoopUntilIdle();
2446 
2447   // Verify that |audio_offload_controller_client| was closed with
2448   // |ZX_ERR_INTERNAL| epitaph
2449   ASSERT_TRUE(audio_offload_controller_epitaph.has_value());
2450   EXPECT_EQ(audio_offload_controller_epitaph.value(), ZX_ERR_NOT_SUPPORTED);
2451 }
2452 
2453 class AndroidSupportedFeaturesTest
2454     : public ProfileServerTestFakeAdapter,
2455       public ::testing::WithParamInterface<
2456           std::pair<bool /*android_vendor_support*/,
2457                     uint32_t /*android_vendor_capabilities*/>> {};
2458 
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtGetSupportedFeatures)2459 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadExtGetSupportedFeatures) {
2460   const bool android_vendor_ext_support = GetParam().first;
2461   const uint32_t a2dp_offload_capabilities = GetParam().second;
2462 
2463   if (android_vendor_ext_support) {
2464     adapter()->mutable_state().controller_features |=
2465         FeaturesBits::kAndroidVendorExtensions;
2466 
2467     bt::StaticPacket<
2468         android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2469         params;
2470     params.SetToZeros();
2471     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2472     params.view().version_supported().major_number().Write(0);
2473     params.view().version_supported().minor_number().Write(98);
2474     params.view()
2475         .a2dp_source_offload_capability_mask()
2476         .BackingStorage()
2477         .UncheckedWriteUInt(a2dp_offload_capabilities);
2478     adapter()->mutable_state().android_vendor_capabilities =
2479         bt::gap::AndroidVendorCapabilities::New(params.view());
2480   }
2481 
2482   const bt::PeerId peer_id(1);
2483   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2484 
2485   // Set L2CAP channel parameters
2486   fidlbredr::L2capParameters l2cap_params;
2487   fidlbredr::ConnectParameters conn_params;
2488   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2489   l2cap_params.set_parameters(fbt::ChannelParameters());
2490   conn_params.set_l2cap(std::move(l2cap_params));
2491 
2492   std::optional<fidlbredr::Channel> response_channel;
2493   client()->Connect(
2494       fidl_peer_id,
2495       std::move(conn_params),
2496       [&response_channel](fidlbredr::Profile_Connect_Result result) {
2497         ASSERT_TRUE(result.is_response());
2498         response_channel = std::move(result.response().channel);
2499       });
2500   RunLoopUntilIdle();
2501   ASSERT_TRUE(response_channel.has_value());
2502   if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2503     EXPECT_FALSE(response_channel->has_ext_audio_offload());
2504     return;
2505   }
2506   ASSERT_TRUE(response_channel->has_ext_audio_offload());
2507 
2508   std::optional<fidlbredr::AudioOffloadExt_GetSupportedFeatures_Response>
2509       result_features;
2510   fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2511       response_channel->mutable_ext_audio_offload()->Bind();
2512   audio_offload_ext_client->GetSupportedFeatures(
2513       [&result_features](
2514           fidlbredr::AudioOffloadExt_GetSupportedFeatures_Result features) {
2515         result_features = std::move(features.response());
2516       });
2517   RunLoopUntilIdle();
2518 
2519   EXPECT_TRUE(result_features->has_audio_offload_features());
2520   const std::vector<fidlbredr::AudioOffloadFeatures>& audio_offload_features =
2521       result_features->audio_offload_features();
2522   const uint32_t audio_offload_features_size =
2523       std::bitset<std::numeric_limits<uint32_t>::digits>(
2524           a2dp_offload_capabilities)
2525           .count();
2526   EXPECT_EQ(audio_offload_features_size, audio_offload_features.size());
2527 
2528   uint32_t capabilities = 0;
2529   const uint32_t sbc_capability =
2530       static_cast<uint32_t>(android_emb::A2dpCodecType::SBC);
2531   const uint32_t aac_capability =
2532       static_cast<uint32_t>(android_emb::A2dpCodecType::AAC);
2533   for (const fidlbredr::AudioOffloadFeatures& feature :
2534        audio_offload_features) {
2535     if (feature.is_sbc()) {
2536       capabilities |= sbc_capability;
2537     }
2538     if (feature.is_aac()) {
2539       capabilities |= aac_capability;
2540     }
2541   }
2542   EXPECT_EQ(capabilities, a2dp_offload_capabilities);
2543 }
2544 
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtStartAudioOffloadSuccess)2545 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadExtStartAudioOffloadSuccess) {
2546   const bool android_vendor_ext_support = GetParam().first;
2547   const uint32_t a2dp_offload_capabilities = GetParam().second;
2548 
2549   if (android_vendor_ext_support) {
2550     adapter()->mutable_state().controller_features |=
2551         FeaturesBits::kAndroidVendorExtensions;
2552 
2553     bt::StaticPacket<
2554         android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2555         params;
2556     params.SetToZeros();
2557     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2558     params.view().version_supported().major_number().Write(0);
2559     params.view().version_supported().minor_number().Write(98);
2560     params.view()
2561         .a2dp_source_offload_capability_mask()
2562         .BackingStorage()
2563         .UncheckedWriteUInt(a2dp_offload_capabilities);
2564     adapter()->mutable_state().android_vendor_capabilities =
2565         bt::gap::AndroidVendorCapabilities::New(params.view());
2566   }
2567 
2568   const bt::PeerId peer_id(1);
2569   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2570 
2571   // Set L2CAP channel parameters
2572   fidlbredr::L2capParameters l2cap_params;
2573   fidlbredr::ConnectParameters conn_params;
2574   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2575   l2cap_params.set_parameters(fbt::ChannelParameters());
2576   conn_params.set_l2cap(std::move(l2cap_params));
2577 
2578   std::optional<fidlbredr::Channel> response_channel;
2579   client()->Connect(
2580       fidl_peer_id,
2581       std::move(conn_params),
2582       [&response_channel](fidlbredr::Profile_Connect_Result result) {
2583         ASSERT_TRUE(result.is_response());
2584         response_channel = std::move(result.response().channel);
2585       });
2586   RunLoopUntilIdle();
2587   ASSERT_TRUE(response_channel.has_value());
2588   if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2589     EXPECT_FALSE(response_channel->has_ext_audio_offload());
2590     return;
2591   }
2592   ASSERT_TRUE(response_channel->has_ext_audio_offload());
2593 
2594   // Set Audio Offload Configuration Values
2595   std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2596       fidlbredr::AudioOffloadFeatures::New();
2597   std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2598       fidlbredr::AudioSbcSupport::New();
2599   codec->set_sbc(std::move(*codec_value));
2600 
2601   std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2602       std::make_unique<fidlbredr::AudioEncoderSettings>();
2603   std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2604       fuchsia::media::SbcEncoderSettings::New();
2605   encoder_settings->set_sbc(*encoder_settings_value);
2606 
2607   std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2608       std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2609   config->set_codec(std::move(*codec));
2610   config->set_max_latency(10);
2611   config->set_scms_t_enable(true);
2612   config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
2613   config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2614   config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2615   config->set_encoded_bit_rate(10);
2616   config->set_encoder_settings(std::move(*encoder_settings));
2617 
2618   fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2619       response_channel->mutable_ext_audio_offload()->Bind();
2620   fidlbredr::AudioOffloadControllerHandle controller_handle;
2621   fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2622       controller_handle.NewRequest();
2623   audio_offload_ext_client->StartAudioOffload(std::move(*config),
2624                                               std::move(controller_request));
2625 
2626   fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
2627   audio_offload_controller_client.Bind(std::move(controller_handle));
2628 
2629   std::optional<zx_status_t> audio_offload_controller_epitaph;
2630   audio_offload_controller_client.set_error_handler(
2631       [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2632 
2633   size_t on_started_count = 0;
2634   audio_offload_controller_client.events().OnStarted = [&]() {
2635     on_started_count++;
2636   };
2637 
2638   RunLoopUntilIdle();
2639 
2640   // Verify that OnStarted event was sent successfully
2641   EXPECT_EQ(on_started_count, 1u);
2642 
2643   // Verify that |audio_offload_controller_client| was not closed with an
2644   // epitaph
2645   ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
2646 }
2647 
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtStartAudioOffloadFail)2648 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadExtStartAudioOffloadFail) {
2649   FakeChannel::WeakPtr fake_channel;
2650   adapter()->fake_bredr()->set_l2cap_channel_callback(
2651       [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
2652 
2653   const bool android_vendor_ext_support = GetParam().first;
2654   const uint32_t a2dp_offload_capabilities = GetParam().second;
2655 
2656   if (android_vendor_ext_support) {
2657     adapter()->mutable_state().controller_features |=
2658         FeaturesBits::kAndroidVendorExtensions;
2659 
2660     bt::StaticPacket<
2661         android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2662         params;
2663     params.SetToZeros();
2664     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2665     params.view().version_supported().major_number().Write(0);
2666     params.view().version_supported().minor_number().Write(98);
2667     params.view()
2668         .a2dp_source_offload_capability_mask()
2669         .BackingStorage()
2670         .UncheckedWriteUInt(a2dp_offload_capabilities);
2671     adapter()->mutable_state().android_vendor_capabilities =
2672         bt::gap::AndroidVendorCapabilities::New(params.view());
2673   }
2674 
2675   const bt::PeerId peer_id(1);
2676   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2677 
2678   // Set L2CAP channel parameters
2679   fidlbredr::L2capParameters l2cap_params;
2680   fidlbredr::ConnectParameters conn_params;
2681   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2682   l2cap_params.set_parameters(fbt::ChannelParameters());
2683   conn_params.set_l2cap(std::move(l2cap_params));
2684 
2685   std::optional<fidlbredr::Channel> response_channel;
2686   client()->Connect(
2687       fidl_peer_id,
2688       std::move(conn_params),
2689       [&response_channel](fidlbredr::Profile_Connect_Result result) {
2690         ASSERT_TRUE(result.is_response());
2691         response_channel = std::move(result.response().channel);
2692       });
2693   RunLoopUntilIdle();
2694   ASSERT_TRUE(response_channel.has_value());
2695   if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2696     EXPECT_FALSE(response_channel->has_ext_audio_offload());
2697     return;
2698   }
2699   ASSERT_TRUE(response_channel->has_ext_audio_offload());
2700 
2701   // Make A2DP offloading fail, resulting in |ZX_ERR_INTERNAL| epitaph
2702   ASSERT_TRUE(fake_channel.is_alive());
2703   fake_channel->set_a2dp_offload_fails(bt::HostError::kFailed);
2704 
2705   // Set Audio Offload Configuration Values
2706   std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2707       fidlbredr::AudioOffloadFeatures::New();
2708   std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2709       fidlbredr::AudioSbcSupport::New();
2710   codec->set_sbc(std::move(*codec_value));
2711 
2712   std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2713       std::make_unique<fidlbredr::AudioEncoderSettings>();
2714   std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2715       fuchsia::media::SbcEncoderSettings::New();
2716   encoder_settings->set_sbc(*encoder_settings_value);
2717 
2718   std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2719       std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2720   config->set_codec(std::move(*codec));
2721   config->set_max_latency(10);
2722   config->set_scms_t_enable(true);
2723   config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
2724   config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2725   config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2726   config->set_encoded_bit_rate(10);
2727   config->set_encoder_settings(std::move(*encoder_settings));
2728 
2729   fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2730       response_channel->mutable_ext_audio_offload()->Bind();
2731   fidlbredr::AudioOffloadControllerHandle controller_handle;
2732   fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2733       controller_handle.NewRequest();
2734   audio_offload_ext_client->StartAudioOffload(std::move(*config),
2735                                               std::move(controller_request));
2736 
2737   fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
2738   audio_offload_controller_client.Bind(std::move(controller_handle));
2739 
2740   std::optional<zx_status_t> audio_offload_controller_epitaph;
2741   audio_offload_controller_client.set_error_handler(
2742       [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2743 
2744   size_t cb_count = 0;
2745   audio_offload_controller_client.events().OnStarted = [&]() { cb_count++; };
2746 
2747   RunLoopUntilIdle();
2748   EXPECT_EQ(cb_count, 0u);
2749 
2750   // Verify that |audio_offload_controller_client| was closed with
2751   // |ZX_ERR_INTERNAL| epitaph
2752   ASSERT_TRUE(audio_offload_controller_epitaph.has_value());
2753   EXPECT_EQ(audio_offload_controller_epitaph.value(), ZX_ERR_INTERNAL);
2754 
2755   bt::l2cap::A2dpOffloadStatus a2dp_offload_status =
2756       fake_channel->a2dp_offload_status();
2757   EXPECT_EQ(bt::l2cap::A2dpOffloadStatus::kStopped, a2dp_offload_status);
2758 }
2759 
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtStartAudioOffloadInProgress)2760 TEST_P(AndroidSupportedFeaturesTest,
2761        AudioOffloadExtStartAudioOffloadInProgress) {
2762   FakeChannel::WeakPtr fake_channel;
2763   adapter()->fake_bredr()->set_l2cap_channel_callback(
2764       [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
2765 
2766   const bool android_vendor_ext_support = GetParam().first;
2767   const uint32_t a2dp_offload_capabilities = GetParam().second;
2768 
2769   if (android_vendor_ext_support) {
2770     adapter()->mutable_state().controller_features |=
2771         FeaturesBits::kAndroidVendorExtensions;
2772 
2773     bt::StaticPacket<
2774         android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2775         params;
2776     params.SetToZeros();
2777     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2778     params.view().version_supported().major_number().Write(0);
2779     params.view().version_supported().minor_number().Write(98);
2780     params.view()
2781         .a2dp_source_offload_capability_mask()
2782         .BackingStorage()
2783         .UncheckedWriteUInt(a2dp_offload_capabilities);
2784     adapter()->mutable_state().android_vendor_capabilities =
2785         bt::gap::AndroidVendorCapabilities::New(params.view());
2786   }
2787 
2788   const bt::PeerId peer_id(1);
2789   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2790 
2791   // Set L2CAP channel parameters
2792   fidlbredr::L2capParameters l2cap_params;
2793   fidlbredr::ConnectParameters conn_params;
2794   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2795   l2cap_params.set_parameters(fbt::ChannelParameters());
2796   conn_params.set_l2cap(std::move(l2cap_params));
2797 
2798   std::optional<fidlbredr::Channel> response_channel;
2799   client()->Connect(
2800       fidl_peer_id,
2801       std::move(conn_params),
2802       [&response_channel](fidlbredr::Profile_Connect_Result result) {
2803         ASSERT_TRUE(result.is_response());
2804         response_channel = std::move(result.response().channel);
2805       });
2806   RunLoopUntilIdle();
2807   ASSERT_TRUE(response_channel.has_value());
2808   if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2809     EXPECT_FALSE(response_channel->has_ext_audio_offload());
2810     return;
2811   }
2812   ASSERT_TRUE(response_channel->has_ext_audio_offload());
2813 
2814   // Make A2DP offloading fail, resulting in |ZX_ERR_ALREADY_BOUND| epitaph
2815   ASSERT_TRUE(fake_channel.is_alive());
2816   fake_channel->set_a2dp_offload_fails(bt::HostError::kInProgress);
2817 
2818   // Set Audio Offload Configuration Values
2819   std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2820       fidlbredr::AudioOffloadFeatures::New();
2821   std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2822       fidlbredr::AudioSbcSupport::New();
2823   codec->set_sbc(std::move(*codec_value));
2824 
2825   std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2826       std::make_unique<fidlbredr::AudioEncoderSettings>();
2827   std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2828       fuchsia::media::SbcEncoderSettings::New();
2829   encoder_settings->set_sbc(*encoder_settings_value);
2830 
2831   std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2832       std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2833   config->set_codec(std::move(*codec));
2834   config->set_max_latency(10);
2835   config->set_scms_t_enable(true);
2836   config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
2837   config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2838   config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2839   config->set_encoded_bit_rate(10);
2840   config->set_encoder_settings(std::move(*encoder_settings));
2841 
2842   fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2843       response_channel->mutable_ext_audio_offload()->Bind();
2844   fidlbredr::AudioOffloadControllerHandle controller_handle;
2845   fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2846       controller_handle.NewRequest();
2847   audio_offload_ext_client->StartAudioOffload(std::move(*config),
2848                                               std::move(controller_request));
2849 
2850   fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
2851   audio_offload_controller_client.Bind(std::move(controller_handle));
2852 
2853   std::optional<zx_status_t> audio_offload_controller_epitaph;
2854   audio_offload_controller_client.set_error_handler(
2855       [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2856 
2857   size_t cb_count = 0;
2858   audio_offload_controller_client.events().OnStarted = [&]() { cb_count++; };
2859 
2860   RunLoopUntilIdle();
2861   EXPECT_EQ(cb_count, 0u);
2862 
2863   // Verify that |audio_offload_controller_client| was closed with
2864   // |ZX_ERR_ALREADY_BOUND| epitaph
2865   ASSERT_TRUE(audio_offload_controller_epitaph.has_value());
2866   EXPECT_EQ(audio_offload_controller_epitaph.value(), ZX_ERR_ALREADY_BOUND);
2867 }
2868 
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadExtStartAudioOffloadControllerError)2869 TEST_P(AndroidSupportedFeaturesTest,
2870        AudioOffloadExtStartAudioOffloadControllerError) {
2871   FakeChannel::WeakPtr fake_channel;
2872   adapter()->fake_bredr()->set_l2cap_channel_callback(
2873       [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
2874 
2875   const bool android_vendor_ext_support = GetParam().first;
2876   const uint32_t a2dp_offload_capabilities = GetParam().second;
2877 
2878   if (android_vendor_ext_support) {
2879     adapter()->mutable_state().controller_features |=
2880         FeaturesBits::kAndroidVendorExtensions;
2881 
2882     bt::StaticPacket<
2883         android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2884         params;
2885     params.SetToZeros();
2886     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2887     params.view().version_supported().major_number().Write(0);
2888     params.view().version_supported().minor_number().Write(98);
2889     params.view()
2890         .a2dp_source_offload_capability_mask()
2891         .BackingStorage()
2892         .UncheckedWriteUInt(a2dp_offload_capabilities);
2893     adapter()->mutable_state().android_vendor_capabilities =
2894         bt::gap::AndroidVendorCapabilities::New(params.view());
2895   }
2896 
2897   const bt::PeerId peer_id(1);
2898   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2899 
2900   // Set L2CAP channel parameters
2901   fidlbredr::L2capParameters l2cap_params;
2902   fidlbredr::ConnectParameters conn_params;
2903   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
2904   l2cap_params.set_parameters(fbt::ChannelParameters());
2905   conn_params.set_l2cap(std::move(l2cap_params));
2906 
2907   std::optional<fidlbredr::Channel> response_channel;
2908   client()->Connect(
2909       fidl_peer_id,
2910       std::move(conn_params),
2911       [&response_channel](fidlbredr::Profile_Connect_Result result) {
2912         ASSERT_TRUE(result.is_response());
2913         response_channel = std::move(result.response().channel);
2914       });
2915   RunLoopUntilIdle();
2916   ASSERT_TRUE(response_channel.has_value());
2917   if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
2918     EXPECT_FALSE(response_channel->has_ext_audio_offload());
2919     return;
2920   }
2921   ASSERT_TRUE(response_channel->has_ext_audio_offload());
2922 
2923   // Set Audio Offload Configuration Values
2924   std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
2925       fidlbredr::AudioOffloadFeatures::New();
2926   std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
2927       fidlbredr::AudioSbcSupport::New();
2928   codec->set_sbc(std::move(*codec_value));
2929 
2930   std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
2931       std::make_unique<fidlbredr::AudioEncoderSettings>();
2932   std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
2933       fuchsia::media::SbcEncoderSettings::New();
2934   encoder_settings->set_sbc(*encoder_settings_value);
2935 
2936   std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
2937       std::make_unique<fidlbredr::AudioOffloadConfiguration>();
2938   config->set_codec(std::move(*codec));
2939   config->set_max_latency(10);
2940   config->set_scms_t_enable(true);
2941   config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
2942   config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
2943   config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
2944   config->set_encoded_bit_rate(10);
2945   config->set_encoder_settings(std::move(*encoder_settings));
2946 
2947   fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
2948       response_channel->mutable_ext_audio_offload()->Bind();
2949   fidlbredr::AudioOffloadControllerHandle controller_handle;
2950   fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
2951       controller_handle.NewRequest();
2952   audio_offload_ext_client->StartAudioOffload(std::move(*config),
2953                                               std::move(controller_request));
2954 
2955   fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
2956   audio_offload_controller_client.Bind(std::move(controller_handle));
2957 
2958   std::optional<zx_status_t> audio_offload_controller_epitaph;
2959   audio_offload_controller_client.set_error_handler(
2960       [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
2961 
2962   size_t cb_count = 0;
2963   audio_offload_controller_client.events().OnStarted = [&]() { cb_count++; };
2964 
2965   // Close client end of protocol to trigger audio offload error handler
2966   audio_offload_controller_client.Unbind();
2967 
2968   RunLoopUntilIdle();
2969   EXPECT_EQ(cb_count, 0u);
2970   ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
2971 }
2972 
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadControllerStopSuccess)2973 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadControllerStopSuccess) {
2974   const bool android_vendor_ext_support = GetParam().first;
2975   const uint32_t a2dp_offload_capabilities = GetParam().second;
2976 
2977   if (android_vendor_ext_support) {
2978     adapter()->mutable_state().controller_features |=
2979         FeaturesBits::kAndroidVendorExtensions;
2980 
2981     bt::StaticPacket<
2982         android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
2983         params;
2984     params.SetToZeros();
2985     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
2986     params.view().version_supported().major_number().Write(0);
2987     params.view().version_supported().minor_number().Write(98);
2988     params.view()
2989         .a2dp_source_offload_capability_mask()
2990         .BackingStorage()
2991         .UncheckedWriteUInt(a2dp_offload_capabilities);
2992     adapter()->mutable_state().android_vendor_capabilities =
2993         bt::gap::AndroidVendorCapabilities::New(params.view());
2994   }
2995 
2996   const bt::PeerId peer_id(1);
2997   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
2998 
2999   // Set L2CAP channel parameters
3000   fidlbredr::L2capParameters l2cap_params;
3001   fidlbredr::ConnectParameters conn_params;
3002   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
3003   l2cap_params.set_parameters(fbt::ChannelParameters());
3004   conn_params.set_l2cap(std::move(l2cap_params));
3005 
3006   std::optional<fidlbredr::Channel> response_channel;
3007   client()->Connect(
3008       fidl_peer_id,
3009       std::move(conn_params),
3010       [&response_channel](fidlbredr::Profile_Connect_Result result) {
3011         ASSERT_TRUE(result.is_response());
3012         response_channel = std::move(result.response().channel);
3013       });
3014   RunLoopUntilIdle();
3015   ASSERT_TRUE(response_channel.has_value());
3016   if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
3017     EXPECT_FALSE(response_channel->has_ext_audio_offload());
3018     return;
3019   }
3020   ASSERT_TRUE(response_channel->has_ext_audio_offload());
3021 
3022   // Set Audio Offload Configuration Values
3023   std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
3024       fidlbredr::AudioOffloadFeatures::New();
3025   std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
3026       fidlbredr::AudioSbcSupport::New();
3027   codec->set_sbc(std::move(*codec_value));
3028 
3029   std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
3030       std::make_unique<fidlbredr::AudioEncoderSettings>();
3031   std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
3032       fuchsia::media::SbcEncoderSettings::New();
3033   encoder_settings->set_sbc(*encoder_settings_value);
3034 
3035   std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
3036       std::make_unique<fidlbredr::AudioOffloadConfiguration>();
3037   config->set_codec(std::move(*codec));
3038   config->set_max_latency(10);
3039   config->set_scms_t_enable(true);
3040   config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
3041   config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
3042   config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
3043   config->set_encoded_bit_rate(10);
3044   config->set_encoder_settings(std::move(*encoder_settings));
3045 
3046   fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
3047       response_channel->mutable_ext_audio_offload()->Bind();
3048   fidlbredr::AudioOffloadControllerHandle controller_handle;
3049   fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
3050       controller_handle.NewRequest();
3051   audio_offload_ext_client->StartAudioOffload(std::move(*config),
3052                                               std::move(controller_request));
3053 
3054   fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
3055   audio_offload_controller_client.Bind(std::move(controller_handle));
3056 
3057   std::optional<zx_status_t> audio_offload_controller_epitaph;
3058   audio_offload_controller_client.set_error_handler(
3059       [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
3060 
3061   size_t on_started_count = 0;
3062   audio_offload_controller_client.events().OnStarted = [&]() {
3063     on_started_count++;
3064   };
3065 
3066   RunLoopUntilIdle();
3067 
3068   // Verify that OnStarted event was sent successfully
3069   EXPECT_EQ(on_started_count, 1u);
3070 
3071   // Verify that |audio_offload_controller_client| was not closed with an
3072   // epitaph
3073   ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
3074 
3075   bool stop_callback_called = false;
3076   auto callback = [&stop_callback_called](
3077                       fidlbredr::AudioOffloadController_Stop_Result result) {
3078     stop_callback_called = true;
3079   };
3080 
3081   audio_offload_controller_client->Stop(std::move(callback));
3082 
3083   RunLoopUntilIdle();
3084 
3085   // Verify that audio offload was stopped successfully
3086   ASSERT_TRUE(stop_callback_called);
3087 }
3088 
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadControllerStopFail)3089 TEST_P(AndroidSupportedFeaturesTest, AudioOffloadControllerStopFail) {
3090   FakeChannel::WeakPtr fake_channel;
3091   adapter()->fake_bredr()->set_l2cap_channel_callback(
3092       [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
3093 
3094   const bool android_vendor_ext_support = GetParam().first;
3095   const uint32_t a2dp_offload_capabilities = GetParam().second;
3096 
3097   if (android_vendor_ext_support) {
3098     adapter()->mutable_state().controller_features |=
3099         FeaturesBits::kAndroidVendorExtensions;
3100 
3101     bt::StaticPacket<
3102         android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
3103         params;
3104     params.SetToZeros();
3105     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
3106     params.view().version_supported().major_number().Write(0);
3107     params.view().version_supported().minor_number().Write(98);
3108     params.view()
3109         .a2dp_source_offload_capability_mask()
3110         .BackingStorage()
3111         .UncheckedWriteUInt(a2dp_offload_capabilities);
3112     adapter()->mutable_state().android_vendor_capabilities =
3113         bt::gap::AndroidVendorCapabilities::New(params.view());
3114   }
3115 
3116   const bt::PeerId peer_id(1);
3117   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
3118 
3119   // Set L2CAP channel parameters
3120   fidlbredr::L2capParameters l2cap_params;
3121   fidlbredr::ConnectParameters conn_params;
3122   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
3123   l2cap_params.set_parameters(fbt::ChannelParameters());
3124   conn_params.set_l2cap(std::move(l2cap_params));
3125 
3126   std::optional<fidlbredr::Channel> response_channel;
3127   client()->Connect(
3128       fidl_peer_id,
3129       std::move(conn_params),
3130       [&response_channel](fidlbredr::Profile_Connect_Result result) {
3131         ASSERT_TRUE(result.is_response());
3132         response_channel = std::move(result.response().channel);
3133       });
3134   RunLoopUntilIdle();
3135   ASSERT_TRUE(response_channel.has_value());
3136   if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
3137     EXPECT_FALSE(response_channel->has_ext_audio_offload());
3138     return;
3139   }
3140   ASSERT_TRUE(response_channel->has_ext_audio_offload());
3141 
3142   // Set Audio Offload Configuration Values
3143   std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
3144       fidlbredr::AudioOffloadFeatures::New();
3145   std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
3146       fidlbredr::AudioSbcSupport::New();
3147   codec->set_sbc(std::move(*codec_value));
3148 
3149   std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
3150       std::make_unique<fidlbredr::AudioEncoderSettings>();
3151   std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
3152       fuchsia::media::SbcEncoderSettings::New();
3153   encoder_settings->set_sbc(*encoder_settings_value);
3154 
3155   std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
3156       std::make_unique<fidlbredr::AudioOffloadConfiguration>();
3157   config->set_codec(std::move(*codec));
3158   config->set_max_latency(10);
3159   config->set_scms_t_enable(true);
3160   config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
3161   config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
3162   config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
3163   config->set_encoded_bit_rate(10);
3164   config->set_encoder_settings(std::move(*encoder_settings));
3165 
3166   fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
3167       response_channel->mutable_ext_audio_offload()->Bind();
3168   fidlbredr::AudioOffloadControllerHandle controller_handle;
3169   fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
3170       controller_handle.NewRequest();
3171   audio_offload_ext_client->StartAudioOffload(std::move(*config),
3172                                               std::move(controller_request));
3173 
3174   fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
3175   audio_offload_controller_client.Bind(std::move(controller_handle));
3176 
3177   std::optional<zx_status_t> audio_offload_controller_epitaph;
3178   audio_offload_controller_client.set_error_handler(
3179       [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
3180 
3181   size_t on_started_count = 0;
3182   audio_offload_controller_client.events().OnStarted = [&]() {
3183     on_started_count++;
3184   };
3185 
3186   RunLoopUntilIdle();
3187 
3188   // Verify that OnStarted event was sent successfully
3189   EXPECT_EQ(on_started_count, 1u);
3190 
3191   // Verify that |audio_offload_controller_client| was not closed with an
3192   // epitaph
3193   ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
3194 
3195   // Make A2DP offloading fail, resulting in |ZX_ERR_UNAVAILABLE| epitaph
3196   ASSERT_TRUE(fake_channel.is_alive());
3197   fake_channel->set_a2dp_offload_fails(bt::HostError::kInProgress);
3198 
3199   size_t cb_count = 0;
3200   audio_offload_controller_client->Stop(
3201       [&cb_count](fidlbredr::AudioOffloadController_Stop_Result result) {
3202         cb_count++;
3203       });
3204 
3205   RunLoopUntilIdle();
3206 
3207   EXPECT_EQ(cb_count, 0u);
3208 
3209   // Verify that |audio_offload_controller_client| was closed with
3210   // |ZX_ERR_UNAVAILABLE| epitaph
3211   ASSERT_TRUE(audio_offload_controller_epitaph.has_value());
3212   EXPECT_EQ(audio_offload_controller_epitaph.value(), ZX_ERR_UNAVAILABLE);
3213 }
3214 
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadControllerStopAfterAlreadyStopped)3215 TEST_P(AndroidSupportedFeaturesTest,
3216        AudioOffloadControllerStopAfterAlreadyStopped) {
3217   const bool android_vendor_ext_support = GetParam().first;
3218   const uint32_t a2dp_offload_capabilities = GetParam().second;
3219 
3220   if (android_vendor_ext_support) {
3221     adapter()->mutable_state().controller_features |=
3222         FeaturesBits::kAndroidVendorExtensions;
3223 
3224     bt::StaticPacket<
3225         android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
3226         params;
3227     params.SetToZeros();
3228     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
3229     params.view().version_supported().major_number().Write(0);
3230     params.view().version_supported().minor_number().Write(98);
3231     params.view()
3232         .a2dp_source_offload_capability_mask()
3233         .BackingStorage()
3234         .UncheckedWriteUInt(a2dp_offload_capabilities);
3235     adapter()->mutable_state().android_vendor_capabilities =
3236         bt::gap::AndroidVendorCapabilities::New(params.view());
3237   }
3238 
3239   const bt::PeerId peer_id(1);
3240   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
3241 
3242   // Set L2CAP channel parameters
3243   fidlbredr::L2capParameters l2cap_params;
3244   fidlbredr::ConnectParameters conn_params;
3245   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
3246   l2cap_params.set_parameters(fbt::ChannelParameters());
3247   conn_params.set_l2cap(std::move(l2cap_params));
3248 
3249   std::optional<fidlbredr::Channel> response_channel;
3250   client()->Connect(
3251       fidl_peer_id,
3252       std::move(conn_params),
3253       [&response_channel](fidlbredr::Profile_Connect_Result result) {
3254         ASSERT_TRUE(result.is_response());
3255         response_channel = std::move(result.response().channel);
3256       });
3257   RunLoopUntilIdle();
3258   ASSERT_TRUE(response_channel.has_value());
3259   if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
3260     EXPECT_FALSE(response_channel->has_ext_audio_offload());
3261     return;
3262   }
3263   ASSERT_TRUE(response_channel->has_ext_audio_offload());
3264 
3265   // Set Audio Offload Configuration Values
3266   std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
3267       fidlbredr::AudioOffloadFeatures::New();
3268   std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
3269       fidlbredr::AudioSbcSupport::New();
3270   codec->set_sbc(std::move(*codec_value));
3271 
3272   std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
3273       std::make_unique<fidlbredr::AudioEncoderSettings>();
3274   std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
3275       fuchsia::media::SbcEncoderSettings::New();
3276   encoder_settings->set_sbc(*encoder_settings_value);
3277 
3278   std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
3279       std::make_unique<fidlbredr::AudioOffloadConfiguration>();
3280   config->set_codec(std::move(*codec));
3281   config->set_max_latency(10);
3282   config->set_scms_t_enable(true);
3283   config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
3284   config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
3285   config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
3286   config->set_encoded_bit_rate(10);
3287   config->set_encoder_settings(std::move(*encoder_settings));
3288 
3289   fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
3290       response_channel->mutable_ext_audio_offload()->Bind();
3291   fidlbredr::AudioOffloadControllerHandle controller_handle;
3292   fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
3293       controller_handle.NewRequest();
3294   audio_offload_ext_client->StartAudioOffload(std::move(*config),
3295                                               std::move(controller_request));
3296 
3297   fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
3298   audio_offload_controller_client.Bind(std::move(controller_handle));
3299 
3300   std::optional<zx_status_t> audio_offload_controller_epitaph;
3301   audio_offload_controller_client.set_error_handler(
3302       [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
3303 
3304   size_t on_started_count = 0;
3305   audio_offload_controller_client.events().OnStarted = [&]() {
3306     on_started_count++;
3307   };
3308 
3309   RunLoopUntilIdle();
3310 
3311   // Verify that OnStarted event was sent successfully
3312   EXPECT_EQ(on_started_count, 1u);
3313 
3314   // Verify that |audio_offload_controller_client| was not closed with an
3315   // epitaph
3316   ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
3317 
3318   bool stop_callback_called = false;
3319   auto callback = [&stop_callback_called](
3320                       fidlbredr::AudioOffloadController_Stop_Result result) {
3321     stop_callback_called = true;
3322   };
3323 
3324   audio_offload_controller_client->Stop(std::move(callback));
3325 
3326   RunLoopUntilIdle();
3327 
3328   // Verify that audio offload stopped successfully
3329   ASSERT_TRUE(stop_callback_called);
3330 
3331   size_t cb_count = 0;
3332   audio_offload_controller_client->Stop(
3333       [&cb_count](fidlbredr::AudioOffloadController_Stop_Result result) {
3334         cb_count++;
3335       });
3336 
3337   RunLoopUntilIdle();
3338 
3339   // Verify that stopping audio offload has no effect when it's already stopped
3340   EXPECT_EQ(cb_count, 1u);
3341 }
3342 
TEST_P(AndroidSupportedFeaturesTest,AudioOffloadControllerUnbindStopsAudioOffload)3343 TEST_P(AndroidSupportedFeaturesTest,
3344        AudioOffloadControllerUnbindStopsAudioOffload) {
3345   FakeChannel::WeakPtr fake_channel;
3346   adapter()->fake_bredr()->set_l2cap_channel_callback(
3347       [&](FakeChannel::WeakPtr chan) { fake_channel = std::move(chan); });
3348 
3349   const bool android_vendor_ext_support = GetParam().first;
3350   const uint32_t a2dp_offload_capabilities = GetParam().second;
3351 
3352   if (android_vendor_ext_support) {
3353     adapter()->mutable_state().controller_features |=
3354         FeaturesBits::kAndroidVendorExtensions;
3355 
3356     bt::StaticPacket<
3357         android_emb::LEGetVendorCapabilitiesCommandCompleteEventWriter>
3358         params;
3359     params.SetToZeros();
3360     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
3361     params.view().version_supported().major_number().Write(0);
3362     params.view().version_supported().minor_number().Write(98);
3363     params.view()
3364         .a2dp_source_offload_capability_mask()
3365         .BackingStorage()
3366         .UncheckedWriteUInt(a2dp_offload_capabilities);
3367     adapter()->mutable_state().android_vendor_capabilities =
3368         bt::gap::AndroidVendorCapabilities::New(params.view());
3369   }
3370 
3371   const bt::PeerId peer_id(1);
3372   const fuchsia::bluetooth::PeerId fidl_peer_id{peer_id.value()};
3373 
3374   // Set L2CAP channel parameters
3375   fidlbredr::L2capParameters l2cap_params;
3376   fidlbredr::ConnectParameters conn_params;
3377   l2cap_params.set_psm(fidlbredr::PSM_AVDTP);
3378   l2cap_params.set_parameters(fbt::ChannelParameters());
3379   conn_params.set_l2cap(std::move(l2cap_params));
3380 
3381   std::optional<fidlbredr::Channel> response_channel;
3382   client()->Connect(
3383       fidl_peer_id,
3384       std::move(conn_params),
3385       [&response_channel](fidlbredr::Profile_Connect_Result result) {
3386         ASSERT_TRUE(result.is_response());
3387         response_channel = std::move(result.response().channel);
3388       });
3389   RunLoopUntilIdle();
3390   ASSERT_TRUE(response_channel.has_value());
3391   if (!android_vendor_ext_support || !a2dp_offload_capabilities) {
3392     EXPECT_FALSE(response_channel->has_ext_audio_offload());
3393     return;
3394   }
3395   ASSERT_TRUE(response_channel->has_ext_audio_offload());
3396 
3397   // Set Audio Offload Configuration Values
3398   std::unique_ptr<fidlbredr::AudioOffloadFeatures> codec =
3399       fidlbredr::AudioOffloadFeatures::New();
3400   std::unique_ptr<fidlbredr::AudioSbcSupport> codec_value =
3401       fidlbredr::AudioSbcSupport::New();
3402   codec->set_sbc(std::move(*codec_value));
3403 
3404   std::unique_ptr<fidlbredr::AudioEncoderSettings> encoder_settings =
3405       std::make_unique<fidlbredr::AudioEncoderSettings>();
3406   std::unique_ptr<fuchsia::media::SbcEncoderSettings> encoder_settings_value =
3407       fuchsia::media::SbcEncoderSettings::New();
3408   encoder_settings->set_sbc(*encoder_settings_value);
3409 
3410   std::unique_ptr<fidlbredr::AudioOffloadConfiguration> config =
3411       std::make_unique<fidlbredr::AudioOffloadConfiguration>();
3412   config->set_codec(std::move(*codec));
3413   config->set_max_latency(10);
3414   config->set_scms_t_enable(true);
3415   config->set_sampling_frequency(fidlbredr::AudioSamplingFrequency::HZ_44100);
3416   config->set_bits_per_sample(fidlbredr::AudioBitsPerSample::BPS_16);
3417   config->set_channel_mode(fidlbredr::AudioChannelMode::MONO);
3418   config->set_encoded_bit_rate(10);
3419   config->set_encoder_settings(std::move(*encoder_settings));
3420 
3421   fidlbredr::AudioOffloadExtPtr audio_offload_ext_client =
3422       response_channel->mutable_ext_audio_offload()->Bind();
3423   fidlbredr::AudioOffloadControllerHandle controller_handle;
3424   fidl::InterfaceRequest<fidlbredr::AudioOffloadController> controller_request =
3425       controller_handle.NewRequest();
3426   audio_offload_ext_client->StartAudioOffload(std::move(*config),
3427                                               std::move(controller_request));
3428 
3429   fidlbredr::AudioOffloadControllerPtr audio_offload_controller_client;
3430   audio_offload_controller_client.Bind(std::move(controller_handle));
3431 
3432   std::optional<zx_status_t> audio_offload_controller_epitaph;
3433   audio_offload_controller_client.set_error_handler(
3434       [&](zx_status_t status) { audio_offload_controller_epitaph = status; });
3435 
3436   size_t on_started_count = 0;
3437   audio_offload_controller_client.events().OnStarted = [&]() {
3438     on_started_count++;
3439   };
3440 
3441   RunLoopUntilIdle();
3442 
3443   // Verify that OnStarted event was sent successfully
3444   EXPECT_EQ(on_started_count, 1u);
3445 
3446   // Verify that |audio_offload_controller_client| was not closed with an
3447   // epitaph
3448   ASSERT_FALSE(audio_offload_controller_epitaph.has_value());
3449 
3450   bt::l2cap::A2dpOffloadStatus a2dp_offload_status =
3451       fake_channel->a2dp_offload_status();
3452 
3453   // Verify that |a2dp_offload_status| is set to started
3454   ASSERT_EQ(bt::l2cap::A2dpOffloadStatus::kStarted, a2dp_offload_status);
3455 
3456   audio_offload_controller_client.Unbind();
3457 
3458   RunLoopUntilIdle();
3459 
3460   // Verify that client is unbound from fidl channel
3461   ASSERT_FALSE(audio_offload_controller_client.is_bound());
3462 
3463   a2dp_offload_status = fake_channel->a2dp_offload_status();
3464 
3465   // Verify that |a2dp_offload_status| is set to stopped
3466   ASSERT_EQ(bt::l2cap::A2dpOffloadStatus::kStopped, a2dp_offload_status);
3467 }
3468 
3469 const std::vector<std::pair<bool, uint32_t>> kVendorCapabilitiesParams = {
3470     {{true, static_cast<uint32_t>(android_emb::A2dpCodecType::SBC)},
3471      {true, static_cast<uint32_t>(android_emb::A2dpCodecType::AAC)},
3472      {true,
3473       static_cast<uint32_t>(android_emb::A2dpCodecType::SBC) |
3474           static_cast<uint32_t>(android_emb::A2dpCodecType::AAC)},
3475      {true, 0},
3476      {false, 0}}};
3477 INSTANTIATE_TEST_SUITE_P(ProfileServerTestFakeAdapter,
3478                          AndroidSupportedFeaturesTest,
3479                          ::testing::ValuesIn(kVendorCapabilitiesParams));
3480 
TEST_F(ProfileServerTestFakeAdapter,ServiceUuidSearchResultRelayedToFidlClient)3481 TEST_F(ProfileServerTestFakeAdapter,
3482        ServiceUuidSearchResultRelayedToFidlClient) {
3483   fidlbredr::SearchResultsHandle search_results_handle;
3484   FakeSearchResults search_results(search_results_handle.NewRequest(),
3485                                    dispatcher());
3486 
3487   fidlbredr::ServiceClassProfileIdentifier search_uuid =
3488       fidlbredr::ServiceClassProfileIdentifier::AUDIO_SINK;
3489 
3490   EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3491   EXPECT_EQ(search_results.service_found_count(), 0u);
3492 
3493   // FIDL client registers a service search.
3494   fidlbredr::ProfileSearchRequest request;
3495   request.set_service_uuid(search_uuid);
3496   request.set_attr_ids({});
3497   request.set_results(std::move(search_results_handle));
3498   client()->Search(std::move(request));
3499   RunLoopUntilIdle();
3500 
3501   EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 1u);
3502 
3503   // Trigger a match on the service search with some data. Should be received by
3504   // the FIDL client.
3505   bt::PeerId peer_id = bt::PeerId{10};
3506   bt::UUID uuid(static_cast<uint32_t>(search_uuid));
3507 
3508   bt::sdp::AttributeId attr_id = 50;  // Random Attribute ID
3509   bt::sdp::DataElement elem = bt::sdp::DataElement();
3510   elem.SetUrl("https://foobar.dev");  // Random URL
3511   auto attributes = std::map<bt::sdp::AttributeId, bt::sdp::DataElement>();
3512   attributes.emplace(attr_id, std::move(elem));
3513   adapter()->fake_bredr()->TriggerServiceFound(
3514       peer_id, uuid, std::move(attributes));
3515 
3516   RunLoopUntilIdle();
3517 
3518   EXPECT_EQ(search_results.service_found_count(), 1u);
3519   EXPECT_EQ(search_results.peer_id().value().value, peer_id.value());
3520   EXPECT_EQ(search_results.attributes().value().size(), 1u);
3521   EXPECT_EQ(search_results.attributes().value()[0].id(), attr_id);
3522   EXPECT_EQ(search_results.attributes().value()[0].element().url(),
3523             std::string("https://foobar.dev"));
3524 }
3525 
TEST_F(ProfileServerTestFakeAdapter,FullUuidSearchResultRelayedToFidlClient)3526 TEST_F(ProfileServerTestFakeAdapter, FullUuidSearchResultRelayedToFidlClient) {
3527   fidlbredr::SearchResultsHandle search_results_handle;
3528   FakeSearchResults search_results(search_results_handle.NewRequest(),
3529                                    dispatcher());
3530 
3531   EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3532   EXPECT_EQ(search_results.service_found_count(), 0u);
3533 
3534   // FIDL client registers a service search.
3535   fuchsia::bluetooth::Uuid search_uuid =
3536       fidl_helpers::UuidToFidl(bt::sdp::profile::kHandsfree);
3537   fidlbredr::ProfileSearchRequest request;
3538   request.set_full_uuid(search_uuid);
3539   request.set_attr_ids({});
3540   request.set_results(std::move(search_results_handle));
3541   client()->Search(std::move(request));
3542   RunLoopUntilIdle();
3543 
3544   EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 1u);
3545 
3546   // Trigger a match on the service search with some data. Should be received by
3547   // the FIDL client.
3548   bt::PeerId peer_id = bt::PeerId{10};
3549   bt::UUID uuid = bt::sdp::profile::kHandsfree;
3550 
3551   bt::sdp::AttributeId attr_id = 50;  // Random Attribute ID
3552   bt::sdp::DataElement elem = bt::sdp::DataElement();
3553   elem.SetUrl("https://foobar.dev");  // Random URL
3554   auto attributes = std::map<bt::sdp::AttributeId, bt::sdp::DataElement>();
3555   attributes.emplace(attr_id, std::move(elem));
3556   adapter()->fake_bredr()->TriggerServiceFound(
3557       peer_id, uuid, std::move(attributes));
3558 
3559   RunLoopUntilIdle();
3560 
3561   EXPECT_EQ(search_results.service_found_count(), 1u);
3562   EXPECT_EQ(search_results.peer_id().value().value, peer_id.value());
3563   EXPECT_EQ(search_results.attributes().value().size(), 1u);
3564   EXPECT_EQ(search_results.attributes().value()[0].id(), attr_id);
3565   EXPECT_EQ(search_results.attributes().value()[0].element().url(),
3566             std::string("https://foobar.dev"));
3567 }
3568 
TEST_F(ProfileServerTestFakeAdapter,SearchWithMissingUuidFails)3569 TEST_F(ProfileServerTestFakeAdapter, SearchWithMissingUuidFails) {
3570   fidlbredr::SearchResultsHandle search_results_handle;
3571   FakeSearchResults search_results(search_results_handle.NewRequest(),
3572                                    dispatcher());
3573 
3574   // Neither `service_uuid` nor `full_uid` is set
3575   fidlbredr::ProfileSearchRequest request;
3576   request.set_results(std::move(search_results_handle));
3577   client()->Search(std::move(request));
3578   RunLoopUntilIdle();
3579   EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3580   EXPECT_TRUE(search_results.closed());
3581 }
3582 
TEST_F(ProfileServerTestFakeAdapter,SearchWithServiceAndFullUuidFails)3583 TEST_F(ProfileServerTestFakeAdapter, SearchWithServiceAndFullUuidFails) {
3584   fidlbredr::SearchResultsHandle search_results_handle;
3585   FakeSearchResults search_results(search_results_handle.NewRequest(),
3586                                    dispatcher());
3587 
3588   fidlbredr::ServiceClassProfileIdentifier search_uuid =
3589       fidlbredr::ServiceClassProfileIdentifier::AUDIO_SINK;
3590 
3591   fidlbredr::ProfileSearchRequest request;
3592   request.set_results(std::move(search_results_handle));
3593   request.set_service_uuid(search_uuid);
3594   request.set_full_uuid(fidl_helpers::UuidToFidl(bt::sdp::profile::kAudioSink));
3595   client()->Search(std::move(request));
3596   RunLoopUntilIdle();
3597   EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3598   EXPECT_TRUE(search_results.closed());
3599 }
3600 
TEST_F(ProfileServerTestFakeAdapter,SearchWithMissingResultsClientFails)3601 TEST_F(ProfileServerTestFakeAdapter, SearchWithMissingResultsClientFails) {
3602   // results is not set
3603   fidlbredr::ProfileSearchRequest request;
3604   request.set_service_uuid(
3605       fidlbredr::ServiceClassProfileIdentifier::AUDIO_SINK);
3606   client()->Search(std::move(request));
3607   RunLoopUntilIdle();
3608   EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 0u);
3609 }
3610 
TEST_F(ProfileServerTestFakeAdapter,SearchWithMissingAttrIdsSucceeds)3611 TEST_F(ProfileServerTestFakeAdapter, SearchWithMissingAttrIdsSucceeds) {
3612   fidlbredr::SearchResultsHandle search_results_handle;
3613   FakeSearchResults search_results(search_results_handle.NewRequest(),
3614                                    dispatcher());
3615 
3616   fidlbredr::ProfileSearchRequest request;
3617   request.set_service_uuid(
3618       fidlbredr::ServiceClassProfileIdentifier::AUDIO_SINK);
3619   request.set_results(std::move(search_results_handle));
3620   client()->Search(std::move(request));
3621   RunLoopUntilIdle();
3622   EXPECT_EQ(adapter()->fake_bredr()->registered_searches().size(), 1u);
3623 }
3624 
TEST_F(ProfileServerTestScoConnected,ScoConnectionRead2Packets)3625 TEST_F(ProfileServerTestScoConnected, ScoConnectionRead2Packets) {
3626   // Queue a read request before the packet is received.
3627   std::optional<fidlbredr::RxPacketStatus> packet_status;
3628   std::optional<std::vector<uint8_t>> packet;
3629   sco_connection()->Read(
3630       [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3631         ASSERT_TRUE(result.is_response());
3632         packet_status = result.response().status_flag();
3633         packet = std::move(*result.response().mutable_data());
3634       });
3635   RunLoopUntilIdle();
3636   EXPECT_FALSE(packet_status);
3637   EXPECT_FALSE(packet);
3638 
3639   bt::StaticByteBuffer packet_buffer_0(
3640       bt::LowerBits(sco_handle()),
3641       bt::UpperBits(sco_handle()) |
3642           0x30,  // handle + packet status flag: kDataPartiallyLost
3643       0x01,      // payload length
3644       0x00       // payload
3645   );
3646   bt::BufferView packet_buffer_0_payload =
3647       packet_buffer_0.view(sizeof(bt::hci_spec::SynchronousDataHeader));
3648   test_device()->SendScoDataChannelPacket(packet_buffer_0);
3649   RunLoopUntilIdle();
3650   ASSERT_TRUE(packet_status);
3651   EXPECT_EQ(packet_status.value(),
3652             fidlbredr::RxPacketStatus::DATA_PARTIALLY_LOST);
3653   ASSERT_TRUE(packet);
3654   EXPECT_THAT(packet.value(),
3655               ::testing::ElementsAreArray(packet_buffer_0_payload));
3656   packet_status.reset();
3657   packet.reset();
3658 
3659   // Receive a second packet. This time, receive the packet before Read() is
3660   // called.
3661   bt::StaticByteBuffer packet_buffer_1(
3662       bt::LowerBits(sco_handle()),
3663       bt::UpperBits(
3664           sco_handle()),  // handle + packet status flag: kCorrectlyReceived
3665       0x01,               // payload length
3666       0x01                // payload
3667   );
3668   bt::BufferView packet_buffer_1_payload =
3669       packet_buffer_1.view(sizeof(bt::hci_spec::SynchronousDataHeader));
3670   test_device()->SendScoDataChannelPacket(packet_buffer_1);
3671   RunLoopUntilIdle();
3672 
3673   sco_connection()->Read(
3674       [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3675         ASSERT_TRUE(result.is_response());
3676         packet_status = result.response().status_flag();
3677         packet = std::move(*result.response().mutable_data());
3678       });
3679   RunLoopUntilIdle();
3680   ASSERT_TRUE(packet_status);
3681   EXPECT_EQ(packet_status.value(),
3682             fidlbredr::RxPacketStatus::CORRECTLY_RECEIVED_DATA);
3683   ASSERT_TRUE(packet);
3684   EXPECT_THAT(packet.value(),
3685               ::testing::ElementsAreArray(packet_buffer_1_payload));
3686 }
3687 
TEST_F(ProfileServerTestScoConnected,ScoConnectionReadWhileReadPendingClosesConnection)3688 TEST_F(ProfileServerTestScoConnected,
3689        ScoConnectionReadWhileReadPendingClosesConnection) {
3690   std::optional<fidlbredr::RxPacketStatus> packet_status_0;
3691   std::optional<std::vector<uint8_t>> packet_0;
3692   sco_connection()->Read(
3693       [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3694         ASSERT_TRUE(result.is_response());
3695         packet_status_0 = result.response().status_flag();
3696         packet_0 = std::move(*result.response().mutable_data());
3697       });
3698 
3699   RunLoopUntilIdle();
3700   EXPECT_FALSE(packet_status_0);
3701   EXPECT_FALSE(packet_0);
3702 
3703   std::optional<fidlbredr::RxPacketStatus> packet_status_1;
3704   std::optional<std::vector<uint8_t>> packet_1;
3705   sco_connection()->Read(
3706       [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3707         ASSERT_TRUE(result.is_response());
3708         packet_status_1 = result.response().status_flag();
3709         packet_1 = std::move(*result.response().mutable_data());
3710       });
3711 
3712   RunLoopUntilIdle();
3713   EXPECT_FALSE(packet_status_0);
3714   EXPECT_FALSE(packet_0);
3715   EXPECT_FALSE(packet_status_1);
3716   EXPECT_FALSE(packet_1);
3717   EXPECT_FALSE(sco_connection());
3718   ASSERT_TRUE(sco_conn_error());
3719   EXPECT_EQ(sco_conn_error().value(), ZX_ERR_BAD_STATE);
3720 }
3721 
TEST_F(ProfileServerTestOffloadedScoConnected,ScoConnectionReadFails)3722 TEST_F(ProfileServerTestOffloadedScoConnected, ScoConnectionReadFails) {
3723   sco_connection()->Read(
3724       [&](::fuchsia::bluetooth::bredr::ScoConnection_Read_Result result) {
3725         FAIL();
3726       });
3727   RunLoopUntilIdle();
3728   EXPECT_FALSE(sco_connection());
3729   ASSERT_TRUE(sco_conn_error());
3730   EXPECT_EQ(sco_conn_error().value(), ZX_ERR_IO_NOT_PRESENT);
3731 }
3732 
TEST_F(ProfileServerTestScoConnected,ScoConnectionWriteTwice)3733 TEST_F(ProfileServerTestScoConnected, ScoConnectionWriteTwice) {
3734   bt::StaticByteBuffer payload_0(0x00);
3735   bt::DynamicByteBuffer packet_buffer_0 = bt::testing::ScoDataPacket(
3736       sco_handle(),
3737       bt::hci_spec::SynchronousDataPacketStatusFlag::kCorrectlyReceived,
3738       payload_0.view());
3739 
3740   bt::StaticByteBuffer payload_1(0x01);
3741   bt::DynamicByteBuffer packet_buffer_1 = bt::testing::ScoDataPacket(
3742       sco_handle(),
3743       bt::hci_spec::SynchronousDataPacketStatusFlag::kCorrectlyReceived,
3744       payload_1.view());
3745 
3746   int sco_cb_count = 0;
3747   test_device()->SetScoDataCallback([&](const bt::ByteBuffer& buffer) {
3748     if (sco_cb_count == 0) {
3749       EXPECT_THAT(buffer, ::testing::ElementsAreArray(packet_buffer_0));
3750     } else if (sco_cb_count == 1) {
3751       EXPECT_THAT(buffer, ::testing::ElementsAreArray(packet_buffer_1));
3752     } else {
3753       ADD_FAILURE() << "Unexpected packet sent";
3754     }
3755     sco_cb_count++;
3756   });
3757   int write_cb_0_count = 0;
3758   fidlbredr::ScoConnectionWriteRequest request_0;
3759   request_0.set_data(payload_0.ToVector());
3760   sco_connection()->Write(std::move(request_0),
3761                           [&](fidlbredr::ScoConnection_Write_Result result) {
3762                             ASSERT_TRUE(result.is_response());
3763                             write_cb_0_count++;
3764                           });
3765   RunLoopUntilIdle();
3766   EXPECT_EQ(sco_cb_count, 1);
3767   EXPECT_EQ(write_cb_0_count, 1);
3768 
3769   int write_cb_1_count = 0;
3770   fidlbredr::ScoConnectionWriteRequest request_1;
3771   request_1.set_data(payload_1.ToVector());
3772   sco_connection()->Write(std::move(request_1),
3773                           [&](fidlbredr::ScoConnection_Write_Result result) {
3774                             ASSERT_TRUE(result.is_response());
3775                             write_cb_1_count++;
3776                           });
3777   RunLoopUntilIdle();
3778   EXPECT_EQ(sco_cb_count, 2);
3779   EXPECT_EQ(write_cb_1_count, 1);
3780 
3781   test_device()->ClearScoDataCallback();
3782 }
3783 
TEST_F(ProfileServerTestScoConnected,ScoConnectionWriteMissingDataField)3784 TEST_F(ProfileServerTestScoConnected, ScoConnectionWriteMissingDataField) {
3785   int write_cb_count = 0;
3786   // The `data` field is not set.
3787   fidlbredr::ScoConnectionWriteRequest request;
3788   sco_connection()->Write(
3789       std::move(request),
3790       [&](fidlbredr::ScoConnection_Write_Result result) { write_cb_count++; });
3791   RunLoopUntilIdle();
3792   EXPECT_EQ(write_cb_count, 0);
3793   EXPECT_FALSE(sco_connection());
3794   ASSERT_TRUE(sco_conn_error());
3795   EXPECT_EQ(sco_conn_error().value(), ZX_ERR_INVALID_ARGS);
3796 }
3797 
TEST_F(ProfileServerTestOffloadedScoConnected,ScoConnectionWriteFails)3798 TEST_F(ProfileServerTestOffloadedScoConnected, ScoConnectionWriteFails) {
3799   int write_cb_count = 0;
3800   fidlbredr::ScoConnectionWriteRequest request;
3801   request.set_data({0x00});
3802   sco_connection()->Write(
3803       std::move(request),
3804       [&](fidlbredr::ScoConnection_Write_Result result) { write_cb_count++; });
3805   RunLoopUntilIdle();
3806   EXPECT_EQ(write_cb_count, 0);
3807   EXPECT_FALSE(sco_connection());
3808   ASSERT_TRUE(sco_conn_error());
3809   EXPECT_EQ(sco_conn_error().value(), ZX_ERR_IO_NOT_PRESENT);
3810 }
3811 
3812 }  // namespace
3813 }  // namespace bthost
3814