* Copyright (c) 2024-2025 Huawei Device Co., Ltd.
* 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.
*/
#include "bluetooth_ble_impl.h"
#include "bluetooth_ble_central_manager.h"
#include "bluetooth_ble_common.h"
#include "bluetooth_ble_ffi.h"
#include "bluetooth_errorcode.h"
#include "bluetooth_log.h"
#include "cj_lambda.h"
#include "napi_bluetooth_utils.h"
namespace OHOS {
namespace CJSystemapi {
namespace CJBluetoothBle {
using Bluetooth::BleAdvertiser;
using Bluetooth::BleAdvertiserData;
using Bluetooth::BleScanFilter;
using Bluetooth::BleScanSettings;
using Bluetooth::IsValidAddress;
using Bluetooth::IsValidUuid;
using Bluetooth::ParcelUuid;
using OHOS::FFI::FFIData;
using Bluetooth::NapiAdvManufactureData;
using Bluetooth::NapiAdvServiceData;
using Bluetooth::BT_ERR_BLE_SCAN_ALREADY_STARTED;
using Bluetooth::BT_ERR_INTERNAL_ERROR;
using Bluetooth::BT_ERR_INVALID_PARAM;
using Bluetooth::BT_NO_ERROR;
namespace {
using Bluetooth::BleCentralManager;
std::shared_ptr<BleAdvertiser> BleAdvertiserGetInstance(void)
{
static auto instance = BleAdvertiser::CreateInstance();
return instance;
}
BleCentralManager* BleCentralManagerGetInstance(void)
{
static BleCentralManager instance(FfiBluetoothBleCentralManagerCallback::GetInstance());
return &instance;
}
}
int32_t BleImpl::CreateGattServer(FfiGattServer*& ffiGattServer)
{
ffiGattServer = FFIData::Create<FfiGattServer>();
if (ffiGattServer == nullptr) {
return BT_ERR_INTERNAL_ERROR;
}
return BT_NO_ERROR;
}
int32_t BleImpl::CreateGattClientDevice(std::string deviceId, FfiClientDevice*& ffiClientDevice)
{
if (!IsValidAddress(deviceId)) {
HILOGE("Invalid deviceId: %{public}s", deviceId.c_str());
return BT_ERR_INVALID_PARAM;
}
ffiClientDevice = FFIData::Create<FfiClientDevice>(deviceId);
return BT_NO_ERROR;
}
int32_t BleImpl::GetConnectedBleDevices(CArrString& res)
{
std::lock_guard<std::mutex> lock(FfiGattServer::deviceListMutex_);
std::vector<std::string> devicesList = FfiGattServer::deviceList_;
res = Convert2CArrString(devicesList);
return BT_NO_ERROR;
}
static void ParseScanFilterDeviceIdParameters(
int32_t& status, NativeScanFilter& scanFilter, BleScanFilter& bleScanFilter)
{
if (scanFilter.deviceId != nullptr) {
std::string deviceId = std::string(scanFilter.deviceId);
if (!IsValidAddress(deviceId)) {
HILOGE("Invalid deviceId: %{public}s", deviceId.c_str());
status = BT_ERR_INVALID_PARAM;
}
bleScanFilter.SetDeviceId(deviceId);
}
}
static void ParseScanFilterLocalNameParameters(
int32_t& status, NativeScanFilter& scanFilter, BleScanFilter& bleScanFilter)
{
if (scanFilter.name != nullptr) {
std::string name = std::string(scanFilter.name);
if (name.empty()) {
HILOGE("name is empty");
status = BT_ERR_INVALID_PARAM;
}
bleScanFilter.SetName(name);
}
}
static int32_t ParseUuidParams(char* name, UUID& outUuid)
{
std::string uuid = std::string(name);
if (!IsValidUuid(uuid)) {
HILOGE("match the UUID faild.");
return BT_ERR_INVALID_PARAM;
}
outUuid = ParcelUuid::FromString(uuid);
return BT_NO_ERROR;
}
static void ParseScanFilterServiceUuidParameters(
int32_t& status, NativeScanFilter& scanFilter, BleScanFilter& bleScanFilter)
{
if (scanFilter.serviceUuid != nullptr) {
UUID uuid {};
status = ParseUuidParams(scanFilter.serviceUuid, uuid);
if (status != BT_NO_ERROR) {
return;
}
bleScanFilter.SetServiceUuid(uuid);
}
if (scanFilter.serviceUuidMask != nullptr) {
UUID uuidMask {};
status = ParseUuidParams(scanFilter.serviceUuidMask, uuidMask);
if (status != BT_NO_ERROR) {
return;
}
bleScanFilter.SetServiceUuidMask(uuidMask);
}
}
static void ParseScanFilterSolicitationUuidParameters(
int32_t& status, NativeScanFilter& scanFilter, BleScanFilter& bleScanFilter)
{
if (scanFilter.serviceSolicitationUuid != nullptr) {
UUID uuid {};
status = ParseUuidParams(scanFilter.serviceSolicitationUuid, uuid);
if (status != BT_NO_ERROR) {
return;
}
bleScanFilter.SetServiceSolicitationUuid(uuid);
}
if (scanFilter.serviceSolicitationUuidMask != nullptr) {
UUID uuidMask {};
status = ParseUuidParams(scanFilter.serviceSolicitationUuidMask, uuidMask);
if (status != BT_NO_ERROR) {
return;
}
bleScanFilter.SetServiceSolicitationUuidMask(uuidMask);
}
}
static void ParseScanFilterServiceDataParameters(
int32_t& status, NativeScanFilter& scanFilter, BleScanFilter& bleScanFilter)
{
std::vector<uint8_t> data {};
if (scanFilter.serviceData.head != nullptr) {
bleScanFilter.SetServiceData(std::move(data));
}
std::vector<uint8_t> dataMask {};
if (scanFilter.serviceDataMask.head != nullptr) {
bleScanFilter.SetServiceDataMask(std::move(dataMask));
}
}
static void ParseScanFilterManufactureDataParameters(
int32_t& status, NativeScanFilter& scanFilter, BleScanFilter& bleScanFilter)
{
if (scanFilter.manufactureId != 0) {
bleScanFilter.SetManufacturerId(scanFilter.manufactureId);
HILOGI("Scan filter manufacturerId is %{public}#x", scanFilter.manufactureId);
}
std::vector<uint8_t> data {};
if (scanFilter.manufactureData.head != nullptr) {
for (int64_t i = 0; i < scanFilter.manufactureData.size; i++) {
data.push_back(scanFilter.manufactureData.head[i]);
}
bleScanFilter.SetManufactureData(std::move(data));
}
std::vector<uint8_t> dataMask {};
if (scanFilter.manufactureDataMask.head != nullptr) {
for (int64_t i = 0; i < scanFilter.manufactureDataMask.size; i++) {
dataMask.push_back(scanFilter.manufactureDataMask.head[i]);
}
bleScanFilter.SetManufactureDataMask(std::move(dataMask));
}
}
static void ParseScanFilter(int32_t& status, NativeScanFilter& scanFilter, BleScanFilter& bleScanFilter)
{
ParseScanFilterDeviceIdParameters(status, scanFilter, bleScanFilter);
ParseScanFilterLocalNameParameters(status, scanFilter, bleScanFilter);
ParseScanFilterServiceUuidParameters(status, scanFilter, bleScanFilter);
ParseScanFilterSolicitationUuidParameters(status, scanFilter, bleScanFilter);
ParseScanFilterServiceDataParameters(status, scanFilter, bleScanFilter);
ParseScanFilterManufactureDataParameters(status, scanFilter, bleScanFilter);
}
static int32_t CheckBleScanParams(CArrNativeScanFilter filters, NativeScanOptions* scanOptions,
std::vector<BleScanFilter>& outScanfilters, BleScanSettings& outSettinngs)
{
std::vector<BleScanFilter> scanfilters;
uint32_t length = static_cast<uint32_t>(filters.size);
int32_t status = BT_NO_ERROR;
for (uint32_t i = 0; i < length; i++) {
BleScanFilter bleScanFilter;
ParseScanFilter(status, filters.head[i], bleScanFilter);
scanfilters.push_back(bleScanFilter);
}
if (status != BT_NO_ERROR) {
return status;
}
if (scanOptions != nullptr) {
outSettinngs.SetReportDelay(scanOptions->interval);
outSettinngs.SetScanMode(scanOptions->dutyMode);
outSettinngs.SetPhy(scanOptions->phyType);
}
outScanfilters = std::move(scanfilters);
return BT_NO_ERROR;
}
int32_t BleImpl::StartBleScan(CArrNativeScanFilter filters, NativeScanOptions* options)
{
std::vector<BleScanFilter> scanfilters;
BleScanSettings settings;
int status = CheckBleScanParams(filters, options, scanfilters, settings);
if (status != BT_NO_ERROR) {
return status;
}
int ret = BleCentralManagerGetInstance()->StartScan(settings, scanfilters);
if (ret != BT_NO_ERROR && ret != BT_ERR_BLE_SCAN_ALREADY_STARTED) {
return ret;
}
return BT_NO_ERROR;
}
int32_t BleImpl::StopBleScan()
{
return BleCentralManagerGetInstance()->StopScan();
}
static void ParseAdvertisingSettingsParameters(
int32_t* errCode, NativeAdvertiseSetting& setting, BleAdvertiserSettings& outSettings)
{
uint32_t interval = setting.interval;
const uint32_t minInterval = 32;
const uint32_t maxInterval = 16384;
if (interval < minInterval || interval > maxInterval) {
HILOGE("Invalid interval: %{public}d", interval);
*errCode = BT_ERR_INVALID_PARAM;
return;
}
HILOGI("interval: %{public}u", interval);
outSettings.SetInterval(interval);
int32_t txPower = setting.txPower;
const int32_t minTxPower = -127;
const int32_t maxTxPower = 1;
if (txPower < minTxPower || txPower > maxTxPower) {
HILOGE("Invalid tx power: %{public}d", txPower);
*errCode = BT_ERR_INVALID_PARAM;
return;
}
HILOGI("txPower is %{public}d", txPower);
outSettings.SetTxPower(txPower);
bool connectable = setting.connectable;
HILOGI("connectable: %{public}d", connectable);
outSettings.SetConnectable(connectable);
return;
}
static void ParseServiceUuidParameters(int32_t* errCode, NativeAdvertiseData advData, BleAdvertiserData& outData)
{
for (int64_t i = 0; i < advData.serviceUuids.size; ++i) {
UUID uuid {};
*errCode = ParseUuidParams(advData.serviceUuids.head[i], uuid);
if (*errCode != BT_NO_ERROR) {
return;
}
outData.AddServiceUuid(uuid);
HILOGI("Service Uuid = %{public}s", uuid.ToString().c_str());
}
return;
}
static void ParseManufactureDataParameters(int32_t* errCode, NativeAdvertiseData advData, BleAdvertiserData& outData)
{
CArrNativeManufactureData parameter = advData.manufactureData;
for (int64_t i = 0; i < parameter.size; ++i) {
NativeManufactureData manufactureData = parameter.head[i];
CArrUI8 manufactureValue = manufactureData.manufactureValue;
std::string value(reinterpret_cast<char*>(manufactureValue.head), manufactureValue.size);
outData.AddManufacturerData(manufactureData.manufactureId, value);
}
return;
}
static void ParseServiceDataParameters(int32_t* errCode, NativeAdvertiseData advData, BleAdvertiserData& outData)
{
CArrNativeServiceData data = advData.serviceData;
for (int64_t i = 0; i < data.size; ++i) {
NativeServiceData serviceData = data.head[i];
std::string value(reinterpret_cast<char*>(serviceData.serviceValue.head), serviceData.serviceValue.size);
outData.AddServiceData(ParcelUuid::FromString(std::string(serviceData.serviceUuid)), value);
}
return;
}
static void ParseAdvertisDataParameters(int32_t* errCode, NativeAdvertiseData advData, BleAdvertiserData& outData)
{
ParseServiceUuidParameters(errCode, advData, outData);
ParseManufactureDataParameters(errCode, advData, outData);
ParseServiceDataParameters(errCode, advData, outData);
bool includeDeviceName = advData.includeDeviceName;
HILOGI("includeDeviceName: %{public}d", includeDeviceName);
outData.SetIncludeDeviceName(includeDeviceName);
return;
}
int32_t BleImpl::StartAdvertising(
NativeAdvertiseSetting setting, NativeAdvertiseData advData, NativeAdvertiseData* advResponse)
{
std::shared_ptr<BleAdvertiser> bleAdvertiser = BleAdvertiserGetInstance();
BleAdvertiserSettings nativeSettings;
BleAdvertiserData nativeAdvData;
BleAdvertiserData nativeRspData;
int32_t errCode = BT_NO_ERROR;
ParseAdvertisingSettingsParameters(&errCode, setting, nativeSettings);
ParseAdvertisDataParameters(&errCode, advData, nativeAdvData);
if (advResponse != nullptr) {
ParseAdvertisDataParameters(&errCode, *advResponse, nativeRspData);
}
if (errCode != BT_NO_ERROR) {
return errCode;
}
return bleAdvertiser->StartAdvertising(
nativeSettings, nativeAdvData, nativeRspData, 0, FfiBluetoothBleAdvertiseCallback::GetInstance());
}
int32_t BleImpl::StopAdvertising()
{
std::shared_ptr<BleAdvertiser> bleAdvertiser = BleAdvertiserGetInstance();
if (bleAdvertiser == nullptr) {
HILOGE("bleAdvertiser is nullptr");
return BT_ERR_INTERNAL_ERROR;
}
return bleAdvertiser->StopAdvertising(FfiBluetoothBleAdvertiseCallback::GetInstance());
}
static bool IsValidAdvertiserDuration(uint32_t duration)
{
const uint32_t MIN_DURATION = 0;
const uint32_t MAX_DURATION = 65535;
if (duration < MIN_DURATION || duration > MAX_DURATION) {
return false;
}
return true;
}
int32_t BleImpl::StartAdvertising(NativeAdvertisingParams advertisingParams, int32_t& id)
{
std::shared_ptr<BleAdvertiser> bleAdvertiser = BleAdvertiserGetInstance();
BleAdvertiserSettings nativeSettings;
BleAdvertiserData nativeAdvData;
BleAdvertiserData nativeRspData;
int32_t errCode = BT_NO_ERROR;
ParseAdvertisingSettingsParameters(&errCode, advertisingParams.advertisingSettings, nativeSettings);
ParseAdvertisDataParameters(&errCode, advertisingParams.advertisingData, nativeAdvData);
ParseAdvertisDataParameters(&errCode, advertisingParams.advertisingResponse, nativeRspData);
uint16_t duration = advertisingParams.duration;
if (!IsValidAdvertiserDuration(duration)) {
HILOGE("Invalid duration: %{public}d", duration);
return BT_ERR_INVALID_PARAM;
}
HILOGI("duration: %{public}u", duration);
errCode = bleAdvertiser->StartAdvertising(
nativeSettings, nativeAdvData, nativeRspData, duration, FfiBluetoothBleAdvertiseCallback::GetInstance());
if (errCode != BT_NO_ERROR) {
return errCode;
}
id = FfiBluetoothBleAdvertiseCallback::GetInstance()->GetAdvHandleEvent();
if (id < 0) {
return BT_ERR_INTERNAL_ERROR;
}
return BT_NO_ERROR;
}
int32_t BleImpl::EnableAdvertising(NativeAdvertisingEnableParams advertisingEnableParams)
{
uint32_t advHandle = advertisingEnableParams.advertisingId;
uint16_t duration = advertisingEnableParams.duration;
std::shared_ptr<BleAdvertiser> bleAdvertiser = BleAdvertiserGetInstance();
if (bleAdvertiser == nullptr) {
HILOGE("bleAdvertiser is nullptr");
return BT_ERR_INTERNAL_ERROR;
}
return bleAdvertiser->EnableAdvertising(advHandle, duration, FfiBluetoothBleAdvertiseCallback::GetInstance());
}
int32_t BleImpl::DisableAdvertising(NativeAdvertisingDisableParams advertisingDisableParams)
{
uint32_t advHandle = advertisingDisableParams.advertisingId;
std::shared_ptr<BleAdvertiser> bleAdvertiser = BleAdvertiserGetInstance();
if (bleAdvertiser == nullptr) {
HILOGE("bleAdvertiser is nullptr");
return BT_ERR_INTERNAL_ERROR;
}
return bleAdvertiser->DisableAdvertising(advHandle, FfiBluetoothBleAdvertiseCallback::GetInstance());
}
int32_t BleImpl::StopAdvertising(uint32_t advertisingId)
{
std::shared_ptr<BleAdvertiser> bleAdvertiser = BleAdvertiserGetInstance();
if (bleAdvertiser == nullptr) {
HILOGE("bleAdvertiser is nullptr");
return BT_ERR_INTERNAL_ERROR;
}
uint32_t advHandle = advertisingId;
if (advHandle != bleAdvertiser->GetAdvHandle(FfiBluetoothBleAdvertiseCallback::GetInstance())) {
HILOGE("Invalid advHandle: %{public}d", advHandle);
return BT_ERR_INVALID_PARAM;
}
bleAdvertiser->StopAdvertising(FfiBluetoothBleAdvertiseCallback::GetInstance());
return BT_NO_ERROR;
}
int32_t BleImpl::RegisterBleObserver(int32_t callbackType, void (*callback)())
{
if (callbackType == REGISTER_BLE_ADVERTISING_STATE_INFO_TYPE) {
auto callbackFunc = CJLambda::Create(reinterpret_cast<void (*)(CAdvertisingStateChangeInfo)>(callback));
FfiBluetoothBleAdvertiseCallback::GetInstance()->RegisterAdvertisingStateChangeFunc(callbackFunc);
} else if (callbackType == REGISTER_BLE_FIND_DEVICE_TYPE) {
auto callbackFunc = CJLambda::Create(reinterpret_cast<void (*)(CArrScanResult)>(callback));
FfiBluetoothBleCentralManagerCallback::GetInstance().RegisterBLEDeviceFindFunc(callbackFunc);
} else {
HILOGE("Unsupported callback type");
return BT_ERR_INVALID_PARAM;
}
return BT_NO_ERROR;
}
}
}
}