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