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