作者:张彬 润开鸿
1. 前言
由于OH开源社区上对蓝牙组件的说明长时间没有更新,与高版本的代码已经不匹配。另外这部分的说明也不太详细,所以本文基于OH开源社区上OpenHarmony-4.1-Release版本的代码对蓝牙组件进行说明。
2. 系统框架
图1 OpenHarmony技术架构图
图1是OH的系统框架图,对应的OH的蓝牙系统框架图如下:
图2 蓝牙系统框架图
3. 蓝牙组件代码目录结构
3.1. 蓝牙组件框架层
/foundation/communication/bluetooth
├── frameworks # bluetooth FW接口及实现代码
│ ├ inner
│ │ ├── c_adapter # C接口实现存放目录
│ │ ├── include # C++接口定义存放目录
│ │ ├── ipc # ipc通信接口定义及实现存放目录
│ │ └── src # C++接口实现存放目录
│ └── js\napi
│ ├── include # NAPI接口定义存放目录
│ └── src # NAPI接口实现存放目录
└── interfaces/inner_api/include #C++接口定义存放目录
└──c_header#C接口定义存放目录
该部分主要是蓝牙组件的框架层实现,包括C/C++接口以及NAPI接口。其中C接口主要包括GAP、GATT、Rfcomm蓝牙协议,以支持BLE和socket通信。C++接口和NAPI接口除了包括GAP、GATT、Rfcomm蓝牙协议,还包括A2DP、AVRCP、HFP、HID、OPP等经典蓝牙常用的蓝牙协议。
3.2. 蓝牙组件服务层
/foundation/communication/bluetooth_service
├── sa_profile # 蓝牙服务定义目录
├── services # 蓝牙服务源码目录
│ ├── bluetooth # 标准蓝牙服务源码目录
│ │ ├── common # 公共源码目录,主要为log相关
│ │ ├──etc\init # 蓝牙服务配置文件保存目录
│ │ ├──external # dummy占位代码,功能预留,未来实现
│ │ ├──hardware # 与蓝牙HDI服务交互的代码,HDI adatper
│ │ ├──ipc # IPC通信相关。
│ │ ├──server # 蓝牙服务server代码。
│ │ ├──service # 蓝牙服务service代码。
│ │ ├──stack # 蓝牙协议栈代码。
│ └── bluetooth_lite # 轻量级蓝牙服务源码目录,未实现。
└──test # 蓝牙测试相关源码目录
server代码和service代码的区别:
class BluetoothA2dpSinkServer : public BluetoothA2dpSinkStub {
以A2dp profile的sink端举例,如上是其server端的类定义,其继承了一个stub类,stub类一般为binder通信的服务端。说明BluetoothA2dpSinkServer为A2dp profile的sink端服务向其他进程提供服务的主体。
BluetoothA2dpSinkServer::BluetoothA2dpSinkServer()
{
pimpl = std::make_unique<impl>();
pimpl->observerImp_->SetObserver(&(pimpl->observers_));
pimpl->systemStateObserver_ = std::make_unique<impl::SystemStateObserver>(pimpl.get());
IAdapterManager::GetInstance()->RegisterSystemStateObserver(*(pimpl->systemStateObserver_));
IProfileManager *serviceMgr = IProfileManager::GetInstance();
if (serviceMgr != nullptr) {
pimpl->a2dpSnkService_ = (IProfileA2dpSnk *)serviceMgr->GetProfileService(PROFILE_NAME_A2DP_SINK);
if (pimpl->a2dpSnkService_ != nullptr) {
pimpl->a2dpSnkService_->RegisterObserver(pimpl->observerImp_.get());
}
}
}
如上是BluetoothA2dpSinkServer的构造函数,从上可以看到a2dpSnkService_的获取过程。这里的a2dpSnkService_的具体实现就是在service目录中。
这样我们就知道了server目录里的代码是binder server端的实现,而service目录是实际的蓝牙 profile的功能实现代码。
4. 蓝牙组件框架层与服务层的交互流程示例
下面以蓝牙打开的流程为例说明一下,蓝牙组件框架层与服务层的各部分代码的交互流程。
框架层蓝牙打开的入口函数为
napi_value NapiAccess::EnableBluetooth(napi_env env, napi_callback_info info)
其是通过如下代码向app层暴露的。
napi_value NapiAccess::DefineAccessJSFunction(napi_env env, napi_value exports)
{
HILOGD("enter");
RegisterAccessObserverToHost();
AccessPropertyValueInit(env, exports);
napi_property_descriptor desc[] = {
DECLARE_NAPI_FUNCTION("getState", GetState),
DECLARE_NAPI_FUNCTION("enableBluetooth", EnableBluetooth), // 暴露enableBluetooth接口
DECLARE_NAPI_FUNCTION("disableBluetooth", DisableBluetooth),
#ifdef BLUETOOTH_API_SINCE_10
DECLARE_NAPI_FUNCTION("factoryReset", FactoryReset),
DECLARE_NAPI_FUNCTION("getLocalAddress", GetLocalAddress),
DECLARE_NAPI_FUNCTION("on", RegisterAccessObserver),
DECLARE_NAPI_FUNCTION("off", DeregisterAccessObserver),
#endif
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
1) EnableBluetooth函数会调用BluetoothHost::EnableBle()。
napi_value NapiAccess::EnableBluetooth(napi_env env, napi_callback_info info)
{
HILOGI("enter");
BluetoothHost *host = &BluetoothHost::GetDefaultHost();
int32_t ret = host->EnableBle();
NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
return NapiGetBooleanTrue(env);
}
在这里大家可能会有疑问,打开蓝牙为什么是使能BLE,而不是使能BREDR。如果了解Android系统蓝牙流程就会知道,在android框架层中,使能蓝牙首先是使能BLE,然后初始化协议栈,最后通过rfkill节点打开蓝牙。蓝牙芯片使能后,再使能BREDR,其具体实现是拉起BREDR的支持的各种profile服务。OH系统也是类似,使能BLE就会使能蓝牙芯片。
2) BluetoothHost::EnableBle()然后会调用BluetoothHostProxy::EnableBle函数。
int BluetoothHost::EnableBle()
{
HILOGD("enter");
CHECK_AND_RETURN_LOG_RET(!IsBtProhibitedByEdm(), BT_ERR_PROHIBITED_BY_EDM, "bluetooth is prohibited !");
CHECK_AND_RETURN_LOG_RET(pimpl && pimpl->LoadBluetoothHostService(), BT_ERR_INTERNAL_ERROR,
"pimpl is null or load bluetooth service failed.");
sptr<IBluetoothHost> proxy = GetRemoteProxy<IBluetoothHost>(BLUETOOTH_HOST);
CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_INTERNAL_ERROR, "proxy is nullptr");
CountEnableTimes(true);
return proxy->EnableBle();
}
3) BluetoothHostProxy是binder通信的client端,BluetoothHostProxy::EnableBle会向binder通信的server发送BluetoothHostInterfaceCode::BT_ENABLE_BLE执行指令。
int32_t BluetoothHostProxy::EnableBle()
{
MessageParcel data;
if (!data.WriteInterfaceToken(BluetoothHostProxy::GetDescriptor())) {
HILOGE("BluetoothHostProxy::EnableBle WriteInterfaceToken error");
return BT_ERR_IPC_TRANS_FAILED;
}
MessageParcel reply;
MessageOption option = {MessageOption::TF_SYNC};
int32_t error = InnerTransact(BluetoothHostInterfaceCode::BT_ENABLE_BLE, option, data, reply);
if (error != BT_NO_ERROR) {
HILOGE("BluetoothHostProxy::EnableBle done fail, error: %{public}d", error);
return BT_ERR_IPC_TRANS_FAILED;
}
return reply.ReadInt32();
}
4) Binder通信的server端,也就是BluetoothHostServer,会处理该指令。BluetoothHostServer继承了BluetoothHostStub。
class BluetoothHostServer : public SystemAbility, public BluetoothHostStub
BT_ENABLE_BLE指令处理函数的映射逻辑如下:
{BluetoothHostInterfaceCode::BT_ENABLE_BLE, std::bind(&BluetoothHostStub::EnableBleInner, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)},//映射处理BT_ENABLE_BLE的函数。
EnableBleInner的处理逻辑如下,会调用EnableBle函数。
int32_t BluetoothHostStub::EnableBleInner(MessageParcel &data, MessageParcel &reply)
{
int32_t result = EnableBle();
bool ret = reply.WriteInt32(result);
if (!ret) {
HILOGE("BluetoothHostStub: reply writing failed in: %{public}s.", __func__);
return BT_ERR_IPC_TRANS_FAILED;
}
return NO_ERROR;
}
5) BluetoothHostServer::EnableBle的实现如下,其会调用AdapterManager::Enable。
int32_t BluetoothHostServer::EnableBle()
{
HILOGI("Enter!");
if (IAdapterManager::GetInstance()->Enable(BTTransport::ADAPTER_BLE)) {
return NO_ERROR;
}
return BT_ERR_INTERNAL_ERROR;
}
6)AdapterManager::Enable的主要实现如下,使用AdapterManager::impl::ProcessMessage来处理AdapterStateMachine::MSG_USER_ENABLE_REQ消息。
if (GetState(transport) == BTStateID::STATE_TURN_OFF) {
utility::Message msg(AdapterStateMachine::MSG_USER_ENABLE_REQ);
pimpl->dispatcher_->PostTask(std::bind(&AdapterManager::impl::ProcessMessage, pimpl.get(), transport, msg));
上面的代码牵涉到状态机,状态机迁移在本文就不展开说明了,接下来会调用BleAdapter::Enable。
7)BleAdapter::Enable实现如下
void BleAdapter::Enable()
{
LOG_DEBUG("[BleAdapter] %{public}s:%{public}s", __func__, Name().c_str());
GetDispatcher()->PostTask(std::bind(&BleAdapter::EnableTask, this));
}
8)其是实际执行函数为BleAdapter::EnableTask
bool BleAdapter::EnableTask()
{
LOG_DEBUG("[BleAdapter] %{public}s", __func__);
std::lock_guard<std::recursive_mutex> lk(pimpl->syncMutex_);
bool ret = (BTM_Enable(LE_CONTROLLER) == BT_SUCCESS);
if (!ret) {
pimpl->btmEnableFlag_ = false;
LOG_ERROR("[BleAdapter] %{public}s:BTM enable failed!", __func__);
} else {
pimpl->btmEnableFlag_ = true;
LoadConfig();
ret = (InitBtmAndGap() == BT_SUCCESS);
LOG_DEBUG("[BleAdapter] %{public}s:BTM enable successfully!", __func__);
}
GetContext()->OnEnable(ADAPTER_NAME_BLE, ret);
return ret;
}
其首先调用协议栈的BTM_Enable函数,其主要完成了HCI的初始化,以及相关回调函数的设置。HCI的初始化会与蓝牙的HCI服务通信,完成蓝牙芯片的使能。然后调用loadconfig,加载蓝牙相关的配置。接着调用InitBtmAndGap,初始化BTM(Bluetooth Manager)以及GAP 协议相关的配置。最后调用回调OnEnable来通知上层蓝牙打开成功。
以上就是以蓝牙打开的流程为示例说明了蓝牙框架层和服务层的交互逻辑。