blob: d041af75894221cc2b603e7612215b03cfbf89ae [file] [log] [blame]
//
// Copyright 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#define LOG_TAG "android.hardware.bluetooth@1.1.remote"
#include "remote_bluetooth.h"
#include <cutils/properties.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <poll.h>
#include <string.h>
#include <sys/uio.h>
#include <termios.h>
#include <utils/Log.h>
#include "log/log.h"
namespace {
int SetTerminalRaw(int fd) {
termios terminal_settings;
int rval = tcgetattr(fd, &terminal_settings);
if (rval < 0) {
return rval;
}
cfmakeraw(&terminal_settings);
rval = tcsetattr(fd, TCSANOW, &terminal_settings);
return rval;
}
} // namespace
namespace android {
namespace hardware {
namespace bluetooth {
namespace V1_1 {
namespace remote {
using ::android::hardware::hidl_vec;
class BluetoothDeathRecipient : public hidl_death_recipient {
public:
BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
void serviceDied(
uint64_t /* cookie */,
const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
LOG(ERROR)
<< "BluetoothDeathRecipient::serviceDied - Bluetooth service died";
has_died_ = true;
mHci->close();
}
sp<IBluetoothHci> mHci;
bool getHasDied() const { return has_died_; }
void setHasDied(bool has_died) { has_died_ = has_died; }
private:
bool has_died_;
};
BluetoothHci::BluetoothHci(const std::string& dev_path)
: death_recipient_(new BluetoothDeathRecipient(this)),
dev_path_(dev_path) {}
Return<void> BluetoothHci::initialize(
const sp<V1_0::IBluetoothHciCallbacks>& cb) {
return initialize_impl(cb, nullptr);
}
Return<void> BluetoothHci::initialize_1_1(
const sp<V1_1::IBluetoothHciCallbacks>& cb) {
return initialize_impl(cb, cb);
}
Return<void> BluetoothHci::initialize_impl(
const sp<V1_0::IBluetoothHciCallbacks>& cb,
const sp<V1_1::IBluetoothHciCallbacks>& cb_1_1) {
LOG(INFO) << __func__;
cb_ = cb;
cb_1_1_ = cb_1_1;
fd_ = open(dev_path_.c_str(), O_RDWR);
if (fd_ < 0) {
LOG(FATAL) << "Could not connect to bt: " << fd_;
}
if (int ret = SetTerminalRaw(fd_) < 0) {
LOG(FATAL) << "Could not make " << fd_ << " a raw terminal: " << ret;
}
if (cb == nullptr) {
LOG(ERROR)
<< "cb == nullptr! -> Unable to call initializationComplete(ERR)";
return Void();
}
death_recipient_->setHasDied(false);
auto link_ret = cb->linkToDeath(death_recipient_, 0);
unlink_cb_ = [this, cb](sp<BluetoothDeathRecipient>& death_recipient) {
if (death_recipient->getHasDied())
LOG(INFO) << "Skipping unlink call, service died.";
else {
auto ret = cb->unlinkToDeath(death_recipient);
if (!ret.isOk()) {
CHECK(death_recipient_->getHasDied())
<< "Error calling unlink, but no death notification.";
}
}
};
auto init_ret = cb->initializationComplete(V1_0::Status::SUCCESS);
if (!init_ret.isOk()) {
CHECK(death_recipient_->getHasDied())
<< "Error sending init callback, but no death notification.";
}
h4_ = rootcanal::H4Packetizer(
fd_,
[](const std::vector<uint8_t>& /* raw_command */) {
LOG_ALWAYS_FATAL("Unexpected command!");
},
[this](const std::vector<uint8_t>& raw_event) {
cb_->hciEventReceived(hidl_vec<uint8_t>(raw_event));
},
[this](const std::vector<uint8_t>& raw_acl) {
cb_->hciEventReceived(hidl_vec<uint8_t>(raw_acl));
},
[this](const std::vector<uint8_t>& raw_sco) {
cb_->hciEventReceived(hidl_vec<uint8_t>(raw_sco));
},
[this](const std::vector<uint8_t>& raw_iso) {
if (cb_1_1_) {
cb_1_1_->hciEventReceived(hidl_vec<uint8_t>(raw_iso));
}
},
[]() { LOG(INFO) << "HCI socket device disconnected"; });
fd_watcher_.WatchFdForNonBlockingReads(
fd_, [this](int fd) { h4_.OnDataReady(fd); });
return Void();
}
Return<void> BluetoothHci::close() {
LOG(INFO) << __func__;
fd_watcher_.StopWatchingFileDescriptors();
::close(fd_);
return Void();
}
Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& packet) {
send(rootcanal::PacketType::COMMAND, packet);
return Void();
}
Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& packet) {
send(rootcanal::PacketType::ACL, packet);
return Void();
}
Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& packet) {
send(rootcanal::PacketType::SCO, packet);
return Void();
}
Return<void> BluetoothHci::sendIsoData(const hidl_vec<uint8_t>& packet) {
send(rootcanal::PacketType::ISO, packet);
return Void();
}
void BluetoothHci::send(rootcanal::PacketType type,
const ::android::hardware::hidl_vec<uint8_t>& v) {
h4_.Send(static_cast<uint8_t>(type), v.data(), v.size());
}
/* Fallback to shared library if there is no service. */
IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* /* name */) {
return new BluetoothHci();
}
} // namespace remote
} // namespace V1_1
} // namespace bluetooth
} // namespace hardware
} // namespace android