Improve GATT Server database handling.

- use references instead of pointers where possible. Thanks to it we can
  remove some reduntant null checks and simplify the code.
- use directly allocated memory instead of own buffers. Thanks to it the
  stack uses around 12kb less of memory after startup.
- use list and vector from std library, instead of some hand-written
  implementations.

This patch is a prerequisite for further server refactoring, that will
further reduce the space used, make unit-testing possible, and enable
proper handling of PTS GATT tests.

Test: sl4a GattReadTest
Bug: 38225928
Change-Id: I1620be682259ccb8f0c02754806e355e3f1ad0c1
diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc
index d5d4de6..a999193 100644
--- a/stack/gatt/gatt_sr.cc
+++ b/stack/gatt/gatt_sr.cc
@@ -345,7 +345,7 @@
                                  uint16_t len, uint8_t* p_data) {
   uint32_t trans_id;
   uint16_t handle = 0, ll = len;
-  uint8_t *p = p_data, i_rcb;
+  uint8_t* p = p_data;
   tGATT_STATUS err = GATT_SUCCESS;
   uint8_t sec_flag, key_size;
 
@@ -373,14 +373,14 @@
          p_tcb->sr_cmd.multi_req.num_handles < GATT_MAX_READ_MULTI_HANDLES) {
     STREAM_TO_UINT16(handle, p);
 
-    i_rcb = gatt_sr_find_i_rcb_by_handle(handle);
-    if (i_rcb < GATT_MAX_SR_PROFILES) {
+    auto it = gatt_sr_find_i_rcb_by_handle(handle);
+    if (it != gatt_cb.srv_list_info->end()) {
       p_tcb->sr_cmd.multi_req.handles[p_tcb->sr_cmd.multi_req.num_handles++] =
           handle;
 
       /* check read permission */
-      err = gatts_read_attr_perm_check(gatt_cb.sr_reg[i_rcb].p_db, false,
-                                       handle, sec_flag, key_size);
+      err = gatts_read_attr_perm_check(it->p_db, false, handle, sec_flag,
+                                       key_size);
       if (err != GATT_SUCCESS) {
         GATT_TRACE_DEBUG("read permission denied : 0x%02x", err);
         break;
@@ -408,17 +408,17 @@
       for (ll = 0; ll < p_tcb->sr_cmd.multi_req.num_handles; ll++) {
         tGATTS_RSP* p_msg = (tGATTS_RSP*)osi_calloc(sizeof(tGATTS_RSP));
         handle = p_tcb->sr_cmd.multi_req.handles[ll];
-        i_rcb = gatt_sr_find_i_rcb_by_handle(handle);
+        auto it = gatt_sr_find_i_rcb_by_handle(handle);
 
         p_msg->attr_value.handle = handle;
         err = gatts_read_attr_value_by_handle(
-            p_tcb, gatt_cb.sr_reg[i_rcb].p_db, op_code, handle, 0,
-            p_msg->attr_value.value, &p_msg->attr_value.len, GATT_MAX_ATTR_LEN,
-            sec_flag, key_size, trans_id);
+            p_tcb, it->p_db, op_code, handle, 0, p_msg->attr_value.value,
+            &p_msg->attr_value.len, GATT_MAX_ATTR_LEN, sec_flag, key_size,
+            trans_id);
 
         if (err == GATT_SUCCESS) {
-          gatt_sr_process_app_rsp(p_tcb, gatt_cb.sr_reg[i_rcb].gatt_if,
-                                  trans_id, op_code, GATT_SUCCESS, p_msg);
+          gatt_sr_process_app_rsp(p_tcb, it->gatt_if, trans_id, op_code,
+                                  GATT_SUCCESS, p_msg);
         }
         /* either not using or done using the buffer, release it now */
         osi_free(p_msg);
@@ -448,21 +448,14 @@
     uint16_t e_hdl, UNUSED_ATTR uint8_t* p_data, tBT_UUID value) {
   tGATT_STATUS status = GATT_NOT_FOUND;
   uint8_t handle_len = 4, *p;
-  tGATT_SR_REG* p_rcb;
-  tGATT_SRV_LIST_INFO* p_list = &gatt_cb.srv_list_info;
-  tGATT_SRV_LIST_ELEM* p_srv = NULL;
   tBT_UUID* p_uuid;
 
   p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
 
-  p_srv = p_list->p_first;
-
-  while (p_srv) {
-    p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
-
-    if (p_rcb->in_use && p_rcb->s_hdl >= s_hdl && p_rcb->s_hdl <= e_hdl &&
-        p_rcb->type == GATT_UUID_PRI_SERVICE) {
-      p_uuid = gatts_get_service_uuid(p_rcb->p_db);
+  for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
+    if (el.s_hdl >= s_hdl && el.s_hdl <= e_hdl &&
+        el.type == GATT_UUID_PRI_SERVICE) {
+      p_uuid = gatts_get_service_uuid(el.p_db);
       if (p_uuid != NULL) {
         if (op_code == GATT_REQ_READ_BY_GRP_TYPE) handle_len = 4 + p_uuid->len;
 
@@ -482,15 +475,15 @@
             handle_len == p_msg->offset) {
           if (op_code != GATT_REQ_FIND_TYPE_VALUE ||
               gatt_uuid_compare(value, *p_uuid)) {
-            UINT16_TO_STREAM(p, p_rcb->s_hdl);
+            UINT16_TO_STREAM(p, el.s_hdl);
 
-            if (p_list->p_last_primary == p_srv &&
-                p_list->p_last_primary == p_list->p_last) {
+            if (gatt_cb.last_primary_s_handle &&
+                gatt_cb.last_primary_s_handle == el.s_hdl) {
               GATT_TRACE_DEBUG("Use 0xFFFF for the last primary attribute");
-              UINT16_TO_STREAM(
-                  p, 0xFFFF); /* see GATT ERRATA 4065, 4063, ATT ERRATA 4062 */
+              /* see GATT ERRATA 4065, 4063, ATT ERRATA 4062 */
+              UINT16_TO_STREAM(p, 0xFFFF);
             } else {
-              UINT16_TO_STREAM(p, p_rcb->e_hdl);
+              UINT16_TO_STREAM(p, el.e_hdl);
             }
 
             if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
@@ -503,64 +496,56 @@
           break;
       }
     }
-    p_srv = p_srv->p_next;
   }
   p_msg->offset = L2CAP_MIN_OFFSET;
 
   return status;
 }
 
-/*******************************************************************************
- *
- * Function         gatt_build_find_info_rsp
- *
- * Description      fill the find information response information in the given
- *                  buffer.
+/**
+ * fill the find information response information in the given buffer.
  *
  * Returns          true: if data filled sucessfully.
  *                  false: packet full, or format mismatch.
- *
- ******************************************************************************/
-static tGATT_STATUS gatt_build_find_info_rsp(tGATT_SR_REG* p_rcb, BT_HDR* p_msg,
-                                             uint16_t* p_len, uint16_t s_hdl,
-                                             uint16_t e_hdl) {
+ */
+static tGATT_STATUS gatt_build_find_info_rsp(tGATT_SRV_LIST_ELEM& el,
+                                             BT_HDR* p_msg, uint16_t* p_len,
+                                             uint16_t s_hdl, uint16_t e_hdl) {
   tGATT_STATUS status = GATT_NOT_FOUND;
   uint8_t* p;
   uint16_t len = *p_len;
-  tGATT_ATTR* p_attr = NULL;
   uint8_t info_pair_len[2] = {4, 18};
 
-  if (!p_rcb->p_db || !p_rcb->p_db->p_attr_list) return status;
+  if (!el.p_db) return status;
 
   /* check the attribute database */
-  p_attr = (tGATT_ATTR*)p_rcb->p_db->p_attr_list;
 
   p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET + p_msg->len;
 
-  while (p_attr) {
-    if (p_attr->handle > e_hdl) {
+  for (auto& attr : el.p_db->attr_list) {
+    if (attr.handle > e_hdl) {
       break;
     }
 
-    if (p_attr->handle >= s_hdl) {
+    if (attr.handle >= s_hdl) {
       if (p_msg->offset == 0)
-        p_msg->offset = (p_attr->uuid.len == LEN_UUID_16)
+        p_msg->offset = (attr.uuid.len == LEN_UUID_16)
                             ? GATT_INFO_TYPE_PAIR_16
                             : GATT_INFO_TYPE_PAIR_128;
 
       if (len >= info_pair_len[p_msg->offset - 1]) {
         if (p_msg->offset == GATT_INFO_TYPE_PAIR_16 &&
-            p_attr->uuid.len == LEN_UUID_16) {
-          UINT16_TO_STREAM(p, p_attr->handle);
-          UINT16_TO_STREAM(p, p_attr->uuid.uu.uuid16);
+            attr.uuid.len == LEN_UUID_16) {
+          UINT16_TO_STREAM(p, attr.handle);
+          UINT16_TO_STREAM(p, attr.uuid.uu.uuid16);
         } else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 &&
-                   p_attr->uuid.len == LEN_UUID_128) {
-          UINT16_TO_STREAM(p, p_attr->handle);
-          ARRAY_TO_STREAM(p, p_attr->uuid.uu.uuid128, LEN_UUID_128);
+                   attr.uuid.len == LEN_UUID_128) {
+          UINT16_TO_STREAM(p, attr.handle);
+          ARRAY_TO_STREAM(p, attr.uuid.uu.uuid128, LEN_UUID_128);
         } else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 &&
-                   p_attr->uuid.len == LEN_UUID_32) {
-          UINT16_TO_STREAM(p, p_attr->handle);
-          gatt_convert_uuid32_to_uuid128(p, p_attr->uuid.uu.uuid32);
+                   attr.uuid.len == LEN_UUID_32) {
+          UINT16_TO_STREAM(p, attr.handle);
+          gatt_convert_uuid32_to_uuid128(p, attr.uuid.uu.uuid32);
           p += LEN_UUID_128;
         } else {
           GATT_TRACE_ERROR("format mismatch");
@@ -577,7 +562,6 @@
         break;
       }
     }
-    p_attr = (tGATT_ATTR*)p_attr->p_next;
   }
 
   *p_len = len;
@@ -714,9 +698,6 @@
   uint8_t reason = GATT_INVALID_PDU, *p;
   uint16_t s_hdl = 0, e_hdl = 0, buf_len;
   BT_HDR* p_msg = NULL;
-  tGATT_SR_REG* p_rcb;
-  tGATT_SRV_LIST_INFO* p_list = &gatt_cb.srv_list_info;
-  tGATT_SRV_LIST_ELEM* p_srv = NULL;
 
   reason = gatts_validate_packet_format(op_code, &len, &p_data, NULL, &s_hdl,
                                         &e_hdl);
@@ -734,20 +715,16 @@
 
     buf_len = p_tcb->payload_size - 2;
 
-    p_srv = p_list->p_first;
-
-    while (p_srv) {
-      p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
-
-      if (p_rcb->in_use && !(p_rcb->s_hdl > e_hdl || p_rcb->e_hdl < s_hdl)) {
-        reason = gatt_build_find_info_rsp(p_rcb, p_msg, &buf_len, s_hdl, e_hdl);
+    for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
+      if (el.s_hdl <= e_hdl && el.e_hdl >= s_hdl) {
+        reason = gatt_build_find_info_rsp(el, p_msg, &buf_len, s_hdl, e_hdl);
         if (reason == GATT_NO_RESOURCES) {
           reason = GATT_SUCCESS;
           break;
         }
       }
-      p_srv = p_srv->p_next;
     }
+
     *p = (uint8_t)p_msg->offset;
 
     p_msg->offset = L2CAP_MIN_OFFSET;
@@ -837,15 +814,12 @@
 void gatts_process_read_by_type_req(tGATT_TCB* p_tcb, uint8_t op_code,
                                     uint16_t len, uint8_t* p_data) {
   tBT_UUID uuid;
-  tGATT_SR_REG* p_rcb;
   size_t msg_len = sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET;
   uint16_t buf_len, s_hdl, e_hdl, err_hdl = 0;
   BT_HDR* p_msg = NULL;
   tGATT_STATUS reason, ret;
   uint8_t* p;
   uint8_t sec_flag, key_size;
-  tGATT_SRV_LIST_INFO* p_list = &gatt_cb.srv_list_info;
-  tGATT_SRV_LIST_ELEM* p_srv = NULL;
 
   reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl,
                                         &e_hdl);
@@ -874,18 +848,14 @@
 
     reason = GATT_NOT_FOUND;
 
-    p_srv = p_list->p_first;
-
-    while (p_srv) {
-      p_rcb = GATT_GET_SR_REG_PTR(p_srv->i_sreg);
-
-      if (p_rcb->in_use && !(p_rcb->s_hdl > e_hdl || p_rcb->e_hdl < s_hdl)) {
+    for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
+      if (el.s_hdl <= e_hdl && el.e_hdl >= s_hdl) {
         gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag,
                              &key_size);
 
-        ret = gatts_db_read_attr_value_by_type(
-            p_tcb, p_rcb->p_db, op_code, p_msg, s_hdl, e_hdl, uuid, &buf_len,
-            sec_flag, key_size, 0, &err_hdl);
+        ret = gatts_db_read_attr_value_by_type(p_tcb, el.p_db, op_code, p_msg,
+                                               s_hdl, e_hdl, uuid, &buf_len,
+                                               sec_flag, key_size, 0, &err_hdl);
         if (ret != GATT_NOT_FOUND) {
           reason = ret;
 
@@ -896,7 +866,6 @@
           break;
         }
       }
-      p_srv = p_srv->p_next;
     }
     *p = (uint8_t)p_msg->offset;
     p_msg->offset = L2CAP_MIN_OFFSET;
@@ -912,24 +881,17 @@
     attp_send_sr_msg(p_tcb, p_msg);
 }
 
-/*******************************************************************************
- *
- * Function         gatts_process_write_req
- *
- * Description      This function is called to process the write request
- *                  from client.
- *
- * Returns          void
- *
- ******************************************************************************/
-void gatts_process_write_req(tGATT_TCB* p_tcb, uint8_t i_rcb, uint16_t handle,
-                             uint8_t op_code, uint16_t len, uint8_t* p_data,
+/**
+ * This function is called to process the write request from client.
+ */
+void gatts_process_write_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
+                             uint16_t handle, uint8_t op_code, uint16_t len,
+                             uint8_t* p_data,
                              bt_gatt_db_attribute_type_t gatt_type) {
   tGATTS_DATA sr_data;
   uint32_t trans_id;
   tGATT_STATUS status;
   uint8_t sec_flag, key_size, *p = p_data;
-  tGATT_SR_REG* p_sreg;
   uint16_t conn_id;
 
   memset(&sr_data, 0, sizeof(tGATTS_DATA));
@@ -968,15 +930,14 @@
 
   gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag, &key_size);
 
-  status = gatts_write_attr_perm_check(gatt_cb.sr_reg[i_rcb].p_db, op_code,
-                                       handle, sr_data.write_req.offset, p, len,
+  status = gatts_write_attr_perm_check(el.p_db, op_code, handle,
+                                       sr_data.write_req.offset, p, len,
                                        sec_flag, key_size);
 
   if (status == GATT_SUCCESS) {
     trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
     if (trans_id != 0) {
-      p_sreg = &gatt_cb.sr_reg[i_rcb];
-      conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
+      conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, el.gatt_if);
 
       uint8_t opcode = 0;
       if (gatt_type == BTGATT_DB_DESCRIPTOR) {
@@ -1010,17 +971,10 @@
   return;
 }
 
-/*******************************************************************************
- *
- * Function         gatts_process_read_req
- *
- * Description      This function is called to process the read request
- *                  from client.
- *
- * Returns          void
- *
- ******************************************************************************/
-static void gatts_process_read_req(tGATT_TCB* p_tcb, tGATT_SR_REG* p_rcb,
+/**
+ * This function is called to process the read request from client.
+ */
+static void gatts_process_read_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
                                    uint8_t op_code, uint16_t handle,
                                    UNUSED_ATTR uint16_t len, uint8_t* p_data) {
   size_t buf_len = sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET;
@@ -1039,8 +993,8 @@
   gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag, &key_size);
 
   reason = gatts_read_attr_value_by_handle(
-      p_tcb, p_rcb->p_db, op_code, handle, offset, p, &value_len,
-      (uint16_t)buf_len, sec_flag, key_size, 0);
+      p_tcb, el.p_db, op_code, handle, offset, p, &value_len, (uint16_t)buf_len,
+      sec_flag, key_size, 0);
 
   p_msg->len += value_len;
 
@@ -1068,10 +1022,8 @@
 void gatts_process_attribute_req(tGATT_TCB* p_tcb, uint8_t op_code,
                                  uint16_t len, uint8_t* p_data) {
   uint16_t handle = 0;
-  uint8_t *p = p_data, i;
-  tGATT_SR_REG* p_rcb = gatt_cb.sr_reg;
+  uint8_t* p = p_data;
   tGATT_STATUS status = GATT_INVALID_HANDLE;
-  tGATT_ATTR* p_attr;
 
   if (len < 2) {
     GATT_TRACE_ERROR("Illegal PDU length, discard request");
@@ -1095,24 +1047,22 @@
 #endif
 
   if (GATT_HANDLE_IS_VALID(handle)) {
-    for (i = 0; i < GATT_MAX_SR_PROFILES; i++, p_rcb++) {
-      if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle) {
-        p_attr = (tGATT_ATTR*)p_rcb->p_db->p_attr_list;
-
-        while (p_attr) {
-          if (p_attr->handle == handle) {
+    for (auto& el : *gatt_cb.srv_list_info) {
+      if (el.s_hdl <= handle && el.e_hdl >= handle) {
+        for (const auto& attr : el.p_db->attr_list) {
+          if (attr.handle == handle) {
             switch (op_code) {
               case GATT_REQ_READ: /* read char/char descriptor value */
               case GATT_REQ_READ_BLOB:
-                gatts_process_read_req(p_tcb, p_rcb, op_code, handle, len, p);
+                gatts_process_read_req(p_tcb, el, op_code, handle, len, p);
                 break;
 
               case GATT_REQ_WRITE: /* write char/char descriptor value */
               case GATT_CMD_WRITE:
               case GATT_SIGN_CMD_WRITE:
               case GATT_REQ_PREPARE_WRITE:
-                gatts_process_write_req(p_tcb, i, handle, op_code, len, p,
-                                        p_attr->gatt_type);
+                gatts_process_write_req(p_tcb, el, handle, op_code, len, p,
+                                        attr.gatt_type);
                 break;
               default:
                 break;
@@ -1120,7 +1070,6 @@
             status = GATT_SUCCESS;
             break;
           }
-          p_attr = (tGATT_ATTR*)p_attr->p_next;
         }
         break;
       }
@@ -1219,8 +1168,6 @@
 void gatts_process_value_conf(tGATT_TCB* p_tcb, uint8_t op_code) {
   uint16_t handle = p_tcb->indicate_handle;
   uint32_t trans_id;
-  uint8_t i;
-  tGATT_SR_REG* p_rcb = gatt_cb.sr_reg;
   bool continue_processing;
   uint16_t conn_id;
 
@@ -1230,10 +1177,10 @@
     continue_processing = gatts_proc_ind_ack(p_tcb, handle);
 
     if (continue_processing) {
-      for (i = 0; i < GATT_MAX_SR_PROFILES; i++, p_rcb++) {
-        if (p_rcb->in_use && p_rcb->s_hdl <= handle && p_rcb->e_hdl >= handle) {
+      for (auto& el : *gatt_cb.srv_list_info) {
+        if (el.s_hdl <= handle && el.e_hdl >= handle) {
           trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
-          conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_rcb->gatt_if);
+          conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, el.gatt_if);
           gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_CONF,
                                     (tGATTS_DATA*)&handle);
         }