1 /******************************************************************************
2 *
3 * Copyright 2024 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include <bluetooth/log.h>
20 #include <com_android_bluetooth_flags.h>
21 #include <string.h>
22
23 #include <array>
24
25 #include "os/system_properties.h"
26 #include "stack/include/ais_api.h"
27 #include "stack/include/bt_types.h"
28 #include "stack/include/gatt_api.h"
29 #include "types/bluetooth/uuid.h"
30
31 using bluetooth::Uuid;
32 using bluetooth::log::error;
33 using bluetooth::log::warn;
34
35 static const char kPropertyAndroidAPILevel[] = "ro.build.version.sdk";
36 static const uint32_t kPropertyAndroidAPILevelDefault = 0;
37
38 const Uuid ANDROID_INFORMATION_SERVICE_UUID =
39 Uuid::FromString(ANDROID_INFORMATION_SERVICE_UUID_STRING);
40 const Uuid GATT_UUID_AIS_API_LEVEL = Uuid::FromString(GATT_UUID_AIS_API_LEVEL_STRING);
41
42 /* LE AIS attribute handle */
43 static uint16_t attr_api_level_handle;
44
45 static uint32_t api_level;
46
47 void ais_request_cback(tCONN_ID, uint32_t, tGATTS_REQ_TYPE, tGATTS_DATA*);
48
49 static tGATT_CBACK ais_cback = {
50 .p_conn_cb = nullptr,
51 .p_cmpl_cb = nullptr,
52 .p_disc_res_cb = nullptr,
53 .p_disc_cmpl_cb = nullptr,
54 .p_req_cb = ais_request_cback,
55 .p_enc_cmpl_cb = nullptr,
56 .p_congestion_cb = nullptr,
57 .p_phy_update_cb = nullptr,
58 .p_conn_update_cb = nullptr,
59 .p_subrate_chg_cb = nullptr,
60 };
61
62 /** AIS ATT server attribute access request callback */
ais_request_cback(tCONN_ID conn_id,uint32_t trans_id,tGATTS_REQ_TYPE type,tGATTS_DATA * p_data)63 void ais_request_cback(tCONN_ID conn_id, uint32_t trans_id, tGATTS_REQ_TYPE type,
64 tGATTS_DATA* p_data) {
65 tGATT_STATUS status = GATT_INVALID_PDU;
66 tGATTS_RSP rsp_msg = {};
67 uint16_t handle = p_data->read_req.handle;
68 tGATT_VALUE* p_value = &rsp_msg.attr_value;
69 uint8_t* p = p_value->value;
70
71 if (type == GATTS_REQ_TYPE_READ_CHARACTERISTIC) {
72 p_value->handle = handle;
73
74 if (handle == attr_api_level_handle) {
75 if (p_data->read_req.is_long) {
76 p_value->offset = p_data->read_req.offset;
77 status = GATT_NOT_LONG;
78 } else {
79 UINT32_TO_STREAM(p, api_level);
80 p_value->len = 4;
81 status = GATT_SUCCESS;
82 }
83 } else {
84 status = GATT_NOT_FOUND;
85 }
86 } else {
87 warn("Unknown/unexpected LE AIS ATT request: 0x{:02x}", type);
88 }
89
90 if (GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg) != GATT_SUCCESS) {
91 warn("Unable to send GATT server response conn_id:{}", conn_id);
92 }
93 }
94
95 /*******************************************************************************
96 *
97 * Function ais_attr_db_init
98 *
99 * Description AIS ATT database initialization.
100 *
101 * Returns void.
102 *
103 ******************************************************************************/
ais_attr_db_init(void)104 static void ais_attr_db_init(void) {
105 if (!com::android::bluetooth::flags::android_os_identifier()) {
106 return;
107 }
108 api_level = bluetooth::os::GetSystemPropertyUint32(kPropertyAndroidAPILevel,
109 kPropertyAndroidAPILevelDefault);
110 // Add Android OS identifier if API level is defined.
111 if (api_level != kPropertyAndroidAPILevelDefault) {
112 std::array<uint8_t, Uuid::kNumBytes128> tmp;
113 tmp.fill(0xc5); // any number is fine here
114 Uuid app_uuid = Uuid::From128BitBE(tmp);
115
116 tGATT_IF gatt_if = GATT_Register(app_uuid, "Ais", &ais_cback, false);
117
118 GATT_StartIf(gatt_if);
119
120 btgatt_db_element_t android_information_service[] = {
121 {
122 .uuid = ANDROID_INFORMATION_SERVICE_UUID,
123 .type = BTGATT_DB_PRIMARY_SERVICE,
124 },
125 {
126 .uuid = GATT_UUID_AIS_API_LEVEL,
127 .type = BTGATT_DB_CHARACTERISTIC,
128 .properties = GATT_CHAR_PROP_BIT_READ,
129 .permissions = GATT_PERM_READ_IF_ENCRYPTED_OR_DISCOVERABLE,
130 }};
131 if (GATTS_AddService(gatt_if, android_information_service,
132 sizeof(android_information_service) / sizeof(btgatt_db_element_t)) !=
133 GATT_SERVICE_STARTED) {
134 error("Unable to add Android Information Server gatt_if:{}", gatt_if);
135 }
136
137 attr_api_level_handle = android_information_service[1].attribute_handle;
138 }
139 }
140
141 /*
142 * This routine should not be called except once per stack invocation.
143 */
AIS_Init(void)144 void AIS_Init(void) { ais_attr_db_init(); }
145