resend discovery primary service ATT request with timeout

This is to work around the problem with iphone.
The iphone didn't respond with our first ATT request
(read By group type Request for for primary service).
the clockwork/phone host keep waiting for ATT response until disconnection
from iphone due to timeout.
The workaround is to
resend discovery primary service before disconnection from remote device
when response timeout happen.
This workaround will be better for us to interop with remote BLE device.

bug:12895830
Change-Id: I236af8eca9790f2dae7098061c74cec55348ca6d
diff --git a/system/stack/gatt/att_protocol.c b/system/stack/gatt/att_protocol.c
index 9c715af..3348599 100644
--- a/system/stack/gatt/att_protocol.c
+++ b/system/stack/gatt/att_protocol.c
@@ -495,7 +495,7 @@
                 /* do not enq cmd if handle value confirmation or set request */
                 if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
                 {
-                    gatt_start_rsp_timer (p_tcb);
+                    gatt_start_rsp_timer (clcb_idx);
                     gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
                 }
             }
diff --git a/system/stack/gatt/gatt_api.c b/system/stack/gatt/gatt_api.c
index b53b7c5..232b191 100644
--- a/system/stack/gatt/gatt_api.c
+++ b/system/stack/gatt/gatt_api.c
@@ -1285,6 +1285,7 @@
                     (p_clcb->p_reg->gatt_if == gatt_if) &&
                     (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
                 {
+                    btu_stop_timer(&p_clcb->rsp_timer_ent);
                     gatt_clcb_dealloc (p_clcb);
                     break;
                 }
diff --git a/system/stack/gatt/gatt_cl.c b/system/stack/gatt/gatt_cl.c
index b173be9..7457dcb 100644
--- a/system/stack/gatt/gatt_cl.c
+++ b/system/stack/gatt/gatt_cl.c
@@ -1096,7 +1096,7 @@
             /* dequeue the request if is write command or sign write */
             if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE)
             {
-                gatt_start_rsp_timer (p_tcb);
+                gatt_start_rsp_timer (p_cmd->clcb_idx);
             }
             else
             {
@@ -1153,7 +1153,10 @@
             return;
         }
         else
-            btu_stop_timer (&p_tcb->rsp_timer_ent);
+        {
+            btu_stop_timer (&p_clcb->rsp_timer_ent);
+            p_clcb->retry_count = 0;
+        }
     }
     /* the size of the message may not be bigger than the local max PDU size*/
     /* The message has to be smaller than the agreed MTU, len does not count op_code */
diff --git a/system/stack/gatt/gatt_int.h b/system/stack/gatt/gatt_int.h
index 48278c2..1f81d63 100644
--- a/system/stack/gatt/gatt_int.h
+++ b/system/stack/gatt/gatt_int.h
@@ -78,6 +78,8 @@
 
 /* wait for ATT cmd response timeout value */
 #define GATT_WAIT_FOR_RSP_TOUT       30
+#define GATT_WAIT_FOR_DISC_RSP_TOUT  5
+#define GATT_REQ_RETRY_LIMIT         2
 
 /* characteristic descriptor type */
 #define GATT_DESCR_EXT_DSCPTOR   1    /* Characteristic Extended Properties */
@@ -360,7 +362,6 @@
     UINT8            ind_count;
 
     tGATT_CMD_Q       cl_cmd_q[GATT_CL_MAX_LCB];
-    TIMER_LIST_ENT    rsp_timer_ent;        /* peer response timer */
     TIMER_LIST_ENT    ind_ack_timer_ent;    /* local app confirm to indication timer */
     UINT8             pending_cl_req;
     UINT8             next_slot_inq;    /* index of next available slot in queue */
@@ -397,6 +398,8 @@
     BOOLEAN                 first_read_blob_after_read;
     tGATT_READ_INC_UUID128  read_uuid128;
     BOOLEAN                 in_use;
+    TIMER_LIST_ENT          rsp_timer_ent;  /* peer response timer */
+    UINT8                   retry_count;
 } tGATT_CLCB;
 
 typedef struct
@@ -556,7 +559,7 @@
 extern UINT8 gatt_build_uuid_to_stream(UINT8 **p_dst, tBT_UUID uuid);
 extern BOOLEAN gatt_uuid_compare(tBT_UUID src, tBT_UUID tar);
 extern void gatt_sr_get_sec_info(BD_ADDR rem_bda, BOOLEAN le_conn, UINT8 *p_sec_flag, UINT8 *p_key_size);
-extern void gatt_start_rsp_timer(tGATT_TCB    *p_tcb);
+extern void gatt_start_rsp_timer(UINT16 clcb_idx);
 extern void gatt_start_conf_timer(tGATT_TCB    *p_tcb);
 extern void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle);
 extern void gatt_ind_ack_timeout(TIMER_LIST_ENT *p_tle);
diff --git a/system/stack/gatt/gatt_utils.c b/system/stack/gatt/gatt_utils.c
index e15918c..36f80a4 100644
--- a/system/stack/gatt/gatt_utils.c
+++ b/system/stack/gatt/gatt_utils.c
@@ -1116,11 +1116,18 @@
 ** Returns          TRUE if command sent, otherwise FALSE.
 **
 *******************************************************************************/
-void gatt_start_rsp_timer(tGATT_TCB    *p_tcb)
+void gatt_start_rsp_timer(UINT16 clcb_idx)
 {
-    p_tcb->rsp_timer_ent.param  = (TIMER_PARAM_TYPE)p_tcb;
-    btu_start_timer (&p_tcb->rsp_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP,
-                     GATT_WAIT_FOR_RSP_TOUT);
+    tGATT_CLCB *p_clcb = &gatt_cb.clcb[clcb_idx];
+    UINT32 timeout = GATT_WAIT_FOR_RSP_TOUT;
+    p_clcb->rsp_timer_ent.param  = (TIMER_PARAM_TYPE)p_clcb;
+    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+        p_clcb->op_subtype == GATT_DISC_SRVC_ALL)
+    {
+        timeout = GATT_WAIT_FOR_DISC_RSP_TOUT;
+    }
+    btu_start_timer (&p_clcb->rsp_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP,
+                     timeout);
 }
 /*******************************************************************************
 **
@@ -1165,8 +1172,32 @@
 *******************************************************************************/
 void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle)
 {
+    tGATT_CLCB *p_clcb = (tGATT_CLCB *)p_tle->param;
+    if (p_clcb == NULL || p_clcb->p_tcb == NULL)
+    {
+        GATT_TRACE_WARNING0("gatt_rsp_timeout clcb is already deleted");
+        return;
+    }
+    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+        p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
+        p_clcb->retry_count < GATT_REQ_RETRY_LIMIT)
+    {
+        UINT8 rsp_code;
+        GATT_TRACE_WARNING0("gatt_rsp_timeout retry discovery primary service");
+        if (p_clcb != gatt_cmd_dequeue(p_clcb->p_tcb, &rsp_code))
+        {
+            GATT_TRACE_ERROR0("gatt_rsp_timeout command queue out of sync, disconnect");
+        }
+        else
+        {
+            p_clcb->retry_count++;
+            gatt_act_discovery(p_clcb);
+            return;
+        }
+    }
+
     GATT_TRACE_WARNING0("gatt_rsp_timeout disconnecting...");
-    gatt_disconnect (((tGATT_TCB *)p_tle->param)->peer_bda);
+    gatt_disconnect (p_clcb->p_tcb->peer_bda);
 }
 
 /*******************************************************************************
@@ -2073,6 +2104,7 @@
 
     operation =  p_clcb->operation;
     conn_id = p_clcb->conn_id;
+    btu_stop_timer(&p_clcb->rsp_timer_ent);
 
     gatt_clcb_dealloc(p_clcb);
 
@@ -2114,6 +2146,7 @@
             p_clcb = &gatt_cb.clcb[i];
             if (p_clcb->in_use && p_clcb->p_tcb == p_tcb)
             {
+                btu_stop_timer(&p_clcb->rsp_timer_ent);
                 GATT_TRACE_DEBUG2 ("found p_clcb conn_id=%d clcb_idx=%d", p_clcb->conn_id, p_clcb->clcb_idx);
                 if (p_clcb->operation != GATTC_OPTYPE_NONE)
                     gatt_end_operation(p_clcb, GATT_ERROR, NULL);
@@ -2123,7 +2156,6 @@
             }
         }
 
-        btu_stop_timer (&p_tcb->rsp_timer_ent);
         btu_stop_timer (&p_tcb->ind_ack_timer_ent);
         btu_stop_timer (&p_tcb->conf_timer_ent);
         gatt_free_pending_ind(p_tcb);