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