blob: 618db74685518cafa8a8f5aaa061489c05110f16 [file] [log] [blame] [edit]
// Copyright 2024, 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.
use crate::{HciHal, HciHalStatus};
use android_hardware_bluetooth::aidl::android::hardware::bluetooth::IBluetoothHci::IBluetoothHci;
use android_hardware_bluetooth::aidl::android::hardware::bluetooth::IBluetoothHciCallbacks::IBluetoothHciCallbacks;
use android_hardware_bluetooth::aidl::android::hardware::bluetooth::Status::Status;
use binder::{DeathRecipient, ExceptionCode, IBinder, Interface, Result as BinderResult, Strong};
use bluetooth_offload_hci::{Module, ModuleBuilder};
use core::ffi::CStr;
use std::io::Write;
use std::sync::{Arc, RwLock};
/// Service Implementation of AIDL interface `hardware/interface/bluetoot/aidl`,
/// including a proxy interface usable by third party modules.
pub struct HciProxy<T: HciHal> {
modules: Vec<Box<dyn ModuleBuilder>>,
ffi: Arc<T>,
state: Arc<RwLock<State>>,
}
/// Callbacks Proxy, from the HAL to the AIDL interface
pub struct HciProxyCallbacks {
callbacks: Strong<dyn IBluetoothHciCallbacks>,
proxy: Arc<dyn Module>,
state: Arc<RwLock<State>>,
}
struct SinkModule<T: HciHal> {
ffi: Arc<T>,
callbacks: Strong<dyn IBluetoothHciCallbacks>,
}
enum State {
Closed,
Opened { proxy: Arc<dyn Module>, _death_recipient: DeathRecipient },
}
impl<T: HciHal> HciProxy<T> {
/// Create the HAL Proxy interface binded to the Bluetooth HCI HAL interface.
pub fn new(modules: Vec<Box<dyn ModuleBuilder>>, hal: T) -> Self {
Self { modules, ffi: Arc::new(hal), state: Arc::new(RwLock::new(State::Closed)) }
}
}
impl<T: HciHal + 'static> Interface for HciProxy<T> {
fn dump(&self, writer: &mut dyn Write, args: &[&CStr]) -> Result<(), binder::StatusCode> {
// SAFETY: The writer, coming from binder, is backed by a concrete File type.
unsafe {
self.ffi.dump(writer, args);
}
Ok(())
}
}
impl<T: HciHal + 'static> IBluetoothHci for HciProxy<T> {
fn initialize(&self, callbacks: &Strong<dyn IBluetoothHciCallbacks>) -> BinderResult<()> {
let (ffi, callbacks) = {
let mut state = self.state.write().unwrap();
if !matches!(*state, State::Closed) {
let _ = callbacks.initializationComplete(Status::ALREADY_INITIALIZED);
return Ok(());
}
let mut proxy: Arc<dyn Module> =
Arc::new(SinkModule::new(self.ffi.clone(), callbacks.clone()));
for m in self.modules.iter().rev() {
proxy = m.build(proxy);
}
let mut death_recipient = {
let (ffi, state) = (self.ffi.clone(), self.state.clone());
DeathRecipient::new(move || {
log::info!("Bluetooth stack has died");
let mut state = state.write().unwrap();
ffi.client_died();
*state = State::Closed;
})
};
callbacks.as_binder().link_to_death(&mut death_recipient)?;
*state = State::Opened { proxy: proxy.clone(), _death_recipient: death_recipient };
(
self.ffi.clone(),
HciProxyCallbacks::new(callbacks.clone(), proxy.clone(), self.state.clone()),
)
};
ffi.initialize(callbacks);
Ok(())
}
fn close(&self) -> BinderResult<()> {
*self.state.write().unwrap() = State::Closed;
self.ffi.close();
Ok(())
}
fn sendHciCommand(&self, data: &[u8]) -> BinderResult<()> {
let State::Opened { ref proxy, .. } = *self.state.read().unwrap() else {
return Err(ExceptionCode::ILLEGAL_STATE.into());
};
proxy.out_cmd(data);
Ok(())
}
fn sendAclData(&self, data: &[u8]) -> BinderResult<()> {
let State::Opened { ref proxy, .. } = *self.state.read().unwrap() else {
return Err(ExceptionCode::ILLEGAL_STATE.into());
};
proxy.out_acl(data);
Ok(())
}
fn sendScoData(&self, data: &[u8]) -> BinderResult<()> {
let State::Opened { ref proxy, .. } = *self.state.read().unwrap() else {
return Err(ExceptionCode::ILLEGAL_STATE.into());
};
proxy.out_sco(data);
Ok(())
}
fn sendIsoData(&self, data: &[u8]) -> BinderResult<()> {
let State::Opened { ref proxy, .. } = *self.state.read().unwrap() else {
return Err(ExceptionCode::ILLEGAL_STATE.into());
};
proxy.out_iso(data);
Ok(())
}
}
impl<T: HciHal> SinkModule<T> {
pub(crate) fn new(ffi: Arc<T>, callbacks: Strong<dyn IBluetoothHciCallbacks>) -> Self {
Self { ffi, callbacks }
}
}
impl<T: HciHal> Module for SinkModule<T> {
fn next(&self) -> &dyn Module {
unreachable!()
}
fn out_cmd(&self, data: &[u8]) {
self.ffi.send_command(data);
}
fn out_acl(&self, data: &[u8]) {
self.ffi.send_acl(data);
}
fn out_iso(&self, data: &[u8]) {
self.ffi.send_iso(data);
}
fn out_sco(&self, data: &[u8]) {
self.ffi.send_sco(data);
}
fn in_evt(&self, data: &[u8]) {
if let Err(e) = self.callbacks.hciEventReceived(data) {
log::error!("Cannot send event to client: {e:?}");
}
}
fn in_acl(&self, data: &[u8]) {
if let Err(e) = self.callbacks.aclDataReceived(data) {
log::error!("Cannot send ACL to client: {e:?}");
}
}
fn in_sco(&self, data: &[u8]) {
if let Err(e) = self.callbacks.scoDataReceived(data) {
log::error!("Cannot send SCO to client: {e:?}");
}
}
fn in_iso(&self, data: &[u8]) {
if let Err(e) = self.callbacks.isoDataReceived(data) {
log::error!("Cannot send ISO to client: {e:?}");
}
}
}
#[allow(missing_docs)]
impl HciProxyCallbacks {
fn new(
callbacks: Strong<dyn IBluetoothHciCallbacks>,
proxy: Arc<dyn Module>,
state: Arc<RwLock<State>>,
) -> Self {
Self { callbacks, proxy, state }
}
pub fn initialization_complete(&self, status: HciHalStatus) {
let mut state = self.state.write().unwrap();
if status != HciHalStatus::Success {
*state = State::Closed;
}
if let Err(e) = self.callbacks.initializationComplete(status.into()) {
log::error!("Cannot call-back client: {e:?}");
*state = State::Closed;
}
}
pub fn event_received(&self, data: &[u8]) {
self.proxy.in_evt(data);
}
pub fn acl_received(&self, data: &[u8]) {
self.proxy.in_acl(data);
}
pub fn sco_received(&self, data: &[u8]) {
self.proxy.in_sco(data);
}
pub fn iso_received(&self, data: &[u8]) {
self.proxy.in_iso(data);
}
}
impl From<HciHalStatus> for Status {
fn from(value: HciHalStatus) -> Self {
match value {
HciHalStatus::Success => Status::SUCCESS,
HciHalStatus::AlreadyInitialized => Status::ALREADY_INITIALIZED,
HciHalStatus::UnableToOpenInterface => Status::UNABLE_TO_OPEN_INTERFACE,
HciHalStatus::HardwareInitializationError => Status::HARDWARE_INITIALIZATION_ERROR,
HciHalStatus::Unknown => Status::UNKNOWN,
}
}
}