Add option to print peer connection factory Java stack traces.

R=wzh@webrtc.org

Review URL: https://codereview.webrtc.org/1395693002 .

Cr-Commit-Position: refs/heads/master@{#10204}
diff --git a/talk/app/webrtc/java/jni/classreferenceholder.cc b/talk/app/webrtc/java/jni/classreferenceholder.cc
index 25b72da..d99aa1a 100644
--- a/talk/app/webrtc/java/jni/classreferenceholder.cc
+++ b/talk/app/webrtc/java/jni/classreferenceholder.cc
@@ -99,6 +99,7 @@
   LoadClass(jni, "org/webrtc/MediaSource$State");
   LoadClass(jni, "org/webrtc/MediaStream");
   LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
+  LoadClass(jni, "org/webrtc/PeerConnectionFactory");
   LoadClass(jni, "org/webrtc/PeerConnection$BundlePolicy");
   LoadClass(jni, "org/webrtc/PeerConnection$ContinualGatheringPolicy");
   LoadClass(jni, "org/webrtc/PeerConnection$RtcpMuxPolicy");
diff --git a/talk/app/webrtc/java/jni/peerconnection_jni.cc b/talk/app/webrtc/java/jni/peerconnection_jni.cc
index 2d14dee..ddf1c8e 100644
--- a/talk/app/webrtc/java/jni/peerconnection_jni.cc
+++ b/talk/app/webrtc/java/jni/peerconnection_jni.cc
@@ -1075,8 +1075,11 @@
   PeerConnectionFactoryInterface* factory() { return factory_; }
   WebRtcVideoEncoderFactory* encoder_factory() { return encoder_factory_; }
   WebRtcVideoDecoderFactory* decoder_factory() { return decoder_factory_; }
+  void InvokeJavaCallbacksOnFactoryThreads();
 
  private:
+  void JavaCallbackOnFactoryThreads();
+
   const scoped_ptr<Thread> worker_thread_;
   const scoped_ptr<Thread> signaling_thread_;
   WebRtcVideoEncoderFactory* encoder_factory_;
@@ -1084,6 +1087,34 @@
   PeerConnectionFactoryInterface* factory_;  // Const after ctor except dtor.
 };
 
+void OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads() {
+  JNIEnv* jni = AttachCurrentThreadIfNeeded();
+  ScopedLocalRefFrame local_ref_frame(jni);
+  jclass j_factory_class = FindClass(jni, "org/webrtc/PeerConnectionFactory");
+  jmethodID m = nullptr;
+  if (Thread::Current() == worker_thread_) {
+    LOG(LS_INFO) << "Worker thread JavaCallback";
+    m = GetStaticMethodID(jni, j_factory_class, "onWorkerThreadReady", "()V");
+  }
+  if (Thread::Current() == signaling_thread_) {
+    LOG(LS_INFO) << "Signaling thread JavaCallback";
+    m = GetStaticMethodID(
+        jni, j_factory_class, "onSignalingThreadReady", "()V");
+  }
+  if (m != nullptr) {
+    jni->CallStaticVoidMethod(j_factory_class, m);
+    CHECK_EXCEPTION(jni) << "error during JavaCallback::CallStaticVoidMethod";
+  }
+}
+
+void OwnedFactoryAndThreads::InvokeJavaCallbacksOnFactoryThreads() {
+  LOG(LS_INFO) << "InvokeJavaCallbacksOnFactoryThreads.";
+  worker_thread_->Invoke<void>(
+      Bind(&OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads, this));
+  signaling_thread_->Invoke<void>(
+      Bind(&OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads, this));
+}
+
 JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
     JNIEnv* jni, jclass) {
   // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
@@ -1119,10 +1150,11 @@
       worker_thread, signaling_thread,
       encoder_factory, decoder_factory,
       factory.release());
+  owned_factory->InvokeJavaCallbacksOnFactoryThreads();
   return jlongFromPointer(owned_factory);
 }
 
-JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
+JOW(void, PeerConnectionFactory_nativeFreeFactory)(JNIEnv*, jclass, jlong j_p) {
   delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
   if (field_trials_init_string) {
     webrtc::field_trial::InitFieldTrialsFromString(NULL);
@@ -1136,6 +1168,13 @@
   return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
 }
 
+JOW(void, PeerConnectionFactory_nativeThreadsCallbacks)(
+    JNIEnv*, jclass, jlong j_p) {
+  OwnedFactoryAndThreads *factory =
+      reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
+  factory->InvokeJavaCallbacksOnFactoryThreads();
+}
+
 JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
     JNIEnv* jni, jclass, jlong native_factory, jstring label) {
   rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
diff --git a/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java b/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
index 7d95485..6bc8189 100644
--- a/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
+++ b/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
@@ -39,7 +39,10 @@
     System.loadLibrary("jingle_peerconnection_so");
   }
 
+  private static final String TAG = "PeerConnectionFactory";
   private final long nativeFactory;
+  private static Thread workerThread;
+  private static Thread signalingThread;
 
   public static class Options {
     // Keep in sync with webrtc/base/network.h!
@@ -136,7 +139,38 @@
   }
 
   public void dispose() {
-    freeFactory(nativeFactory);
+    nativeFreeFactory(nativeFactory);
+    signalingThread = null;
+    workerThread = null;
+  }
+
+  public void threadsCallbacks() {
+    nativeThreadsCallbacks(nativeFactory);
+  }
+
+  public static void printStackTraces() {
+    if (workerThread != null) {
+      Logging.d(TAG, "Worker thread stacks trace:");
+      for (StackTraceElement stackTrace : workerThread.getStackTrace()) {
+        Logging.d(TAG, stackTrace.toString());
+      }
+    }
+    if (signalingThread != null) {
+      Logging.d(TAG, "Signaling thread stacks trace:");
+      for (StackTraceElement stackTrace : signalingThread.getStackTrace()) {
+        Logging.d(TAG, stackTrace.toString());
+      }
+    }
+  }
+
+  private static void onWorkerThreadReady() {
+    workerThread = Thread.currentThread();
+    Logging.d(TAG, "onWorkerThreadReady");
+  }
+
+  private static void onSignalingThreadReady() {
+    signalingThread = Thread.currentThread();
+    Logging.d(TAG, "onSignalingThreadReady");
   }
 
   private static native long nativeCreatePeerConnectionFactory();
@@ -169,5 +203,7 @@
   private static native void nativeSetVideoHwAccelerationOptions(
       long nativeFactory, Object renderEGLContext);
 
-  private static native void freeFactory(long nativeFactory);
+  private static native void nativeThreadsCallbacks(long nativeFactory);
+
+  private static native void nativeFreeFactory(long nativeFactory);
 }