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, ¤t_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, ¤t_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, ¤t_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, ¤t_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