1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/properties.h>
18 #include <base/functional/bind.h>
19 #include <base/location.h>
20 #include <bluetooth/log.h>
21 #include <com_android_bluetooth_flags.h>
22 #include <flag_macros.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 
26 #include <memory>
27 #include <string>
28 
29 #include "bta/ag/bta_ag_int.h"
30 #include "bta/include/bta_ag_swb_aptx.h"
31 #include "hci/controller_interface_mock.h"
32 #include "stack/include/btm_status.h"
33 #include "test/common/main_handler.h"
34 #include "test/common/mock_functions.h"
35 #include "test/fake/fake_osi.h"
36 #include "test/mock/mock_bta_sys_main.h"
37 #include "test/mock/mock_device_esco_parameters.h"
38 #include "test/mock/mock_main_shim_entry.h"
39 #include "test/mock/mock_osi_alarm.h"
40 #include "test/mock/mock_stack_acl.h"
41 #include "test/mock/mock_stack_btm_interface.h"
42 
43 #define TEST_BT com::android::bluetooth::flags
44 
45 using namespace bluetooth;
46 
47 namespace {
48 
bta_ag_hdl_event(const BT_HDR_RIGID *)49 bool bta_ag_hdl_event(const BT_HDR_RIGID* /*p_msg*/) { return true; }
BTA_AgDisable()50 void BTA_AgDisable() { bta_sys_deregister(BTA_ID_AG); }
51 
52 const tBTA_SYS_REG bta_ag_reg = {bta_ag_hdl_event, BTA_AgDisable};
53 
54 }  // namespace
55 
56 const std::string kBtCodecAptxVoiceEnabled = "bluetooth.hfp.codec_aptx_voice.enabled";
57 
enable_aptx_voice_property(bool enable)58 static bool enable_aptx_voice_property(bool enable) {
59   const std::string value = enable ? "true" : "false";
60   return android::base::SetProperty(kBtCodecAptxVoiceEnabled, value);
61 }
62 
63 class BtaAgTest : public testing::Test {
64 protected:
SetUp()65   void SetUp() override {
66     reset_mock_function_count_map();
67     fake_osi_ = std::make_unique<test::fake::FakeOsi>();
68     bluetooth::hci::testing::mock_controller_ = &controller_;
69 
70     main_thread_start_up();
71     post_on_bt_main([]() { log::info("Main thread started up"); });
72 
73     bta_sys_register(BTA_ID_AG, &bta_ag_reg);
74 
75     bta_ag_cb.p_cback = [](tBTA_AG_EVT /*event*/, tBTA_AG* /*p_data*/) {};
76     RawAddress::FromString("00:11:22:33:44:55", addr);
77     test::mock::device_esco_parameters::esco_parameters_for_codec.body =
78             [this](esco_codec_t codec) {
79               this->codec = codec;
80               return enh_esco_params_t{};
81             };
82   }
TearDown()83   void TearDown() override {
84     test::mock::device_esco_parameters::esco_parameters_for_codec = {};
85     bta_sys_deregister(BTA_ID_AG);
86     post_on_bt_main([]() { log::info("Main thread shutting down"); });
87     main_thread_shut_down();
88     bluetooth::hci::testing::mock_controller_ = nullptr;
89   }
90 
91   std::unique_ptr<test::fake::FakeOsi> fake_osi_;
92   const char test_strings[5][13] = {"0,4,6,7", "4,6,7", "test,0,4", "9,8,7", "4,6,7,test"};
93   uint32_t tmp_num = 0xFFFF;
94   RawAddress addr;
95   esco_codec_t codec;
96   bluetooth::hci::testing::MockControllerInterface controller_;
97 };
98 
99 class BtaAgSwbTest : public BtaAgTest {
100 protected:
SetUp()101   void SetUp() override { BtaAgTest::SetUp(); }
TearDown()102   void TearDown() override { BtaAgTest::TearDown(); }
103 };
104 
TEST_F(BtaAgSwbTest,parse_qac_at_command)105 TEST_F(BtaAgSwbTest, parse_qac_at_command) {
106   tBTA_AG_PEER_CODEC codec = bta_ag_parse_qac((char*)test_strings[0]);
107   codec = bta_ag_parse_qac((char*)test_strings[0]);
108   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK);
109   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK);
110   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK);
111   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK);
112 
113   codec = bta_ag_parse_qac((char*)test_strings[1]);
114   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK);
115   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK);
116   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK);
117 
118   codec = bta_ag_parse_qac((char*)test_strings[2]);
119   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK);
120   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK);
121 
122   codec = bta_ag_parse_qac((char*)test_strings[3]);
123   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK);
124 
125   codec = bta_ag_parse_qac((char*)test_strings[4]);
126   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK);
127   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK);
128   ASSERT_TRUE(codec & BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK);
129 }
130 
TEST_F(BtaAgSwbTest,enable_swb_codec)131 TEST_F(BtaAgSwbTest, enable_swb_codec) {
132   ASSERT_TRUE(enable_aptx_voice_property(true));
133   ASSERT_EQ(BT_STATUS_SUCCESS, enable_aptx_swb_codec(true, &addr));
134   ASSERT_TRUE(get_swb_codec_status(bluetooth::headset::BTHF_SWB_CODEC_VENDOR_APTX, &addr));
135   ASSERT_TRUE(enable_aptx_voice_property(false));
136 }
137 
138 class BtaAgActTest : public BtaAgTest {
139 protected:
SetUp()140   void SetUp() override { BtaAgTest::SetUp(); }
TearDown()141   void TearDown() override { BtaAgTest::TearDown(); }
142 };
143 
TEST_F(BtaAgActTest,set_codec_q0_success)144 TEST_F(BtaAgActTest, set_codec_q0_success) {
145   tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
146   const tBTA_AG_DATA data = {.api_setcodec.codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0};
147 
148   bta_ag_cb.p_cback = [](tBTA_AG_EVT /*event*/, tBTA_AG* p_data) {
149     tBTA_AG_VAL* val = (tBTA_AG_VAL*)p_data;
150     ASSERT_EQ(val->num, BTA_AG_SCO_APTX_SWB_SETTINGS_Q0);
151     ASSERT_EQ(val->hdr.status, BTA_AG_SUCCESS);
152   };
153 
154   p_scb->peer_codecs = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0;
155   p_scb->sco_codec = BTM_SCO_CODEC_NONE;
156   p_scb->codec_updated = false;
157 
158   bta_ag_setcodec(p_scb, data);
159   ASSERT_EQ(p_scb->sco_codec, BTA_AG_SCO_APTX_SWB_SETTINGS_Q0);
160 }
161 
TEST_F(BtaAgActTest,set_codec_q1_fail_unsupported)162 TEST_F(BtaAgActTest, set_codec_q1_fail_unsupported) {
163   tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
164   const tBTA_AG_DATA data = {.api_setcodec.codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q1};
165 
166   ASSERT_TRUE(enable_aptx_voice_property(true));
167 
168   bta_ag_cb.p_cback = [](tBTA_AG_EVT /*event*/, tBTA_AG* p_data) {
169     tBTA_AG_VAL* val = (tBTA_AG_VAL*)p_data;
170     ASSERT_EQ(val->num, BTA_AG_SCO_APTX_SWB_SETTINGS_Q1);
171     ASSERT_EQ(val->hdr.status, BTA_AG_FAIL_RESOURCES);
172   };
173 
174   p_scb->peer_codecs = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0;
175   p_scb->sco_codec = BTM_SCO_CODEC_NONE;
176   p_scb->codec_updated = false;
177 
178   bta_ag_setcodec(p_scb, data);
179   ASSERT_TRUE(enable_aptx_voice_property(false));
180 }
181 
182 class BtaAgCmdTest : public BtaAgTest {
183 protected:
SetUp()184   void SetUp() override { BtaAgTest::SetUp(); }
TearDown()185   void TearDown() override { BtaAgTest::TearDown(); }
186 };
187 
TEST_F(BtaAgCmdTest,check_flag_guarding_with_prop)188 TEST_F(BtaAgCmdTest, check_flag_guarding_with_prop) {
189   ASSERT_TRUE(enable_aptx_voice_property(false));
190   ASSERT_FALSE(is_hfp_aptx_voice_enabled());
191 
192   ASSERT_TRUE(enable_aptx_voice_property(true));
193   ASSERT_TRUE(is_hfp_aptx_voice_enabled());
194 }
195 
TEST_F(BtaAgCmdTest,at_hfp_cback__qac_ev_codec_disabled)196 TEST_F(BtaAgCmdTest, at_hfp_cback__qac_ev_codec_disabled) {
197   tBTA_AG_SCB p_scb = {
198           .peer_addr = addr,
199           .app_id = 0,
200   };
201 
202   ASSERT_TRUE(enable_aptx_voice_property(false));
203 
204   bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QAC_EVT, 0, (char*)&test_strings[0][0],
205                       (char*)&test_strings[0][12], BTA_AG_SCO_APTX_SWB_SETTINGS_Q0);
206   ASSERT_FALSE(p_scb.codec_updated);
207   ASSERT_FALSE(p_scb.is_aptx_swb_codec);
208   ASSERT_EQ(1, get_func_call_count("PORT_WriteData"));
209 }
210 
TEST_F(BtaAgCmdTest,at_hfp_cback__qac_ev_codec_enabled)211 TEST_F(BtaAgCmdTest, at_hfp_cback__qac_ev_codec_enabled) {
212   tBTA_AG_SCB p_scb = {
213           .peer_addr = addr, .app_id = 0, .peer_codecs = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK};
214 
215   ASSERT_TRUE(enable_aptx_voice_property(true));
216   ASSERT_EQ(BT_STATUS_SUCCESS, enable_aptx_swb_codec(true, &addr));
217   bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QAC_EVT, 0, (char*)&test_strings[0][0],
218                       (char*)&test_strings[0][12], BTA_AG_SCO_APTX_SWB_SETTINGS_Q0);
219   ASSERT_TRUE(p_scb.codec_updated);
220   ASSERT_TRUE(p_scb.is_aptx_swb_codec);
221   ASSERT_EQ(2, get_func_call_count("PORT_WriteData"));
222   ASSERT_EQ(p_scb.sco_codec, BTA_AG_SCO_APTX_SWB_SETTINGS_Q0);
223   ASSERT_TRUE(enable_aptx_voice_property(false));
224 }
225 
TEST_F(BtaAgCmdTest,at_hfp_cback__qcs_ev_codec_disabled)226 TEST_F(BtaAgCmdTest, at_hfp_cback__qcs_ev_codec_disabled) {
227   tBTA_AG_SCB p_scb = {
228           .peer_addr = addr,
229           .app_id = 0,
230   };
231 
232   ASSERT_TRUE(enable_aptx_voice_property(false));
233 
234   bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QCS_EVT, 0, (char*)&test_strings[0][0],
235                       (char*)&test_strings[0][12], BTA_AG_SCO_APTX_SWB_SETTINGS_Q0);
236   ASSERT_FALSE(p_scb.codec_updated);
237   ASSERT_FALSE(p_scb.is_aptx_swb_codec);
238   ASSERT_EQ(1, get_func_call_count("PORT_WriteData"));
239 }
240 
TEST_F(BtaAgCmdTest,at_hfp_cback__qcs_ev_codec_q0_enabled)241 TEST_F(BtaAgCmdTest, at_hfp_cback__qcs_ev_codec_q0_enabled) {
242   reset_mock_btm_client_interface();
243   mock_btm_client_interface.sco.BTM_SetEScoMode =
244           [](enh_esco_params_t* /* p_params */) -> tBTM_STATUS {
245     inc_func_call_count("BTM_SetEScoMode");
246     return tBTM_STATUS::BTM_SUCCESS;
247   };
248   mock_btm_client_interface.sco.BTM_CreateSco =
249           [](const RawAddress* /* remote_bda */, bool /* is_orig */, uint16_t /* pkt_types */,
250              uint16_t* /* p_sco_inx */, tBTM_SCO_CB* /* p_conn_cb */,
251              tBTM_SCO_CB* /* p_disc_cb */) -> tBTM_STATUS {
252     inc_func_call_count("BTM_CreateSco");
253     return tBTM_STATUS::BTM_CMD_STARTED;
254   };
255 
256   tBTA_AG_SCB p_scb = {.peer_addr = addr,
257                        .sco_idx = BTM_INVALID_SCO_INDEX,
258                        .app_id = 0,
259                        .sco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0,
260                        .is_aptx_swb_codec = true};
261 
262   ASSERT_TRUE(enable_aptx_voice_property(true));
263 
264   bta_ag_cb.sco.state = BTA_AG_SCO_CODEC_ST;
265   bta_ag_api_set_active_device(addr);
266   ASSERT_EQ(addr, bta_ag_get_active_device());
267 
268   ASSERT_EQ(BT_STATUS_SUCCESS, enable_aptx_swb_codec(true, &addr));
269   bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QCS_EVT, 0, (char*)&test_strings[0][0],
270                       (char*)&test_strings[0][12], BTA_AG_SCO_APTX_SWB_SETTINGS_Q0);
271 
272   ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
273   ASSERT_EQ(1, get_func_call_count("esco_parameters_for_codec"));
274   ASSERT_EQ(BT_STATUS_SUCCESS, enable_aptx_swb_codec(true, &addr));
275   ASSERT_EQ(1, get_func_call_count("BTM_SetEScoMode"));
276   ASSERT_EQ(1, get_func_call_count("BTM_CreateSco"));
277   ASSERT_EQ(this->codec, ESCO_CODEC_SWB_Q0);
278   ASSERT_TRUE(enable_aptx_voice_property(false));
279 }
280 
TEST_F(BtaAgCmdTest,handle_swb_at_event__qcs_ev_codec_q1_fallback_to_q0)281 TEST_F(BtaAgCmdTest, handle_swb_at_event__qcs_ev_codec_q1_fallback_to_q0) {
282   reset_mock_btm_client_interface();
283   mock_btm_client_interface.sco.BTM_SetEScoMode =
284           [](enh_esco_params_t* /*p_params*/) -> tBTM_STATUS {
285     inc_func_call_count("BTM_SetEScoMode");
286     return tBTM_STATUS::BTM_SUCCESS;
287   };
288   mock_btm_client_interface.sco.BTM_CreateSco =
289           [](const RawAddress* /* remote_bda */, bool /* is_orig */, uint16_t /* pkt_types */,
290              uint16_t* /* p_sco_inx */, tBTM_SCO_CB* /* p_conn_cb */,
291              tBTM_SCO_CB* /* p_disc_cb */) -> tBTM_STATUS {
292     inc_func_call_count("BTM_CreateSco");
293     return tBTM_STATUS::BTM_CMD_STARTED;
294   };
295 
296   tBTA_AG_SCB p_scb = {.peer_addr = addr,
297                        .sco_idx = BTM_INVALID_SCO_INDEX,
298                        .app_id = 0,
299                        .sco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q1,
300                        .codec_fallback = false,
301                        .is_aptx_swb_codec = true};
302 
303   ASSERT_TRUE(enable_aptx_voice_property(true));
304 
305   bta_ag_cb.sco.state = BTA_AG_SCO_CODEC_ST;
306   bta_ag_api_set_active_device(addr);
307   ASSERT_EQ(addr, bta_ag_get_active_device());
308 
309   ASSERT_EQ(BT_STATUS_SUCCESS, enable_aptx_swb_codec(true, &addr));
310   bta_ag_at_hfp_cback(&p_scb, BTA_AG_AT_QCS_EVT, 0, (char*)&test_strings[0][0],
311                       (char*)&test_strings[0][12], BTA_AG_SCO_APTX_SWB_SETTINGS_Q1);
312 
313   ASSERT_EQ(1, get_func_call_count("alarm_cancel"));
314   ASSERT_EQ(1, get_func_call_count("esco_parameters_for_codec"));
315   ASSERT_EQ(BT_STATUS_SUCCESS, enable_aptx_swb_codec(true, &addr));
316   ASSERT_EQ(1, get_func_call_count("BTM_SetEScoMode"));
317   ASSERT_EQ(1, get_func_call_count("BTM_CreateSco"));
318   ASSERT_EQ(this->codec, ESCO_CODEC_SWB_Q0);
319   ASSERT_TRUE(enable_aptx_voice_property(false));
320 }
321 
322 namespace {
323 uint8_t data[3] = {1, 2, 3};
324 }  // namespace
325 
326 class BtaAgScoTest : public BtaAgTest {
327 protected:
SetUp()328   void SetUp() override {
329     BtaAgTest::SetUp();
330     reset_mock_btm_client_interface();
331     mock_btm_client_interface.peer.BTM_ReadRemoteFeatures = [](const RawAddress& /*addr*/) {
332       inc_func_call_count("BTM_ReadRemoteFeatures");
333       return data;
334     };
335   }
TearDown()336   void TearDown() override {
337     reset_mock_btm_client_interface();
338     BtaAgTest::TearDown();
339   }
340 };
341 
TEST_F(BtaAgScoTest,codec_negotiate__aptx_state_on)342 TEST_F(BtaAgScoTest, codec_negotiate__aptx_state_on) {
343   tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
344   p_scb->app_id = 0;
345   p_scb->peer_addr = addr;
346   p_scb->codec_negotiation_timer = alarm_new("bta_ag.scb_codec_negotiation_timer");
347   p_scb->peer_codecs = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK;
348   p_scb->is_aptx_swb_codec = false;
349 
350   ASSERT_TRUE(enable_aptx_voice_property(true));
351   ASSERT_EQ(BT_STATUS_SUCCESS, enable_aptx_swb_codec(true, &addr));
352   bta_ag_codec_negotiate(p_scb);
353   ASSERT_EQ(1, get_func_call_count("BTM_ReadRemoteFeatures"));
354   ASSERT_EQ(1, get_func_call_count("PORT_WriteData"));
355   ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
356   ASSERT_TRUE(p_scb->is_aptx_swb_codec);
357   ASSERT_EQ(p_scb->sco_codec, BTA_AG_SCO_APTX_SWB_SETTINGS_Q0);
358   ASSERT_TRUE(enable_aptx_voice_property(false));
359 }
360 
TEST_F(BtaAgScoTest,codec_negotiate__aptx_state_off)361 TEST_F(BtaAgScoTest, codec_negotiate__aptx_state_off) {
362   tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
363   p_scb->app_id = 0;
364   p_scb->peer_addr = addr;
365   p_scb->codec_negotiation_timer = alarm_new("bta_ag.scb_codec_negotiation_timer");
366   p_scb->peer_codecs = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK;
367   p_scb->is_aptx_swb_codec = true;
368 
369   ASSERT_TRUE(enable_aptx_voice_property(true));
370   ASSERT_EQ(BT_STATUS_SUCCESS, enable_aptx_swb_codec(false, &addr));
371   bta_ag_codec_negotiate(p_scb);
372   ASSERT_EQ(1, get_func_call_count("BTM_ReadRemoteFeatures"));
373   ASSERT_EQ(1, get_func_call_count("PORT_WriteData"));
374   ASSERT_EQ(1, get_func_call_count("alarm_set_on_mloop"));
375   ASSERT_FALSE(p_scb->is_aptx_swb_codec);
376   ASSERT_EQ(p_scb->sco_codec, BTM_SCO_CODEC_MSBC);
377   ASSERT_TRUE(enable_aptx_voice_property(false));
378 }
379 
TEST_F(BtaAgScoTest,codec_negotiate__aptx_disabled)380 TEST_F(BtaAgScoTest, codec_negotiate__aptx_disabled) {
381   tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
382   p_scb->app_id = 0;
383   p_scb->peer_addr = addr;
384   p_scb->codec_negotiation_timer = alarm_new("bta_ag.scb_codec_negotiation_timer");
385   p_scb->peer_codecs = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK;
386   p_scb->is_aptx_swb_codec = true;
387   p_scb->codec_updated = true;
388 
389   ASSERT_TRUE(enable_aptx_voice_property(false));
390   ASSERT_EQ(BT_STATUS_FAIL, enable_aptx_swb_codec(false, &addr));
391   bta_ag_codec_negotiate(p_scb);
392   ASSERT_EQ(1, get_func_call_count("BTM_ReadRemoteFeatures"));
393   ASSERT_EQ(0, get_func_call_count("PORT_WriteData"));
394   ASSERT_EQ(0, get_func_call_count("alarm_set_on_mloop"));
395   ASSERT_FALSE(p_scb->codec_updated);
396 }
397