QCamera2: Sync stream stop with poll updates

 The stream command thread will be released as
 part of the stream stop but the channel poll
 thread can still run until the channel is released.
 In this case the synchronous poll delete during
 stream stop can fail if the asynchronous poll version
 got triggered immediately before that. The stop
 will proceed and release the stream command thread
 resources before the async poll update could be
 processed. The poll thread could then try and
 access the command thread resources resulting in
 a crash. The failing sync poll delete should be
 handled by syncing to the poll thread again and
 allowing any previously pending async updates to
 be processed before releasing any resources.

Bug: 14028116
CRs-Fixed: 629996
Change-Id: Ib6252445731d05c01a59503b3cfe70ef089a4ffd
diff --git a/camera/QCamera2/stack/mm-camera-interface/inc/mm_camera.h b/camera/QCamera2/stack/mm-camera-interface/inc/mm_camera.h
index bcac23e..4d7b511 100644
--- a/camera/QCamera2/stack/mm-camera-interface/inc/mm_camera.h
+++ b/camera/QCamera2/stack/mm-camera-interface/inc/mm_camera.h
@@ -569,6 +569,8 @@
                                 mm_camera_poll_thread_t * poll_cb,
                                 uint32_t handler,
                                 mm_camera_call_type_t);
+extern int32_t mm_camera_poll_thread_commit_updates(
+        mm_camera_poll_thread_t * poll_cb);
 extern int32_t mm_camera_cmd_thread_launch(
                                 mm_camera_cmd_thread_t * cmd_thread,
                                 mm_camera_cmd_cb_t cb,
diff --git a/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c b/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c
index 745d0dd..9ccfed7 100644
--- a/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c
+++ b/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_stream.c
@@ -911,7 +911,17 @@
          __func__, my_obj->my_hdl, my_obj->fd, my_obj->state);
 
     /* step1: remove fd from data poll thread */
-    mm_camera_poll_thread_del_poll_fd(&my_obj->ch_obj->poll_thread[0], my_obj->my_hdl, mm_camera_sync_call);
+    rc = mm_camera_poll_thread_del_poll_fd(&my_obj->ch_obj->poll_thread[0],
+            my_obj->my_hdl, mm_camera_sync_call);
+    if (rc < 0) {
+        /* The error might be due to async update. In this case
+         * wait for all updates to complete before proceeding. */
+        rc = mm_camera_poll_thread_commit_updates(&my_obj->ch_obj->poll_thread[0]);
+        if (rc < 0) {
+            CDBG_ERROR("%s: Poll sync failed %d",
+                 __func__, rc);
+        }
+    }
 
     /* step2: stream off */
     rc = ioctl(my_obj->fd, VIDIOC_STREAMOFF, &buf_type);
diff --git a/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_thread.c b/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_thread.c
index 074af3b..9f0dfe7 100644
--- a/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_thread.c
+++ b/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_thread.c
@@ -46,6 +46,8 @@
     MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED,
     /* poll entries updated */
     MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC,
+    /* commit updates */
+    MM_CAMERA_PIPE_CMD_COMMIT,
     /* exit */
     MM_CAMERA_PIPE_CMD_EXIT,
     /* max count */
@@ -252,6 +254,9 @@
             mm_camera_poll_sig_done(poll_cb);
         break;
 
+    case MM_CAMERA_PIPE_CMD_COMMIT:
+        mm_camera_poll_sig_done(poll_cb);
+        break;
     case MM_CAMERA_PIPE_CMD_EXIT:
     default:
         mm_camera_poll_set_state(poll_cb, MM_CAMERA_POLL_TASK_STATE_STOPPED);
@@ -359,6 +364,23 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : mm_camera_poll_thread_commit_updates
+ *
+ * DESCRIPTION: sync with all previously pending async updates
+ *
+ * PARAMETERS :
+ *   @poll_cb : ptr to poll thread object
+ *
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
+ *==========================================================================*/
+int32_t mm_camera_poll_thread_commit_updates(mm_camera_poll_thread_t * poll_cb)
+{
+    return mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_COMMIT);
+}
+
+/*===========================================================================
  * FUNCTION   : mm_camera_poll_thread_add_poll_fd
  *
  * DESCRIPTION: add a new fd into polling thread
@@ -420,7 +442,9 @@
  *   @handler   : stream handle if channel data polling thread,
  *                0 if event polling thread
  *
- * RETURN     : none
+ * RETURN     : int32_t type of status
+ *              0  -- success
+ *              -1 -- failure
  *==========================================================================*/
 int32_t mm_camera_poll_thread_del_poll_fd(mm_camera_poll_thread_t * poll_cb,
                                           uint32_t handler,
@@ -453,6 +477,7 @@
     } else {
         CDBG_ERROR("%s: invalid handler %d (%d)",
                    __func__, handler, idx);
+        return -1;
     }
 
     return rc;