Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26b76ebc authored by Zhengping Jiang's avatar Zhengping Jiang
Browse files

Add Android information service to send API level

Register the Android information service as a custom service when
the Android API level is defined. Send the API level as a characteristic.

Bug: 348512828
Bug: 351860033
Test: m com.android.btservices
Flag: android_os_identifier
Change-Id: Ifcdfa4b8b05d7bf32d4b1a285ea2d5c0d8f7f42c
parent b686c692
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@
#include "internal_include/stack_config.h"
#include "rust/src/core/ffi/module.h"
#include "stack/btm/btm_ble_int.h"
#include "stack/include/ais_api.h"
#include "stack/include/smp_api.h"

#ifndef BT_STACK_CLEANUP_WAIT_MS
@@ -301,6 +302,7 @@ static void event_start_up_stack(bluetooth::core::CoreInterface* interface,

  RFCOMM_Init();
  GAP_Init();
  AIS_Init();

  startProfiles();

+5 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ cc_library_static {
    name: "libbt-stack",
    defaults: ["fluoride_defaults"],
    local_include_dirs: [
        "ais",
        "avct",
        "avdt",
        "avrc",
@@ -180,6 +181,7 @@ cc_library_static {
    name: "libbt-stack-core",
    defaults: ["fluoride_defaults"],
    local_include_dirs: [
        "ais",
        "avct",
        "avdt",
        "avrc",
@@ -213,6 +215,7 @@ cc_library_static {
        "acl/ble_acl.cc",
        "acl/btm_acl.cc",
        "acl/btm_pm.cc",
        "ais/ais_ble.cc",
        "arbiter/acl_arbiter.cc",
        "btm/ble_scanner_hci_interface.cc",
        "btm/btm_ble.cc",
@@ -517,6 +520,7 @@ cc_fuzz {
        ":TestMockStackL2cap",
        ":TestMockStackMetrics",
        ":TestMockStackSdp",
        "ais/*.cc",
        "eatt/*.cc",
        "fuzzers/gatt_fuzzer.cc",
        "gatt/*.cc",
@@ -1973,6 +1977,7 @@ cc_test {
        ":TestMockStackL2cap",
        ":TestMockStackSdp",
        ":TestMockStackSmp",
        "ais/ais_ble.cc",
        "arbiter/acl_arbiter.cc",
        "eatt/eatt.cc",
        "gatt/att_protocol.cc",
+2 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ source_set("nonstandard_codecs") {

source_set("stack") {
  sources = [
    "ais/ais_ble.cc",
    "a2dp/a2dp_api.cc",
    "a2dp/a2dp_codec_config.cc",
    "a2dp/a2dp_ext.cc",
@@ -187,6 +188,7 @@ source_set("stack") {
  include_dirs = [
    ".",
    "include",
    "ais",
    "avct",
    "btm",
    "avrc",
+144 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  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.
 *
 ******************************************************************************/

#include <bluetooth/log.h>
#include <com_android_bluetooth_flags.h>
#include <string.h>

#include <array>

#include "os/system_properties.h"
#include "stack/include/ais_api.h"
#include "stack/include/bt_types.h"
#include "stack/include/gatt_api.h"
#include "types/bluetooth/uuid.h"

using bluetooth::Uuid;
using bluetooth::log::error;
using bluetooth::log::warn;

static const char kPropertyAndroidAPILevel[] = "ro.build.version.sdk";
static const uint32_t kPropertyAndroidAPILevelDefault = 0;

const Uuid ANDROID_INFORMATION_SERVICE_UUID =
        Uuid::FromString(ANDROID_INFORMATION_SERVICE_UUID_STRING);
const Uuid GATT_UUID_AIS_API_LEVEL = Uuid::FromString(GATT_UUID_AIS_API_LEVEL_STRING);

/* LE AIS attribute handle */
static uint16_t attr_api_level_handle;

static uint32_t api_level;

void ais_request_cback(uint16_t, uint32_t, tGATTS_REQ_TYPE, tGATTS_DATA*);

static tGATT_CBACK ais_cback = {
        .p_conn_cb = nullptr,
        .p_cmpl_cb = nullptr,
        .p_disc_res_cb = nullptr,
        .p_disc_cmpl_cb = nullptr,
        .p_req_cb = ais_request_cback,
        .p_enc_cmpl_cb = nullptr,
        .p_congestion_cb = nullptr,
        .p_phy_update_cb = nullptr,
        .p_conn_update_cb = nullptr,
        .p_subrate_chg_cb = nullptr,
};

/** AIS ATT server attribute access request callback */
void ais_request_cback(uint16_t conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type,
                       tGATTS_DATA* p_data) {
  tGATT_STATUS status = GATT_INVALID_PDU;
  tGATTS_RSP rsp_msg = {};
  uint16_t handle = p_data->read_req.handle;
  tGATT_VALUE* p_value = &rsp_msg.attr_value;
  uint8_t* p = p_value->value;

  if (type == GATTS_REQ_TYPE_READ_CHARACTERISTIC) {
    p_value->handle = handle;

    if (handle == attr_api_level_handle) {
      if (p_data->read_req.is_long) {
        p_value->offset = p_data->read_req.offset;
        status = GATT_NOT_LONG;
      } else {
        UINT32_TO_STREAM(p, api_level);
        p_value->len = 4;
        status = GATT_SUCCESS;
      }
    } else {
      status = GATT_NOT_FOUND;
    }
  } else {
    warn("Unknown/unexpected LE AIS ATT request: 0x{:02x}", type);
  }

  if (GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg) != GATT_SUCCESS) {
    warn("Unable to send GATT server response conn_id:{}", conn_id);
  }
}

/*******************************************************************************
 *
 * Function         ais_attr_db_init
 *
 * Description      AIS ATT database initialization.
 *
 * Returns          void.
 *
 ******************************************************************************/
void ais_attr_db_init(void) {
  if (!com::android::bluetooth::flags::android_os_identifier()) {
    return;
  }
  api_level = bluetooth::os::GetSystemPropertyUint32(kPropertyAndroidAPILevel,
                                                     kPropertyAndroidAPILevelDefault);
  // Add Android OS identifier if API level is defined.
  if (api_level != kPropertyAndroidAPILevelDefault) {
    std::array<uint8_t, Uuid::kNumBytes128> tmp;
    tmp.fill(0xc5);  // any number is fine here
    Uuid app_uuid = Uuid::From128BitBE(tmp);

    tGATT_IF gatt_if = GATT_Register(app_uuid, "Ais", &ais_cback, false);

    GATT_StartIf(gatt_if);

    btgatt_db_element_t android_information_service[] = {
            {
                    .uuid = ANDROID_INFORMATION_SERVICE_UUID,
                    .type = BTGATT_DB_PRIMARY_SERVICE,
            },
            {
                    .uuid = GATT_UUID_AIS_API_LEVEL,
                    .type = BTGATT_DB_CHARACTERISTIC,
                    .properties = GATT_CHAR_PROP_BIT_READ,
                    .permissions = GATT_PERM_READ_IF_ENCRYPTED_OR_DISCOVERABLE,
            }};
    if (GATTS_AddService(gatt_if, android_information_service,
                         sizeof(android_information_service) / sizeof(btgatt_db_element_t)) !=
        GATT_SERVICE_STARTED) {
      error("Unable to add Android Information Server gatt_if:{}", gatt_if);
    }

    attr_api_level_handle = android_information_service[1].attribute_handle;
  }
}

/*
 * This routine should not be called except once per stack invocation.
 */
void AIS_Init(void) { ais_attr_db_init(); }
+3 −0
Original line number Diff line number Diff line
@@ -49,6 +49,9 @@ namespace os {
bool GetSystemPropertyBool(const std::string& property, bool default_value) {
  return default_value;
}
uint32_t GetSystemPropertyUint32(const std::string& property, uint32_t default_value) {
  return default_value;
}
}  // namespace os
}  // namespace bluetooth

Loading