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 #pragma once 18 19 #define LOG_TAG "bt_headless_mode" 20 21 #include <bluetooth/log.h> 22 23 #include <future> 24 #include <mutex> 25 26 #include "bta/dm/bta_dm_int.h" 27 #include "stack/include/btm_client_interface.h" 28 #include "stack/include/btm_status.h" 29 #include "stack/include/hci_error_code.h" 30 #include "types/raw_address.h" 31 32 using namespace std::chrono_literals; 33 using namespace bluetooth; 34 35 namespace { 36 const tBTM_PM_PWR_MD default_mandatory_sniff_mode = { 37 .max = 0x0006, 38 .min = 0x0006, 39 .attempt = 0x0020, 40 .timeout = 0x7fff, 41 .mode = BTM_PM_MD_SNIFF, 42 }; 43 44 const tBTM_PM_PWR_MD typical_sniff_mode = { 45 .max = 800, // 5 seconds 46 .min = 400, // 2.5 seconds 47 .attempt = 4, 48 .timeout = 1, 49 .mode = BTM_PM_MD_SNIFF, 50 }; 51 52 const tBTM_PM_PWR_MD default_active_mode = { 53 .max = 0, // Unused 54 .min = 0, // Unused 55 .attempt = 0, // Unused 56 .timeout = 0, // Unused 57 .mode = BTM_PM_MD_ACTIVE, 58 }; 59 } // namespace 60 61 // tBTM_PM_STATUS_CBACK 62 struct power_mode_callback_t { 63 const RawAddress bd_addr; 64 tBTM_PM_STATUS status; 65 uint16_t value; 66 tHCI_STATUS hci_status; 67 ToStringpower_mode_callback_t68 std::string ToString() const { 69 return std::format("bd_addr:{} pm_status:{} value:{} hci_status:{}", bd_addr.ToString(), 70 power_mode_status_text(status), value, hci_status_code_text(hci_status)); 71 } 72 }; 73 74 struct pwr_command_t { 75 std::promise<power_mode_callback_t> cmd_status_promise; 76 std::promise<power_mode_callback_t> mode_event_promise; 77 }; 78 79 struct pwr_result_t { 80 tBTM_STATUS btm_status; 81 std::future<power_mode_callback_t> cmd_status_future; 82 std::future<power_mode_callback_t> mode_event_future; 83 }; 84 85 namespace { 86 87 class Queue { 88 public: CallbackReceived(const power_mode_callback_t & data)89 void CallbackReceived(const power_mode_callback_t& data) { 90 log::info("Power mode callback cnt:{} data:{}", cnt++, data.ToString()); 91 std::unique_lock<std::mutex> lk(mutex); 92 if (promises_map_[data.bd_addr].empty()) { 93 log::info("Received unsolicited power mode callback: {}", data.ToString()); 94 return; 95 } 96 promises_map_[data.bd_addr].front().set_value(data); 97 promises_map_[data.bd_addr].pop_front(); 98 } 99 CommandSent(const RawAddress & bd_addr,pwr_command_t && pwr_command)100 void CommandSent(const RawAddress& bd_addr, pwr_command_t&& pwr_command) { 101 std::unique_lock<std::mutex> lk(mutex); 102 promises_map_[bd_addr].push_back(std::move(pwr_command.cmd_status_promise)); 103 promises_map_[bd_addr].push_back(std::move(pwr_command.mode_event_promise)); 104 } 105 PopFront(const RawAddress & bd_addr)106 void PopFront(const RawAddress& bd_addr) { 107 std::unique_lock<std::mutex> lk(mutex); 108 log::assert_that(!promises_map_[bd_addr].empty(), 109 "Unable to remove promise from empty bag of promises"); 110 promises_map_[bd_addr].pop_front(); 111 } 112 113 private: 114 mutable std::mutex mutex; 115 std::unordered_map<RawAddress, std::deque<std::promise<power_mode_callback_t>>> promises_map_; 116 size_t cnt = 0; 117 } queue_; 118 119 } // namespace 120 121 class PowerMode { 122 public: 123 class Client { 124 public: Client(const uint8_t pm_id,const RawAddress & bd_addr)125 Client(const uint8_t pm_id, const RawAddress& bd_addr) : pm_id_(pm_id), bd_addr_(bd_addr) {} 126 127 // Used when the power mode command status is unsuccessful 128 // to prevent waiting for a mode event that will never arrive. 129 // Exposed to allow testing of these conditions. remove_mode_event_promise()130 void remove_mode_event_promise() { queue_.PopFront(bd_addr_); } 131 set_sniff(pwr_command_t && pwr_command)132 pwr_result_t set_sniff(pwr_command_t&& pwr_command) { 133 return send_power_mode_command(std::move(pwr_command), 134 get_btm_client_interface().link_policy.BTM_SetPowerMode( 135 pm_id_, bd_addr_, &default_mandatory_sniff_mode)); 136 } set_typical_sniff(pwr_command_t && pwr_command)137 pwr_result_t set_typical_sniff(pwr_command_t&& pwr_command) { 138 return send_power_mode_command(std::move(pwr_command), 139 get_btm_client_interface().link_policy.BTM_SetPowerMode( 140 pm_id_, bd_addr_, &typical_sniff_mode)); 141 } 142 set_active(pwr_command_t && pwr_command)143 pwr_result_t set_active(pwr_command_t&& pwr_command) { 144 return send_power_mode_command(std::move(pwr_command), 145 get_btm_client_interface().link_policy.BTM_SetPowerMode( 146 pm_id_, bd_addr_, &default_active_mode)); 147 } 148 149 private: send_power_mode_command(pwr_command_t && pwr_command,const tBTM_STATUS btm_status)150 pwr_result_t send_power_mode_command(pwr_command_t&& pwr_command, 151 const tBTM_STATUS btm_status) { 152 pwr_result_t result = { 153 .btm_status = btm_status, 154 .cmd_status_future = pwr_command.cmd_status_promise.get_future(), 155 .mode_event_future = pwr_command.mode_event_promise.get_future(), 156 }; 157 queue_.CommandSent(bd_addr_, std::move(pwr_command)); 158 return result; 159 } 160 161 const uint8_t pm_id_; 162 const RawAddress bd_addr_; 163 }; 164 PowerMode()165 PowerMode() { 166 BTM_PmRegister( 167 BTM_PM_DEREG, &bta_dm_cb.pm_id, 168 []([[maybe_unused]] const RawAddress& bd_addr, [[maybe_unused]] tBTM_PM_STATUS status, 169 [[maybe_unused]] uint16_t value, [[maybe_unused]] tHCI_STATUS hci_status) {}); 170 171 tBTM_STATUS btm_status = get_btm_client_interface().lifecycle.BTM_PmRegister( 172 BTM_PM_REG_SET, &pm_id_, 173 [](const RawAddress& bd_addr, tBTM_PM_STATUS status, uint16_t value, 174 tHCI_STATUS hci_status) { 175 queue_.CallbackReceived(power_mode_callback_t{ 176 .bd_addr = bd_addr, 177 .status = status, 178 .value = value, 179 .hci_status = hci_status, 180 }); 181 }); 182 183 log::assert_that(tBTM_STATUS::BTM_SUCCESS == btm_status, "Failed to register power mode:{}", 184 btm_status_text(btm_status)); 185 } 186 ~PowerMode()187 ~PowerMode() { 188 auto status = get_btm_client_interface().lifecycle.BTM_PmRegister( 189 BTM_PM_DEREG, &pm_id_, 190 []([[maybe_unused]] const RawAddress& bd_addr, [[maybe_unused]] tBTM_PM_STATUS status, 191 [[maybe_unused]] uint16_t value, [[maybe_unused]] tHCI_STATUS hci_status) {}); 192 log::assert_that(tBTM_STATUS::BTM_SUCCESS == status, "assert failed: BTM_SUCCESS == status"); 193 } 194 GetClient(const RawAddress bd_addr)195 Client GetClient(const RawAddress bd_addr) { return Client(pm_id_, bd_addr); } 196 197 private: 198 uint8_t pm_id_; 199 }; 200