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 #include <gmock/gmock.h>
17 #include <gtest/gtest.h>
18 
19 #include <cstdint>
20 
21 #include "common/init_flags.h"
22 #include "hci/controller_interface_mock.h"
23 #include "stack/include/acl_api.h"
24 #include "stack/include/acl_hci_link_interface.h"
25 #include "stack/include/hci_error_code.h"
26 #include "test/common/mock_functions.h"
27 #include "test/mock/mock_main_shim_entry.h"
28 #include "types/raw_address.h"
29 
30 using testing::Return;
31 
32 namespace {
33 const char* test_flags[] = {
34     "INIT_default_log_level_str=LOG_DEBUG",
35     nullptr,
36 };
37 
38 const RawAddress kRawAddress = RawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
39 const uint16_t kHciHandle = 123;
40 
41 }  // namespace
42 
43 struct power_mode_callback {
44   const RawAddress bd_addr;
45   tBTM_PM_STATUS status;
46   uint16_t value;
47   tHCI_STATUS hci_status;
48 };
49 
50 #include <deque>
51 std::deque<power_mode_callback> power_mode_callback_queue;
52 
53 class StackBtmPowerMode : public testing::Test {
54  protected:
SetUp()55   void SetUp() override {
56     ON_CALL(controller_, SupportsSniffMode).WillByDefault(Return(true));
57     bluetooth::hci::testing::mock_controller_ = &controller_;
58     power_mode_callback_queue.clear();
59     reset_mock_function_count_map();
60     bluetooth::common::InitFlags::Load(test_flags);
61     ASSERT_EQ(BTM_SUCCESS,
62               BTM_PmRegister(BTM_PM_REG_SET, &pm_id_,
63                              [](const RawAddress& p_bda, tBTM_PM_STATUS status,
64                                 uint16_t value, tHCI_STATUS hci_status) {
65                                power_mode_callback_queue.push_back(
66                                    power_mode_callback{
67                                        .bd_addr = p_bda,
68                                        .status = status,
69                                        .value = value,
70                                        .hci_status = hci_status,
71                                    });
72                              }));
73   }
74 
TearDown()75   void TearDown() override {
76     ASSERT_EQ(BTM_SUCCESS,
77               BTM_PmRegister(
78                   BTM_PM_DEREG, &pm_id_,
79                   [](const RawAddress& /* p_bda */, tBTM_PM_STATUS /* status */,
80                      uint16_t /* value */, tHCI_STATUS /* hci_status */) {}));
81     bluetooth::hci::testing::mock_controller_ = nullptr;
82   }
83 
84   bluetooth::hci::testing::MockControllerInterface controller_;
85   uint8_t pm_id_{0};
86 };
87 
88 class StackBtmPowerModeConnected : public StackBtmPowerMode {
89  protected:
SetUp()90   void SetUp() override {
91     StackBtmPowerMode::SetUp();
92     BTM_PM_OnConnected(kHciHandle, kRawAddress);
93   }
94 
TearDown()95   void TearDown() override {
96     BTM_PM_OnDisconnected(kHciHandle);
97     StackBtmPowerMode::TearDown();
98   }
99 };
100 
TEST_F(StackBtmPowerMode,BTM_SetPowerMode__Undefined)101 TEST_F(StackBtmPowerMode, BTM_SetPowerMode__Undefined) {
102   tBTM_PM_PWR_MD mode = {};
103   ASSERT_EQ(BTM_UNKNOWN_ADDR, BTM_SetPowerMode(pm_id_, kRawAddress, &mode));
104 }
105 
TEST_F(StackBtmPowerModeConnected,BTM_SetPowerMode__AlreadyActive)106 TEST_F(StackBtmPowerModeConnected, BTM_SetPowerMode__AlreadyActive) {
107   tBTM_PM_PWR_MD mode = {};
108   ASSERT_EQ(BTM_SUCCESS, BTM_SetPowerMode(pm_id_, kRawAddress, &mode));
109 }
110 
TEST_F(StackBtmPowerModeConnected,BTM_SetPowerMode__ActiveToSniff)111 TEST_F(StackBtmPowerModeConnected, BTM_SetPowerMode__ActiveToSniff) {
112   tBTM_PM_PWR_MD mode = {
113       .mode = BTM_PM_MD_SNIFF,
114   };
115   ASSERT_EQ("BTM_CMD_STARTED",
116             btm_status_text(BTM_SetPowerMode(pm_id_, kRawAddress, &mode)));
117   ASSERT_EQ(1, get_func_call_count("btsnd_hcic_sniff_mode"));
118 
119   // Respond with successful command status for mode command
120   btm_pm_proc_cmd_status(HCI_SUCCESS);
121 
122   // Check power mode state directly
123   {
124     tBTM_PM_MODE current_power_mode;
125     ASSERT_TRUE(BTM_ReadPowerMode(kRawAddress, &current_power_mode));
126     ASSERT_EQ(BTM_PM_STS_PENDING, current_power_mode);
127   }
128 
129   // Check power mode state from callback
130   ASSERT_EQ(1U, power_mode_callback_queue.size());
131   {
132     const auto cb = power_mode_callback_queue.front();
133     power_mode_callback_queue.pop_front();
134 
135     ASSERT_EQ(kRawAddress, cb.bd_addr);
136     ASSERT_EQ(BTM_PM_STS_PENDING, cb.status);
137     ASSERT_EQ(0, cb.value);
138     ASSERT_EQ(HCI_SUCCESS, cb.hci_status);
139   }
140 
141   // Respond with a successful mode change event
142   btm_pm_proc_mode_change(HCI_SUCCESS, kHciHandle, HCI_MODE_SNIFF, 0);
143 
144   {
145     tBTM_PM_MODE current_power_mode;
146     ASSERT_TRUE(BTM_ReadPowerMode(kRawAddress, &current_power_mode));
147     ASSERT_EQ(BTM_PM_STS_SNIFF, current_power_mode);
148   }
149 
150   // Check power mode state from callback
151   ASSERT_EQ(1U, power_mode_callback_queue.size());
152   {
153     const auto cb = power_mode_callback_queue.front();
154     power_mode_callback_queue.pop_front();
155 
156     ASSERT_EQ(kRawAddress, cb.bd_addr);
157     ASSERT_EQ(BTM_PM_STS_SNIFF, cb.status);
158     ASSERT_EQ(0, cb.value);
159     ASSERT_EQ(HCI_SUCCESS, cb.hci_status);
160   }
161 }
162 
TEST_F(StackBtmPowerModeConnected,BTM_SetPowerMode__ActiveToSniffTwice)163 TEST_F(StackBtmPowerModeConnected, BTM_SetPowerMode__ActiveToSniffTwice) {
164   tBTM_PM_PWR_MD mode = {
165       .mode = BTM_PM_MD_SNIFF,
166   };
167   ASSERT_EQ("BTM_CMD_STARTED",
168             btm_status_text(BTM_SetPowerMode(pm_id_, kRawAddress, &mode)));
169   ASSERT_EQ(1, get_func_call_count("btsnd_hcic_sniff_mode"));
170 
171   // Respond with successful command status for mode command
172   btm_pm_proc_cmd_status(HCI_SUCCESS);
173 
174   // Check power mode state directly
175   {
176     tBTM_PM_MODE current_power_mode;
177     ASSERT_TRUE(BTM_ReadPowerMode(kRawAddress, &current_power_mode));
178     ASSERT_EQ(BTM_PM_STS_PENDING, current_power_mode);
179   }
180 
181   // Check power mode state from callback
182   ASSERT_EQ(1U, power_mode_callback_queue.size());
183   {
184     const auto cb = power_mode_callback_queue.front();
185     power_mode_callback_queue.pop_front();
186 
187     ASSERT_EQ(kRawAddress, cb.bd_addr);
188     ASSERT_EQ(BTM_PM_STS_PENDING, cb.status);
189     ASSERT_EQ(0, cb.value);
190     ASSERT_EQ(HCI_SUCCESS, cb.hci_status);
191   }
192 
193   // Send a second active to sniff command
194   ASSERT_EQ("BTM_CMD_STORED",
195             btm_status_text(BTM_SetPowerMode(pm_id_, kRawAddress, &mode)));
196   // No command should be issued
197   ASSERT_EQ(1, get_func_call_count("btsnd_hcic_sniff_mode"));
198 
199   // Check power mode state directly
200   {
201     tBTM_PM_MODE current_power_mode;
202     ASSERT_TRUE(BTM_ReadPowerMode(kRawAddress, &current_power_mode));
203     // NOTE: The mixed enum values
204     ASSERT_EQ(
205         static_cast<tBTM_PM_MODE>(BTM_PM_STS_PENDING | BTM_PM_STORED_MASK),
206         current_power_mode);
207   }
208 }
209