Implement robust caching (server)

Flag:
- Use flag to enable/disable robust caching on server side

btif_storage
- Add APIs to set/get/remove database hash and client supported features

Database Hash
- Add database hash definition into GATT profile
- Set client to change aware when reading database hash

Client Supported Features
- Add write check for client supported features characteristic
- Store client supported feature into btif_storage

Behaviors
- When a service is added/removed
  . Update database hash
  . Set clients that support robust caching to change unaware
- After ack for service changed indication is received
  . Set the client to change aware
- When the client is change unaware
  . Allow request of reading database hash (by handle or by uuid)
  . Allow write_execute, config_mtu and handle_value_conf
  . Send DATABASE_OUT_OF_SYNC error when it is a request
  . Ignore if it is a command
  . After the response is sent, set the client to change aware
- When a client is set from change unaware to change aware
  . Store current database hash to btif_stroage for that client

Connect and Disconnect:
- When a tGATT_TCB instance is allocated, load status from btif_storage
- When disconnected, if the device is untrusted, remove data from btif_storage

Tag: #feature
Test: atest net_test_stack_gatt_native:GattSrRobustCachingTest
Bug: 154056389
Change-Id: I81971012618472dd9e0e6a9e41868caa68998ad4
diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc
index 9685325..681189a 100644
--- a/stack/gatt/gatt_sr.cc
+++ b/stack/gatt/gatt_sr.cc
@@ -1190,6 +1190,9 @@
     /* there is no need to inform the application since srv chg is handled
      * internally by GATT */
     continue_processing = false;
+
+    // After receiving ack of svc_chg_ind, reset client status
+    gatt_sr_update_cl_status(tcb, /* chg_aware= */ true);
   }
 
   gatts_chk_pending_ind(tcb);
@@ -1232,6 +1235,80 @@
   }
 }
 
+static bool gatts_process_db_out_of_sync(tGATT_TCB& tcb, uint16_t cid,
+                                         uint8_t op_code, uint16_t len,
+                                         uint8_t* p_data) {
+  if (gatt_sr_is_cl_change_aware(tcb)) return false;
+
+  // default value
+  bool should_ignore = true;
+  bool should_rsp = true;
+
+  switch (op_code) {
+    case GATT_REQ_READ_BY_TYPE: {
+      // Check if read database hash by UUID
+      Uuid uuid = Uuid::kEmpty;
+      uint16_t s_hdl = 0, e_hdl = 0;
+      uint16_t db_hash_handle = gatt_cb.handle_of_database_hash;
+      tGATT_STATUS reason = gatts_validate_packet_format(op_code, len, p_data,
+                                                         &uuid, s_hdl, e_hdl);
+      if (reason == GATT_SUCCESS &&
+          (s_hdl <= db_hash_handle && db_hash_handle <= e_hdl) &&
+          (uuid == Uuid::From16Bit(GATT_UUID_DATABASE_HASH)))
+        should_ignore = false;
+
+    } break;
+    case GATT_REQ_READ: {
+      // Check if read database hash by handle
+      uint16_t handle = 0;
+      uint8_t* p = p_data;
+      tGATT_STATUS status = GATT_SUCCESS;
+
+      if (len < 2) {
+        status = GATT_INVALID_PDU;
+      } else {
+        STREAM_TO_UINT16(handle, p);
+        len -= 2;
+      }
+
+      if (status == GATT_SUCCESS && handle == gatt_cb.handle_of_database_hash)
+        should_ignore = false;
+
+    } break;
+    case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */
+    case GATT_REQ_FIND_TYPE_VALUE:  /* discover service by UUID */
+    case GATT_REQ_FIND_INFO:        /* discover char descrptor */
+    case GATT_REQ_READ_BLOB:        /* read long char */
+    case GATT_REQ_READ_MULTI:       /* read multi char*/
+    case GATT_REQ_WRITE:            /* write char/char descriptor value */
+    case GATT_REQ_PREPARE_WRITE:    /* write long char */
+      // Use default value
+      break;
+    case GATT_CMD_WRITE:      /* cmd */
+    case GATT_SIGN_CMD_WRITE: /* sign cmd */
+      should_rsp = false;
+      break;
+    case GATT_REQ_MTU:           /* configure mtu */
+    case GATT_REQ_EXEC_WRITE:    /* execute write */
+    case GATT_HANDLE_VALUE_CONF: /* confirm for indication */
+    default:
+      should_ignore = false;
+  }
+
+  if (should_ignore) {
+    if (should_rsp) {
+      gatt_send_error_rsp(tcb, cid, GATT_DATABASE_OUT_OF_SYNC, op_code, 0x0000,
+                          false);
+    }
+    LOG(INFO) << __func__ << ": database out of sync, device=" << tcb.peer_bda
+              << ", op_code=" << loghex((uint16_t)op_code)
+              << ", should_rsp=" << should_rsp;
+    gatt_sr_update_cl_status(tcb, /* chg_aware= */ should_rsp);
+  }
+
+  return should_ignore;
+}
+
 /** This function is called to handle the client requests to server */
 void gatt_server_handle_client_req(tGATT_TCB& tcb, uint16_t cid,
                                    uint8_t op_code, uint16_t len,
@@ -1254,6 +1331,9 @@
     }
     /* otherwise, ignore the pkt */
   } else {
+    // handle database out of sync
+    if (gatts_process_db_out_of_sync(tcb, cid, op_code, len, p_data)) return;
+
     switch (op_code) {
       case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */
       case GATT_REQ_FIND_TYPE_VALUE:  /* discover service by UUID */