Myles Watson | 6d5e772 | 2022-09-30 06:22:43 -0700 | [diff] [blame] | 1 | /* |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 2 | * Copyright 2022 The Android Open Source Project |
Myles Watson | 6d5e772 | 2022-09-30 06:22:43 -0700 | [diff] [blame] | 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 | #define LOG_TAG "android.hardware.bluetooth.service.default" |
| 18 | |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 19 | #include "BluetoothHci.h" |
| 20 | |
Myles Watson | 6d5e772 | 2022-09-30 06:22:43 -0700 | [diff] [blame] | 21 | #include <cutils/properties.h> |
| 22 | #include <fcntl.h> |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 23 | #include <netdb.h> |
| 24 | #include <netinet/in.h> |
| 25 | #include <poll.h> |
Myles Watson | 6d5e772 | 2022-09-30 06:22:43 -0700 | [diff] [blame] | 26 | #include <string.h> |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 27 | #include <sys/uio.h> |
Myles Watson | 6d5e772 | 2022-09-30 06:22:43 -0700 | [diff] [blame] | 28 | #include <termios.h> |
| 29 | |
| 30 | #include "log/log.h" |
| 31 | |
| 32 | namespace { |
| 33 | int SetTerminalRaw(int fd) { |
| 34 | termios terminal_settings; |
| 35 | int rval = tcgetattr(fd, &terminal_settings); |
| 36 | if (rval < 0) { |
| 37 | return rval; |
| 38 | } |
| 39 | cfmakeraw(&terminal_settings); |
| 40 | rval = tcsetattr(fd, TCSANOW, &terminal_settings); |
| 41 | return rval; |
| 42 | } |
| 43 | } // namespace |
| 44 | |
| 45 | using namespace ::android::hardware::bluetooth::hci; |
| 46 | using namespace ::android::hardware::bluetooth::async; |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 47 | using aidl::android::hardware::bluetooth::hal::Status; |
Myles Watson | 6d5e772 | 2022-09-30 06:22:43 -0700 | [diff] [blame] | 48 | |
| 49 | namespace aidl::android::hardware::bluetooth::impl { |
| 50 | |
Henri Chataing | 1267ff2 | 2023-08-09 22:38:24 +0000 | [diff] [blame] | 51 | std::optional<std::string> GetSystemProperty(const std::string& property) { |
| 52 | std::array<char, PROPERTY_VALUE_MAX> value_array{0}; |
| 53 | auto value_len = property_get(property.c_str(), value_array.data(), nullptr); |
| 54 | if (value_len <= 0) { |
| 55 | return std::nullopt; |
| 56 | } |
| 57 | return std::string(value_array.data(), value_len); |
| 58 | } |
| 59 | |
| 60 | bool starts_with(const std::string& str, const std::string& prefix) { |
| 61 | return str.compare(0, prefix.length(), prefix) == 0; |
| 62 | } |
| 63 | |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 64 | BluetoothHci::BluetoothHci(const std::string& dev_path) { |
| 65 | char property_bytes[PROPERTY_VALUE_MAX]; |
| 66 | property_get("vendor.ser.bt-uart", property_bytes, dev_path.c_str()); |
| 67 | mDevPath = std::string(property_bytes); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | int BluetoothHci::getFdFromDevPath() { |
| 71 | int fd = open(mDevPath.c_str(), O_RDWR); |
| 72 | if (fd < 0) { |
| 73 | ALOGE("Could not connect to bt: %s (%s)", mDevPath.c_str(), |
| 74 | strerror(errno)); |
| 75 | return fd; |
| 76 | } |
| 77 | if (int ret = SetTerminalRaw(fd) < 0) { |
| 78 | ALOGI("Could not make %s a raw terminal %d(%s)", mDevPath.c_str(), ret, |
| 79 | strerror(errno)); |
| 80 | } |
| 81 | return fd; |
| 82 | } |
| 83 | |
| 84 | void BluetoothHci::reset() { |
| 85 | // Send a reset command and wait until the command complete comes back. |
| 86 | |
| 87 | std::vector<uint8_t> reset = {0x03, 0x0c, 0x00}; |
| 88 | |
| 89 | auto resetPromise = std::make_shared<std::promise<void>>(); |
| 90 | auto resetFuture = resetPromise->get_future(); |
| 91 | |
| 92 | mH4 = std::make_shared<H4Protocol>( |
| 93 | mFd, |
| 94 | [](const std::vector<uint8_t>& raw_command) { |
| 95 | ALOGI("Discarding %d bytes with command type", |
| 96 | static_cast<int>(raw_command.size())); |
| 97 | }, |
| 98 | [](const std::vector<uint8_t>& raw_acl) { |
| 99 | ALOGI("Discarding %d bytes with acl type", |
| 100 | static_cast<int>(raw_acl.size())); |
| 101 | }, |
| 102 | [](const std::vector<uint8_t>& raw_sco) { |
| 103 | ALOGI("Discarding %d bytes with sco type", |
| 104 | static_cast<int>(raw_sco.size())); |
| 105 | }, |
| 106 | [resetPromise](const std::vector<uint8_t>& raw_event) { |
| 107 | std::vector<uint8_t> reset_complete = {0x0e, 0x04, 0x01, |
| 108 | 0x03, 0x0c, 0x00}; |
| 109 | bool valid = raw_event.size() == 6 && |
| 110 | raw_event[0] == reset_complete[0] && |
| 111 | raw_event[1] == reset_complete[1] && |
| 112 | // Don't compare the number of packets field. |
| 113 | raw_event[3] == reset_complete[3] && |
| 114 | raw_event[4] == reset_complete[4] && |
| 115 | raw_event[5] == reset_complete[5]; |
| 116 | if (valid) { |
| 117 | resetPromise->set_value(); |
| 118 | } else { |
| 119 | ALOGI("Discarding %d bytes with event type", |
| 120 | static_cast<int>(raw_event.size())); |
| 121 | } |
| 122 | }, |
| 123 | [](const std::vector<uint8_t>& raw_iso) { |
| 124 | ALOGI("Discarding %d bytes with iso type", |
| 125 | static_cast<int>(raw_iso.size())); |
| 126 | }, |
| 127 | [this]() { |
| 128 | ALOGI("HCI socket device disconnected while waiting for reset"); |
| 129 | mFdWatcher.StopWatchingFileDescriptors(); |
| 130 | }); |
| 131 | mFdWatcher.WatchFdForNonBlockingReads(mFd, |
| 132 | [this](int) { mH4->OnDataReady(); }); |
| 133 | |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 134 | send(PacketType::COMMAND, reset); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 135 | auto status = resetFuture.wait_for(std::chrono::seconds(1)); |
| 136 | mFdWatcher.StopWatchingFileDescriptors(); |
| 137 | if (status == std::future_status::ready) { |
| 138 | ALOGI("HCI Reset successful"); |
| 139 | } else { |
| 140 | ALOGE("HCI Reset Response not received in one second"); |
| 141 | } |
| 142 | |
| 143 | resetPromise.reset(); |
| 144 | } |
| 145 | |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 146 | void BluetoothHci::initialize( |
| 147 | const std::shared_ptr<hal::IBluetoothHciCallbacks>& cb) { |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 148 | ALOGI(__func__); |
| 149 | |
| 150 | if (cb == nullptr) { |
| 151 | ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)"); |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 152 | abort(); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | HalState old_state = HalState::READY; |
| 156 | { |
| 157 | std::lock_guard<std::mutex> guard(mStateMutex); |
| 158 | if (mState != HalState::READY) { |
| 159 | old_state = mState; |
| 160 | } else { |
| 161 | mState = HalState::INITIALIZING; |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | if (old_state != HalState::READY) { |
| 166 | ALOGE("initialize: Unexpected State %d", static_cast<int>(old_state)); |
| 167 | close(); |
| 168 | cb->initializationComplete(Status::ALREADY_INITIALIZED); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | mCb = cb; |
| 172 | management_.reset(new NetBluetoothMgmt); |
| 173 | mFd = management_->openHci(); |
| 174 | if (mFd < 0) { |
| 175 | management_.reset(); |
| 176 | |
| 177 | ALOGI("Unable to open Linux interface, trying default path."); |
| 178 | mFd = getFdFromDevPath(); |
| 179 | if (mFd < 0) { |
| 180 | mState = HalState::READY; |
| 181 | cb->initializationComplete(Status::UNABLE_TO_OPEN_INTERFACE); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 182 | } |
| 183 | } |
| 184 | |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 185 | // TODO: HCI Reset on emulators since the bluetooth controller |
| 186 | // cannot be powered on/off during the HAL setup; and the stack |
| 187 | // might received spurious packets/events during boottime. |
| 188 | // Proper solution would be to use bt-virtio or vsock to better |
| 189 | // control the link to rootcanal and the controller lifetime. |
| 190 | const std::string kBoardProperty = "ro.product.board"; |
| 191 | const std::string kCuttlefishBoard = "cutf"; |
| 192 | auto board_name = GetSystemProperty(kBoardProperty); |
| 193 | if (board_name.has_value() && ( |
| 194 | starts_with(board_name.value(), "cutf") || |
| 195 | starts_with(board_name.value(), "goldfish"))) { |
| 196 | reset(); |
| 197 | } |
| 198 | |
| 199 | mH4 = std::make_shared<H4Protocol>( |
| 200 | mFd, |
| 201 | [](const std::vector<uint8_t>& /* raw_command */) { |
| 202 | LOG_ALWAYS_FATAL("Unexpected command!"); |
| 203 | }, |
| 204 | [this](const std::vector<uint8_t>& raw_acl) { |
| 205 | mCb->aclDataReceived(raw_acl); |
| 206 | }, |
| 207 | [this](const std::vector<uint8_t>& raw_sco) { |
| 208 | mCb->scoDataReceived(raw_sco); |
| 209 | }, |
| 210 | [this](const std::vector<uint8_t>& raw_event) { |
| 211 | mCb->hciEventReceived(raw_event); |
| 212 | }, |
| 213 | [this](const std::vector<uint8_t>& raw_iso) { |
| 214 | mCb->isoDataReceived(raw_iso); |
| 215 | }, |
| 216 | [this]() { |
| 217 | ALOGI("HCI socket device disconnected"); |
| 218 | mFdWatcher.StopWatchingFileDescriptors(); |
| 219 | }); |
| 220 | mFdWatcher.WatchFdForNonBlockingReads(mFd, |
| 221 | [this](int) { mH4->OnDataReady(); }); |
| 222 | |
| 223 | { |
| 224 | std::lock_guard<std::mutex> guard(mStateMutex); |
| 225 | mState = HalState::ONE_CLIENT; |
| 226 | } |
| 227 | ALOGI("initialization complete"); |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 228 | mCb->initializationComplete(Status::SUCCESS); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 229 | } |
| 230 | |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 231 | void BluetoothHci::close() { |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 232 | ALOGI(__func__); |
| 233 | { |
| 234 | std::lock_guard<std::mutex> guard(mStateMutex); |
| 235 | if (mState != HalState::ONE_CLIENT) { |
| 236 | LOG_ALWAYS_FATAL_IF(mState == HalState::INITIALIZING, |
| 237 | "mState is INITIALIZING"); |
| 238 | ALOGI("Already closed"); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 239 | } |
| 240 | mState = HalState::CLOSING; |
| 241 | } |
| 242 | |
| 243 | mFdWatcher.StopWatchingFileDescriptors(); |
| 244 | |
| 245 | if (management_) { |
| 246 | management_->closeHci(); |
| 247 | } else { |
| 248 | ::close(mFd); |
| 249 | } |
| 250 | |
| 251 | { |
| 252 | std::lock_guard<std::mutex> guard(mStateMutex); |
| 253 | mState = HalState::READY; |
| 254 | mH4 = nullptr; |
| 255 | } |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 256 | } |
| 257 | |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 258 | void BluetoothHci::clientDied() { |
| 259 | ALOGI(__func__); |
| 260 | close(); |
| 261 | } |
| 262 | |
| 263 | void BluetoothHci::sendHciCommand(const std::vector<uint8_t>& packet) { |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 264 | return send(PacketType::COMMAND, packet); |
| 265 | } |
| 266 | |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 267 | void BluetoothHci::sendAclData(const std::vector<uint8_t>& packet) { |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 268 | return send(PacketType::ACL_DATA, packet); |
| 269 | } |
| 270 | |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 271 | void BluetoothHci::sendScoData(const std::vector<uint8_t>& packet) { |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 272 | return send(PacketType::SCO_DATA, packet); |
| 273 | } |
| 274 | |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 275 | void BluetoothHci::sendIsoData(const std::vector<uint8_t>& packet) { |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 276 | return send(PacketType::ISO_DATA, packet); |
| 277 | } |
| 278 | |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 279 | void BluetoothHci::send(PacketType type, const std::vector<uint8_t>& v) { |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 280 | if (v.empty()) { |
| 281 | ALOGE("Packet is empty, no data was found to be sent"); |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 282 | abort(); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 283 | } |
| 284 | |
| 285 | std::lock_guard<std::mutex> guard(mStateMutex); |
| 286 | if (mH4 == nullptr) { |
Antoine SOULIER | 35fef7c | 2025-02-26 23:01:21 +0000 | [diff] [blame] | 287 | ALOGE("Illegal State"); |
| 288 | abort(); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 289 | } |
| 290 | |
| 291 | mH4->Send(type, v); |
Antoine SOULIER | f0d56e8 | 2025-02-26 17:35:45 +0000 | [diff] [blame] | 292 | } |
| 293 | |
Myles Watson | 6d5e772 | 2022-09-30 06:22:43 -0700 | [diff] [blame] | 294 | } // namespace aidl::android::hardware::bluetooth::impl |