Expose connection update callback (1/3)

Test: manual
Bug: 30622771
Change-Id: I94d25f6f22b42fb1432a9288c97b82503d57db86
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index 89aef54..e8f28ee 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -64,6 +64,9 @@
 static void bta_gattc_phy_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
                                        uint8_t tx_phy, uint8_t rx_phy,
                                        uint8_t status);
+static void bta_gattc_conn_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+                                        uint16_t interval, uint16_t latency,
+                                        uint16_t timeout, uint8_t status);
 
 static tGATT_CBACK bta_gattc_cl_cback = {bta_gattc_conn_cback,
                                          bta_gattc_cmpl_cback,
@@ -72,7 +75,8 @@
                                          NULL,
                                          bta_gattc_enc_cmpl_cback,
                                          bta_gattc_cong_cback,
-                                         bta_gattc_phy_update_cback};
+                                         bta_gattc_phy_update_cback,
+                                         bta_gattc_conn_update_cback};
 
 /* opcode(tGATTC_OPTYPE) order has to be comply with internal event order */
 static uint16_t bta_gattc_opcode_to_int_evt[] = {
@@ -1723,3 +1727,22 @@
   cb_data.phy_update.status = status;
   (*p_clreg->p_cback)(BTA_GATTC_PHY_UPDATE_EVT, &cb_data);
 }
+
+static void bta_gattc_conn_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+                                        uint16_t interval, uint16_t latency,
+                                        uint16_t timeout, uint8_t status) {
+  tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(gatt_if);
+
+  if (!p_clreg || !p_clreg->p_cback) {
+    APPL_TRACE_ERROR("%s: client_if=%d not found", __func__, gatt_if);
+    return;
+  }
+
+  tBTA_GATTC cb_data;
+  cb_data.conn_update.conn_id = conn_id;
+  cb_data.conn_update.interval = interval;
+  cb_data.conn_update.latency = latency;
+  cb_data.conn_update.timeout = timeout;
+  cb_data.conn_update.status = status;
+  (*p_clreg->p_cback)(BTA_GATTC_CONN_UPDATE_EVT, &cb_data);
+}
diff --git a/bta/gatt/bta_gatts_act.cc b/bta/gatt/bta_gatts_act.cc
index 5f87e74..86dfd9a 100644
--- a/bta/gatt/bta_gatts_act.cc
+++ b/bta/gatt/bta_gatts_act.cc
@@ -52,6 +52,9 @@
 static void bta_gatts_phy_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
                                        uint8_t tx_phy, uint8_t rx_phy,
                                        uint8_t status);
+static void bta_gatts_conn_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+                                        uint16_t interval, uint16_t latency,
+                                        uint16_t timeout, uint8_t status);
 
 static tGATT_CBACK bta_gatts_cback = {bta_gatts_conn_cback,
                                       NULL,
@@ -60,7 +63,8 @@
                                       bta_gatts_send_request_cback,
                                       NULL,
                                       bta_gatts_cong_cback,
-                                      bta_gatts_phy_update_cback};
+                                      bta_gatts_phy_update_cback,
+                                      bta_gatts_conn_update_cback};
 
 tGATT_APPL_INFO bta_gatts_nv_cback = {bta_gatts_nv_save_cback,
                                       bta_gatts_nv_srv_chg_cback};
@@ -631,6 +635,25 @@
   (*p_reg->p_cback)(BTA_GATTS_PHY_UPDATE_EVT, &cb_data);
 }
 
+static void bta_gatts_conn_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+                                        uint16_t interval, uint16_t latency,
+                                        uint16_t timeout, uint8_t status) {
+  tBTA_GATTS_RCB* p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+  if (!p_reg || !p_reg->p_cback) {
+    APPL_TRACE_ERROR("%s: server_if=%d not found", __func__, gatt_if);
+    return;
+  }
+
+  tBTA_GATTS cb_data;
+  cb_data.conn_update.conn_id = conn_id;
+  cb_data.conn_update.server_if = gatt_if;
+  cb_data.conn_update.interval = interval;
+  cb_data.conn_update.latency = latency;
+  cb_data.conn_update.timeout = timeout;
+  cb_data.conn_update.status = status;
+  (*p_reg->p_cback)(BTA_GATTS_CONN_UPDATE_EVT, &cb_data);
+}
+
 /*******************************************************************************
  *
  * Function         bta_gatts_cong_cback
diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h
index f4a82ff..ac09c18 100644
--- a/bta/include/bta_gatt_api.h
+++ b/bta/include/bta_gatt_api.h
@@ -120,6 +120,7 @@
 #define BTA_GATTC_CFG_MTU_EVT 18     /* configure MTU complete event */
 #define BTA_GATTC_CONGEST_EVT 24     /* Congestion event */
 #define BTA_GATTC_PHY_UPDATE_EVT 25  /* PHY change event */
+#define BTA_GATTC_CONN_UPDATE_EVT 26 /* Connection parameters update event */
 
 typedef uint8_t tBTA_GATTC_EVT;
 
@@ -313,6 +314,15 @@
   tBTA_GATT_STATUS status;
 } tBTA_GATTC_PHY_UPDATE;
 
+typedef struct {
+  tBTA_GATTC_IF server_if;
+  uint16_t conn_id;
+  uint16_t interval;
+  uint16_t latency;
+  uint16_t timeout;
+  tBTA_GATT_STATUS status;
+} tBTA_GATTC_CONN_UPDATE;
+
 typedef union {
   tBTA_GATT_STATUS status;
 
@@ -330,6 +340,7 @@
   tBTA_GATTC_CFG_MTU cfg_mtu; /* configure MTU operation */
   tBTA_GATTC_CONGEST congest;
   tBTA_GATTC_PHY_UPDATE phy_update;
+  tBTA_GATTC_CONN_UPDATE conn_update;
 } tBTA_GATTC;
 
 /* GATTC enable callback function */
@@ -360,6 +371,7 @@
 #define BTA_GATTS_CLOSE_EVT 18
 #define BTA_GATTS_CONGEST_EVT 20
 #define BTA_GATTS_PHY_UPDATE_EVT 21
+#define BTA_GATTS_CONN_UPDATE_EVT 22
 
 typedef uint8_t tBTA_GATTS_EVT;
 typedef tGATT_IF tBTA_GATTS_IF;
@@ -506,6 +518,15 @@
   tBTA_GATT_STATUS status;
 } tBTA_GATTS_PHY_UPDATE;
 
+typedef struct {
+  tBTA_GATTS_IF server_if;
+  uint16_t conn_id;
+  uint16_t interval;
+  uint16_t latency;
+  uint16_t timeout;
+  tBTA_GATT_STATUS status;
+} tBTA_GATTS_CONN_UPDATE;
+
 /* GATTS callback data */
 typedef union {
   tBTA_GATTS_REG_OPER reg_oper;
@@ -517,6 +538,8 @@
   tBTA_GATTS_CONGEST congest; /* BTA_GATTS_CONGEST_EVT callback data */
   tBTA_GATTS_CONF confirm;    /* BTA_GATTS_CONF_EVT callback data */
   tBTA_GATTS_PHY_UPDATE phy_update; /* BTA_GATTS_PHY_UPDATE_EVT callback data */
+  tBTA_GATTS_CONN_UPDATE
+      conn_update; /* BTA_GATTS_CONN_UPDATE_EVT callback data */
 } tBTA_GATTS;
 
 /* GATTS enable callback function */
diff --git a/btif/src/btif_gatt_client.cc b/btif/src/btif_gatt_client.cc
index 82f06dc..4dad646 100644
--- a/btif/src/btif_gatt_client.cc
+++ b/btif/src/btif_gatt_client.cc
@@ -186,6 +186,13 @@
                 p_data->phy_update.rx_phy, p_data->phy_update.status);
       break;
 
+    case BTA_GATTC_CONN_UPDATE_EVT:
+      HAL_CBACK(bt_gatt_callbacks, client->conn_updated_cb,
+                p_data->conn_update.conn_id, p_data->conn_update.interval,
+                p_data->conn_update.latency, p_data->conn_update.timeout,
+                p_data->conn_update.status);
+      break;
+
     default:
       LOG_ERROR(LOG_TAG, "%s: Unhandled event (%d)!", __func__, event);
       break;
diff --git a/btif/src/btif_gatt_server.cc b/btif/src/btif_gatt_server.cc
index ef7aa96..24f0346 100644
--- a/btif/src/btif_gatt_server.cc
+++ b/btif/src/btif_gatt_server.cc
@@ -254,6 +254,13 @@
                 p_data->phy_update.rx_phy, p_data->phy_update.status);
       break;
 
+    case BTA_GATTS_CONN_UPDATE_EVT:
+      HAL_CBACK(bt_gatt_callbacks, server->conn_updated_cb,
+                p_data->conn_update.conn_id, p_data->conn_update.interval,
+                p_data->conn_update.latency, p_data->conn_update.timeout,
+                p_data->conn_update.status);
+      break;
+
     default:
       LOG_ERROR(LOG_TAG, "%s: Unhandled event (%d)!", __func__, event);
       break;
diff --git a/btif/src/btif_gatt_test.cc b/btif/src/btif_gatt_test.cc
index c5faf27..73cffc5 100644
--- a/btif/src/btif_gatt_test.cc
+++ b/btif/src/btif_gatt_test.cc
@@ -193,6 +193,7 @@
                                           NULL,
                                           NULL,
                                           NULL,
+                                          NULL,
                                           NULL};
 
 /*******************************************************************************
diff --git a/service/gatt_server_old.cc b/service/gatt_server_old.cc
index 3e74261..d6fac7f 100644
--- a/service/gatt_server_old.cc
+++ b/service/gatt_server_old.cc
@@ -419,6 +419,7 @@
     nullptr, /* congestion_cb*/
     nullptr, /* mtu_changed_cb */
     nullptr, /* phy_update_cb */
+    nullptr, /* conn_update_cb */
 };
 
 // TODO(eisenbach): Refactor GATT interface to not require servers
@@ -442,6 +443,7 @@
     nullptr, /* services_removed_cb */
     nullptr, /* services_added_cb */
     nullptr, /* phy_update_cb */
+    nullptr, /* conn_update_cb */
 };
 
 const btgatt_scanner_callbacks_t gatt_scanner_callbacks = {
diff --git a/service/hal/bluetooth_gatt_interface.cc b/service/hal/bluetooth_gatt_interface.cc
index 65b6b45..936a053 100644
--- a/service/hal/bluetooth_gatt_interface.cc
+++ b/service/hal/bluetooth_gatt_interface.cc
@@ -404,6 +404,7 @@
     ServicesRemovedCallback,
     ServicesAddedCallback,
     nullptr,
+    nullptr,
 };
 
 const btgatt_server_callbacks_t gatt_server_callbacks = {
@@ -422,6 +423,7 @@
     nullptr,  // congestion_cb
     MtuChangedCallback,
     nullptr,
+    nullptr,
 };
 
 const btgatt_callbacks_t gatt_callbacks = {
diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc
index a4f1c06..560d358 100644
--- a/stack/btu/btu_hcif.cc
+++ b/stack/btu/btu_hcif.cc
@@ -1666,6 +1666,11 @@
   btm_ble_conn_complete(p, evt_len, true);
 }
 #endif
+
+extern void gatt_notify_conn_update(uint16_t handle, uint16_t interval,
+                                    uint16_t latency, uint16_t timeout,
+                                    uint8_t status);
+
 static void btu_ble_ll_conn_param_upd_evt(uint8_t* p, uint16_t evt_len) {
   /* LE connection update has completed successfully as a master. */
   /* We can enable the update request if the result is a success. */
@@ -1683,6 +1688,8 @@
   STREAM_TO_UINT16(timeout, p);
 
   l2cble_process_conn_update_evt(handle, status, interval, latency, timeout);
+
+  gatt_notify_conn_update(handle & 0x0FFF, interval, latency, timeout, status);
 }
 
 static void btu_ble_read_remote_feat_evt(uint8_t* p) {
diff --git a/stack/gap/gap_ble.cc b/stack/gap/gap_ble.cc
index f6313f7..6e42ad5 100644
--- a/stack/gap/gap_ble.cc
+++ b/stack/gap/gap_ble.cc
@@ -61,6 +61,7 @@
                                 gap_ble_s_attr_request_cback,
                                 NULL,
                                 NULL,
+                                NULL,
                                 NULL};
 
 /*******************************************************************************
diff --git a/stack/gatt/gatt_api.cc b/stack/gatt/gatt_api.cc
index 20def14..af16df7 100644
--- a/stack/gatt/gatt_api.cc
+++ b/stack/gatt/gatt_api.cc
@@ -663,7 +663,7 @@
   uint8_t status, tx_phy, rx_phy;
   uint16_t handle;
 
-  LOG_ASSERT(len == 5) << "Received bad response length";
+  LOG_ASSERT(len == 5) << "Received bad response length: " << len;
   uint8_t* pp = data;
   STREAM_TO_UINT8(status, pp);
   STREAM_TO_UINT16(handle, pp);
diff --git a/stack/gatt/gatt_attr.cc b/stack/gatt/gatt_attr.cc
index e2b85cd..3730ee6 100644
--- a/stack/gatt/gatt_attr.cc
+++ b/stack/gatt/gatt_attr.cc
@@ -66,6 +66,7 @@
                                          gatt_request_cback,
                                          NULL,
                                          NULL,
+                                         NULL,
                                          NULL};
 
 /*******************************************************************************
diff --git a/stack/gatt/gatt_main.cc b/stack/gatt/gatt_main.cc
index ddec58e..7c2ab7a 100644
--- a/stack/gatt/gatt_main.cc
+++ b/stack/gatt/gatt_main.cc
@@ -499,6 +499,28 @@
   }
 }
 
+void gatt_notify_conn_update(uint16_t handle, uint16_t interval,
+                             uint16_t latency, uint16_t timeout,
+                             uint8_t status) {
+  tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+  if (!p_dev_rec) {
+    return;
+  }
+
+  tGATT_TCB* p_tcb =
+      gatt_find_tcb_by_addr(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
+  if (p_tcb == NULL) return;
+
+  for (int i = 0; i < GATT_MAX_APPS; i++) {
+    tGATT_REG* p_reg = &gatt_cb.cl_rcb[i];
+    if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) {
+      uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+      (*p_reg->app_cb.p_conn_update_cb)(p_reg->gatt_if, conn_id, interval,
+                                        latency, timeout, status);
+    }
+  }
+}
+
 /*******************************************************************************
  *
  * Function         gatt_le_cong_cback
diff --git a/stack/include/gatt_api.h b/stack/include/gatt_api.h
index 263c6d4..631cdfc 100644
--- a/stack/include/gatt_api.h
+++ b/stack/include/gatt_api.h
@@ -584,6 +584,11 @@
                                   uint8_t tx_phy, uint8_t rx_phy,
                                   uint8_t status);
 
+/* Define a callback function when connection parameters are updated */
+typedef void(tGATT_CONN_UPDATE_CB)(tGATT_IF gatt_if, uint16_t conn_id,
+                                   uint16_t interval, uint16_t latency,
+                                   uint16_t timeout, uint8_t status);
+
 /* Define the structure that applications use to register with
  * GATT. This structure includes callback functions. All functions
  * MUST be provided.
@@ -597,6 +602,7 @@
   tGATT_ENC_CMPL_CB* p_enc_cmpl_cb;
   tGATT_CONGESTION_CBACK* p_congestion_cb;
   tGATT_PHY_UPDATE_CB* p_phy_update_cb;
+  tGATT_CONN_UPDATE_CB* p_conn_update_cb;
 } tGATT_CBACK;
 
 /*****************  Start Handle Management Definitions   *********************/
diff --git a/stack/srvc/srvc_eng.cc b/stack/srvc/srvc_eng.cc
index 1af3627..568b66e 100644
--- a/stack/srvc/srvc_eng.cc
+++ b/stack/srvc/srvc_eng.cc
@@ -43,6 +43,7 @@
                                       srvc_eng_s_request_cback,
                                       NULL,
                                       NULL,
+                                      NULL,
                                       NULL};
 /* type for action functions */
 typedef void (*tSRVC_ENG_C_CMPL_ACTION)(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op,