Remove deadlock in WebRtcVideoEngine2.

Acquiring stream_lock_ in WebRtcVideoChannel2 in a callback from Call
forms a lock-order inversion between process-thread locks and libjingle
locks, manifesting as CPU adaptation requests blocking on stream
creation that is blocked on the CPU adaptation request finishing.

R=asapersson@webrtc.org, mflodman@webrtc.org
BUG=4535,chromium:475065

Review URL: https://webrtc-codereview.appspot.com/50679004

Cr-Commit-Position: refs/heads/master@{#8985}
diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc
index 939df41..42fe072 100644
--- a/talk/media/webrtc/webrtcvideoengine2.cc
+++ b/talk/media/webrtc/webrtcvideoengine2.cc
@@ -633,6 +633,7 @@
       external_decoder_factory_(external_decoder_factory) {
   SetDefaultOptions();
   options_.SetAll(options);
+  options_.cpu_overuse_detection.Get(&signal_cpu_adaptation_);
   webrtc::Call::Config config(this);
   config.overuse_callback = this;
   if (voice_engine != NULL) {
@@ -1144,13 +1145,15 @@
   LOG(LS_INFO) << "SetCapturer: " << ssrc << " -> "
                << (capturer != NULL ? "(capturer)" : "NULL");
   assert(ssrc != 0);
-  rtc::CritScope stream_lock(&stream_crit_);
-  if (send_streams_.find(ssrc) == send_streams_.end()) {
-    LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc;
-    return false;
-  }
-  if (!send_streams_[ssrc]->SetCapturer(capturer)) {
-    return false;
+  {
+    rtc::CritScope stream_lock(&stream_crit_);
+    if (send_streams_.find(ssrc) == send_streams_.end()) {
+      LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc;
+      return false;
+    }
+    if (!send_streams_[ssrc]->SetCapturer(capturer)) {
+      return false;
+    }
   }
 
   if (capturer) {
@@ -1158,6 +1161,10 @@
         !FindHeaderExtension(send_rtp_extensions_,
                              kRtpVideoRotationHeaderExtension));
   }
+  {
+    rtc::CritScope lock(&capturer_crit_);
+    capturers_[ssrc] = capturer;
+  }
   return true;
 }
 
@@ -1333,6 +1340,10 @@
     // No new options to set.
     return true;
   }
+  {
+    rtc::CritScope lock(&capturer_crit_);
+    options_.cpu_overuse_detection.Get(&signal_cpu_adaptation_);
+  }
   rtc::DiffServCodePoint dscp = options_.dscp.GetWithDefaultIfUnset(false)
                                     ? rtc::DSCP_AF41
                                     : rtc::DSCP_DEFAULT;
@@ -1372,14 +1383,18 @@
 }
 
 void WebRtcVideoChannel2::OnLoadUpdate(Load load) {
-  rtc::CritScope stream_lock(&stream_crit_);
-  for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
-           send_streams_.begin();
-       it != send_streams_.end();
-       ++it) {
-    it->second->OnCpuResolutionRequest(load == kOveruse
-                                           ? CoordinatedVideoAdapter::DOWNGRADE
-                                           : CoordinatedVideoAdapter::UPGRADE);
+  // OnLoadUpdate can not take any locks that are held while creating streams
+  // etc. Doing so establishes lock-order inversions between the webrtc process
+  // thread on stream creation and locks such as stream_crit_ while calling out.
+  rtc::CritScope stream_lock(&capturer_crit_);
+  if (!signal_cpu_adaptation_)
+    return;
+  for (auto& kv : capturers_) {
+    if (kv.second != nullptr && kv.second->video_adapter() != nullptr) {
+      kv.second->video_adapter()->OnCpuResolutionRequest(
+          load == kOveruse ? CoordinatedVideoAdapter::DOWNGRADE
+                           : CoordinatedVideoAdapter::UPGRADE);
+    }
   }
 }
 
@@ -1962,18 +1977,6 @@
   last_dimensions_.width = 0;
   SetDimensions(width, last_dimensions_.height, last_dimensions_.is_screencast);
 }
-void WebRtcVideoChannel2::WebRtcVideoSendStream::OnCpuResolutionRequest(
-    CoordinatedVideoAdapter::AdaptRequest adapt_request) {
-  rtc::CritScope cs(&lock_);
-  bool adapt_cpu;
-  parameters_.options.cpu_overuse_detection.Get(&adapt_cpu);
-  if (!adapt_cpu)
-    return;
-  if (capturer_ == NULL || capturer_->video_adapter() == NULL)
-    return;
-
-  capturer_->video_adapter()->OnCpuResolutionRequest(adapt_request);
-}
 
 void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() {
   if (stream_ != NULL) {
diff --git a/talk/media/webrtc/webrtcvideoengine2.h b/talk/media/webrtc/webrtcvideoengine2.h
index 3254015..321614d 100644
--- a/talk/media/webrtc/webrtcvideoengine2.h
+++ b/talk/media/webrtc/webrtcvideoengine2.h
@@ -295,9 +295,6 @@
 
     void SetMaxBitrateBps(int max_bitrate_bps);
 
-    void OnCpuResolutionRequest(
-        CoordinatedVideoAdapter::AdaptRequest adapt_request);
-
    private:
     // Parameters needed to reconstruct the underlying stream.
     // webrtc::VideoSendStream doesn't support setting a lot of options on the
@@ -497,6 +494,13 @@
   DefaultUnsignalledSsrcHandler default_unsignalled_ssrc_handler_;
   UnsignalledSsrcHandler* const unsignalled_ssrc_handler_;
 
+  // Separate list of set capturers used to signal CPU adaptation. These should
+  // not be locked while calling methods that take other locks to prevent
+  // lock-order inversions.
+  rtc::CriticalSection capturer_crit_;
+  bool signal_cpu_adaptation_ GUARDED_BY(capturer_crit_);
+  std::map<uint32, VideoCapturer*> capturers_ GUARDED_BY(capturer_crit_);
+
   rtc::CriticalSection stream_crit_;
   // Using primary-ssrc (first ssrc) as key.
   std::map<uint32, WebRtcVideoSendStream*> send_streams_