Merge "ExternalCamera: Fix a deadlock crash using std::thread" into main
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();
 }