ExternalCamera: Fix a deadlock crash using std::thread

It's not a good idea to call join() from std::thread's destructor.

In this case, the order of sequence is:

1. OutputThread::threadLoop runs to completion, holding the last
   ExternalCameraDeviceSession reference,
2. Upon exiting OutputThread::threadLopp, ~ExternalCameraDeviceSession
   is called, which calls OutputThread.requestExitAndWait()

In this sequence, the requesetExitAndWait() is joining on itself,
causing deadlock. Check the calling thread id before calling
'join'. If the calling thread id matches the 'thread' object's thread
id, use 'detach' instead.

Test: Run VTS on a USB camera
Flag: EXEMPT bugfix
Bug: 399939768
Change-Id: Ic39a2d54828f4269a29ba047dee8e6644fef62a4
diff --git a/camera/common/default/SimpleThread.cpp b/camera/common/default/SimpleThread.cpp
index 46e89ba..f084970 100644
--- a/camera/common/default/SimpleThread.cpp
+++ b/camera/common/default/SimpleThread.cpp
@@ -24,9 +24,13 @@
 
 SimpleThread::SimpleThread() : mDone(true), mThread() {}
 SimpleThread::~SimpleThread() {
-    // Safe to call requestExitAndWait() from the destructor because requestExitAndWait() ensures
-    // that the thread is joinable before joining on it. This is different from how
-    // android::Thread worked.
+    // b/399939768: We need to be careful calling requestExitAndWait() from
+    // the destructor due to the possibility of
+    // OutputThread::threadLoop->~ExternalCameraDeviceSession->~OutputThread::requestExit()
+    // resulting in join() called on the calling thread.
+    //
+    // Rather than removing `requestExitAndExit`, we guard the `join` call
+    // in it by checking the thread id.
     requestExitAndWait();
 }
 
@@ -43,9 +47,15 @@
     mDone.store(true, std::memory_order_release);
 
     // Wait for thread to exit if needed. This should happen in no more than one iteration of
-    // threadLoop
+    // threadLoop. Only call 'join' if this function is called from a thread
+    // different from the thread associated with this object. Otherwise call
+    // 'detach' so that the threadLoop can finish and clean up itself.
     if (mThread.joinable()) {
-        mThread.join();
+        if (mThread.get_id() != std::this_thread::get_id()) {
+            mThread.join();
+        } else {
+            mThread.detach();
+        }
     }
     mThread = std::thread();
 }