From 443760d4baa80753b148ab5571628c3d80d2a896 Mon Sep 17 00:00:00 2001 From: Magnus Jedvert Date: Sun, 20 Jan 2019 13:44:45 +0100 Subject: [PATCH] Android: Add option to print native stack traces in PeerConnectionFactory API This CL hooks up the recently added native stack trace functionality to the existing PeerConnectionFactory API. Bug: webrtc:10168 Change-Id: I16189d2988b1359fc53f9a4d0b3d06f34e2a8fd5 Reviewed-on: https://webrtc-review.googlesource.com/c/118600 Reviewed-by: Tommi Commit-Queue: Magnus Jedvert Cr-Commit-Position: refs/heads/master@{#26344} --- sdk/android/BUILD.gn | 1 + .../api/org/webrtc/PeerConnectionFactory.java | 76 +++++++++++++------ .../src/jni/pc/peer_connection_factory.cc | 5 ++ 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 534865ec11..c6ffe73481 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -784,6 +784,7 @@ if (is_android) { ":generated_peerconnection_jni", ":logging_jni", ":native_api_jni", + ":native_api_stacktrace", "../..:webrtc_common", "../../api:libjingle_peerconnection_api", "../../api/video_codecs:video_codecs_api", diff --git a/sdk/android/api/org/webrtc/PeerConnectionFactory.java b/sdk/android/api/org/webrtc/PeerConnectionFactory.java index b68c816990..6d00baa2d5 100644 --- a/sdk/android/api/org/webrtc/PeerConnectionFactory.java +++ b/sdk/android/api/org/webrtc/PeerConnectionFactory.java @@ -11,6 +11,7 @@ package org.webrtc; import android.content.Context; +import android.os.Process; import android.support.annotation.Nullable; import java.util.List; import org.webrtc.Logging.Severity; @@ -29,17 +30,32 @@ public class PeerConnectionFactory { private static final String TAG = "PeerConnectionFactory"; private static final String VIDEO_CAPTURER_THREAD_NAME = "VideoCapturerThread"; + /** Helper class holding both Java and C++ thread info. */ + private static class ThreadInfo { + final Thread thread; + final int tid; + + public static ThreadInfo getCurrent() { + return new ThreadInfo(Thread.currentThread(), Process.myTid()); + } + + private ThreadInfo(Thread thread, int tid) { + this.thread = thread; + this.tid = tid; + } + } + private static volatile boolean internalTracerInitialized; // Remove these once deprecated static printStackTrace() is gone. - @Nullable private static Thread staticNetworkThread; - @Nullable private static Thread staticWorkerThread; - @Nullable private static Thread staticSignalingThread; + @Nullable private static ThreadInfo staticNetworkThread; + @Nullable private static ThreadInfo staticWorkerThread; + @Nullable private static ThreadInfo staticSignalingThread; private long nativeFactory; - @Nullable private volatile Thread networkThread; - @Nullable private volatile Thread workerThread; - @Nullable private volatile Thread signalingThread; + @Nullable private volatile ThreadInfo networkThread; + @Nullable private volatile ThreadInfo workerThread; + @Nullable private volatile ThreadInfo signalingThread; public static class InitializationOptions { final Context applicationContext; @@ -471,24 +487,37 @@ public class PeerConnectionFactory { } } - private static void printStackTrace(@Nullable Thread thread, String threadName) { - if (thread != null) { - StackTraceElement[] stackTraces = thread.getStackTrace(); - if (stackTraces.length > 0) { - Logging.w(TAG, threadName + " stacks trace:"); - for (StackTraceElement stackTrace : stackTraces) { - Logging.w(TAG, stackTrace.toString()); - } + private static void printStackTrace( + @Nullable ThreadInfo threadInfo, boolean printNativeStackTrace) { + if (threadInfo == null) { + // Thread callbacks have not been completed yet, ignore call. + return; + } + final String threadName = threadInfo.thread.getName(); + StackTraceElement[] stackTraces = threadInfo.thread.getStackTrace(); + if (stackTraces.length > 0) { + Logging.w(TAG, threadName + " stacktrace:"); + for (StackTraceElement stackTrace : stackTraces) { + Logging.w(TAG, stackTrace.toString()); } } + if (printNativeStackTrace) { + // Imitate output from debuggerd/tombstone so that stack trace can easily be symbolized with + // ndk-stack. + Logging.w(TAG, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***"); + Logging.w(TAG, + "pid: " + Process.myPid() + ", tid: " + threadInfo.tid + ", name: " + threadName + + " >>> WebRTC <<<"); + nativePrintStackTrace(threadInfo.tid); + } } /** Deprecated, use non-static version instead. */ @Deprecated public static void printStackTraces() { - printStackTrace(staticNetworkThread, "Network thread"); - printStackTrace(staticWorkerThread, "Worker thread"); - printStackTrace(staticSignalingThread, "Signaling thread"); + printStackTrace(staticNetworkThread, /* printNativeStackTrace= */ false); + printStackTrace(staticWorkerThread, /* printNativeStackTrace= */ false); + printStackTrace(staticSignalingThread, /* printNativeStackTrace= */ false); } /** @@ -497,28 +526,28 @@ public class PeerConnectionFactory { * attempt to print the C++ stack traces for these threads. */ public void printInternalStackTraces(boolean printNativeStackTraces) { - printStackTrace(signalingThread, "Signaling thread"); - printStackTrace(workerThread, "Worker thread"); - printStackTrace(networkThread, "Network thread"); + printStackTrace(signalingThread, printNativeStackTraces); + printStackTrace(workerThread, printNativeStackTraces); + printStackTrace(networkThread, printNativeStackTraces); } @CalledByNative private void onNetworkThreadReady() { - networkThread = Thread.currentThread(); + networkThread = ThreadInfo.getCurrent(); staticNetworkThread = networkThread; Logging.d(TAG, "onNetworkThreadReady"); } @CalledByNative private void onWorkerThreadReady() { - workerThread = Thread.currentThread(); + workerThread = ThreadInfo.getCurrent(); staticWorkerThread = workerThread; Logging.d(TAG, "onWorkerThreadReady"); } @CalledByNative private void onSignalingThreadReady() { - signalingThread = Thread.currentThread(); + signalingThread = ThreadInfo.getCurrent(); staticSignalingThread = signalingThread; Logging.d(TAG, "onSignalingThreadReady"); } @@ -558,4 +587,5 @@ public class PeerConnectionFactory { private static native long nativeGetNativePeerConnectionFactory(long factory); private static native void nativeInjectLoggable(JNILogging jniLogging, int severity); private static native void nativeDeleteLoggable(); + private static native void nativePrintStackTrace(int tid); } diff --git a/sdk/android/src/jni/pc/peer_connection_factory.cc b/sdk/android/src/jni/pc/peer_connection_factory.cc index 040753dd25..79ac7324fd 100644 --- a/sdk/android/src/jni/pc/peer_connection_factory.cc +++ b/sdk/android/src/jni/pc/peer_connection_factory.cc @@ -26,6 +26,7 @@ #include "rtc_base/thread.h" #include "sdk/android/generated_peerconnection_jni/jni/PeerConnectionFactory_jni.h" #include "sdk/android/native_api/jni/java_types.h" +#include "sdk/android/native_api/stacktrace/stacktrace.h" #include "sdk/android/src/jni/jni_helpers.h" #include "sdk/android/src/jni/logging/log_sink.h" #include "sdk/android/src/jni/pc/android_network_monitor.h" @@ -515,5 +516,9 @@ static void JNI_PeerConnectionFactory_DeleteLoggable(JNIEnv* jni) { } } +static void JNI_PeerConnectionFactory_PrintStackTrace(JNIEnv* env, jint tid) { + RTC_LOG(LS_WARNING) << StackTraceToString(GetStackTrace(tid)); +} + } // namespace jni } // namespace webrtc