diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn index e7dfb9e96e..ceb5b02a4a 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -1325,6 +1325,7 @@ if (is_android) { rtc_android_library("base_java") { java_files = [ "java/src/org/webrtc/ContextUtils.java", + "java/src/org/webrtc/Loggable.java", "java/src/org/webrtc/Logging.java", "java/src/org/webrtc/Size.java", "java/src/org/webrtc/ThreadUtils.java", diff --git a/rtc_base/java/src/org/webrtc/Loggable.java b/rtc_base/java/src/org/webrtc/Loggable.java new file mode 100644 index 0000000000..cd66aa1214 --- /dev/null +++ b/rtc_base/java/src/org/webrtc/Loggable.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +import org.webrtc.Logging.Severity; + +/** + * Java interface for WebRTC logging. The default implementation uses webrtc.Logging. + * + * When injected, the Loggable will receive logging from both Java and native. + */ +public interface Loggable { + public void onLogMessage(String message, Severity severity, String tag); +} diff --git a/rtc_base/java/src/org/webrtc/Logging.java b/rtc_base/java/src/org/webrtc/Logging.java index 35ef0216f2..aafdbe8023 100644 --- a/rtc_base/java/src/org/webrtc/Logging.java +++ b/rtc_base/java/src/org/webrtc/Logging.java @@ -15,21 +15,35 @@ import java.io.StringWriter; import java.util.EnumSet; import java.util.logging.Level; import java.util.logging.Logger; +import javax.annotation.Nullable; +import org.webrtc.Loggable; /** - * Java wrapper for WebRTC logging. Logging defaults to java.util.logging.Logger, but will switch to - * native logging (rtc::LogMessage) if one of the following static functions are called from the - * app: + * Java wrapper for WebRTC logging. Logging defaults to java.util.logging.Logger, but a custom + * logger implementing the Loggable interface can be injected along with a Severity. All subsequent + * log messages will then be redirected to the injected Loggable, except those with a severity lower + * than the specified severity, which will be discarded. + * + * It is also possible to switch to native logging (rtc::LogMessage) if one of the following static + * functions are called from the app: * - Logging.enableLogThreads * - Logging.enableLogTimeStamps * - Logging.enableLogToDebugOutput * - * Using these APIs requires that the native library is loaded, using - * PeerConnectionFactory.initialize. + * The priority goes: + * 1. Injected loggable + * 2. Native logging + * 3. Fallback logging. + * Only one method will be used at a time. + * + * Injecting a Loggable or using any of the enable... methods requires that the native library is + * loaded, using PeerConnectionFactory.initialize. */ public class Logging { private static final Logger fallbackLogger = createFallbackLogger(); private static volatile boolean loggingEnabled; + @Nullable private static Loggable loggable; + private static Severity loggableSeverity; private static Logger createFallbackLogger() { final Logger fallbackLogger = Logger.getLogger("org.webrtc.Logging"); @@ -37,6 +51,17 @@ public class Logging { return fallbackLogger; } + static void injectLoggable(Loggable injectedLoggable, Severity severity) { + if (injectedLoggable != null) { + loggable = injectedLoggable; + loggableSeverity = severity; + } + } + + static void deleteInjectedLoggable() { + loggable = null; + } + // TODO(solenberg): Remove once dependent projects updated. @Deprecated public enum TraceLevel { @@ -83,6 +108,11 @@ public class Logging { // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. @SuppressWarnings("NoSynchronizedMethodCheck") public static synchronized void enableLogToDebugOutput(Severity severity) { + if (loggable != null) { + throw new IllegalStateException( + "Logging to native debug output not supported while Loggable is injected. " + + "Delete the Loggable before calling this method."); + } nativeEnableLogToDebugOutput(severity.ordinal()); loggingEnabled = true; } @@ -91,6 +121,16 @@ public class Logging { if (tag == null || message == null) { throw new IllegalArgumentException("Logging tag or message may not be null."); } + if (loggable != null) { + // Filter log messages below loggableSeverity. + if (severity.ordinal() < loggableSeverity.ordinal()) { + return; + } + loggable.onLogMessage(message, severity, tag); + return; + } + + // Try native logging if no loggable is injected. if (loggingEnabled) { nativeLog(severity.ordinal(), tag, message); return; diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 498c7dc23e..524449db03 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -78,6 +78,7 @@ rtc_source_set("base_jni") { "src/jni/jni_helpers.cc", "src/jni/jni_helpers.h", "src/jni/pc/audio.h", + "src/jni/pc/logging.cc", "src/jni/pc/media.h", "src/jni/pc/video.h", ] @@ -493,6 +494,38 @@ generate_jni("generated_peerconnection_jni") { jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h" } +rtc_android_library("logging_java") { + java_files = [ "src/java/org/webrtc/JNILogging.java" ] + + deps = [ + ":base_java", + "//rtc_base:base_java", + ] +} + +generate_jni("generated_logging_jni") { + sources = [ + "src/java/org/webrtc/JNILogging.java", + ] + jni_package = "" + jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h" +} + +rtc_static_library("logging_jni") { + visibility = [ "*" ] + sources = [ + "src/jni/logging/logsink.cc", + "src/jni/logging/logsink.h", + ] + + deps = [ + ":base_jni", + ":generated_logging_jni", + ":native_api_jni", + "../../rtc_base:rtc_base", + ] +} + rtc_static_library("peerconnection_jni") { # Do not depend on this target externally unless you absolute have to. It is # made public because we don't have a proper NDK yet. Header APIs here are not @@ -509,7 +542,6 @@ rtc_static_library("peerconnection_jni") { "src/jni/pc/dtmfsender.cc", "src/jni/pc/icecandidate.cc", "src/jni/pc/icecandidate.h", - "src/jni/pc/logging.cc", "src/jni/pc/mediaconstraints.cc", "src/jni/pc/mediaconstraints.h", "src/jni/pc/mediasource.cc", @@ -555,6 +587,7 @@ rtc_static_library("peerconnection_jni") { ":base_jni", ":generated_external_classes_jni", ":generated_peerconnection_jni", + ":logging_jni", ":native_api_jni", "../..:webrtc_common", "../../api:libjingle_peerconnection_api", @@ -679,6 +712,7 @@ dist_jar("libwebrtc") { ":java_audio_device_module_java", ":libjingle_peerconnection_java", ":libjingle_peerconnection_metrics_default_java", + ":logging_java", ":peerconnection_java", ":screencapturer_java", ":surfaceviewrenderer_java", @@ -967,6 +1001,7 @@ rtc_android_library("peerconnection_java") { deps = [ ":audio_api_java", ":base_java", + ":logging_java", ":video_api_java", ":video_java", "//modules/audio_device:audio_device_java", @@ -1033,6 +1068,7 @@ if (rtc_include_tests) { "instrumentationtests/src/org/webrtc/VideoFrameBufferTest.java", "instrumentationtests/src/org/webrtc/HardwareVideoDecoderTest.java", "instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java", + "instrumentationtests/src/org/webrtc/LoggableTest.java", "instrumentationtests/src/org/webrtc/MediaCodecVideoEncoderTest.java", "instrumentationtests/src/org/webrtc/NetworkMonitorTest.java", "instrumentationtests/src/org/webrtc/PeerConnectionFactoryTest.java", @@ -1077,6 +1113,7 @@ rtc_shared_library("libjingle_peerconnection_instrumentationtests_so") { configs += [ "//build/config/android:hide_all_but_jni" ] deps = [ + ":instrumentationtests_jni", ":libjingle_peerconnection_jni", ":libjingle_peerconnection_metrics_default_jni", "../../pc:libjingle_peerconnection", @@ -1085,6 +1122,19 @@ rtc_shared_library("libjingle_peerconnection_instrumentationtests_so") { output_extension = "so" } +rtc_static_library("instrumentationtests_jni") { + testonly = true + sources = [ + "instrumentationtests/loggable_test.cc", + ] + + deps = [ + ":base_jni", + ":native_api_jni", + "../../rtc_base:rtc_base_approved", + ] +} + # The native API is currently experimental and may change without notice. group("native_api") { deps = [ diff --git a/sdk/android/api/org/webrtc/PeerConnectionFactory.java b/sdk/android/api/org/webrtc/PeerConnectionFactory.java index 96c196c0db..aab621632d 100644 --- a/sdk/android/api/org/webrtc/PeerConnectionFactory.java +++ b/sdk/android/api/org/webrtc/PeerConnectionFactory.java @@ -13,6 +13,7 @@ package org.webrtc; import android.content.Context; import java.util.List; import javax.annotation.Nullable; +import org.webrtc.Logging.Severity; import org.webrtc.audio.AudioDeviceModule; import org.webrtc.audio.LegacyAudioDeviceModule; @@ -42,16 +43,21 @@ public class PeerConnectionFactory { final boolean enableVideoHwAcceleration; final NativeLibraryLoader nativeLibraryLoader; final String nativeLibraryName; + @Nullable Loggable loggable; + @Nullable Severity loggableSeverity; private InitializationOptions(Context applicationContext, String fieldTrials, boolean enableInternalTracer, boolean enableVideoHwAcceleration, - NativeLibraryLoader nativeLibraryLoader, String nativeLibraryName) { + NativeLibraryLoader nativeLibraryLoader, String nativeLibraryName, + @Nullable Loggable loggable, @Nullable Severity loggableSeverity) { this.applicationContext = applicationContext; this.fieldTrials = fieldTrials; this.enableInternalTracer = enableInternalTracer; this.enableVideoHwAcceleration = enableVideoHwAcceleration; this.nativeLibraryLoader = nativeLibraryLoader; this.nativeLibraryName = nativeLibraryName; + this.loggable = loggable; + this.loggableSeverity = loggableSeverity; } public static Builder builder(Context applicationContext) { @@ -65,6 +71,8 @@ public class PeerConnectionFactory { private boolean enableVideoHwAcceleration = true; private NativeLibraryLoader nativeLibraryLoader = new NativeLibrary.DefaultLoader(); private String nativeLibraryName = "jingle_peerconnection_so"; + @Nullable private Loggable loggable = null; + @Nullable private Severity loggableSeverity = null; Builder(Context applicationContext) { this.applicationContext = applicationContext; @@ -89,15 +97,22 @@ public class PeerConnectionFactory { this.nativeLibraryLoader = nativeLibraryLoader; return this; } + public Builder setNativeLibraryName(String nativeLibraryName) { this.nativeLibraryName = nativeLibraryName; return this; } + public Builder setInjectableLogger(Loggable loggable, Severity severity) { + this.loggable = loggable; + this.loggableSeverity = severity; + return this; + } + public PeerConnectionFactory.InitializationOptions createInitializationOptions() { return new PeerConnectionFactory.InitializationOptions(applicationContext, fieldTrials, - enableInternalTracer, enableVideoHwAcceleration, nativeLibraryLoader, - nativeLibraryName); + enableInternalTracer, enableVideoHwAcceleration, nativeLibraryLoader, nativeLibraryName, + loggable, loggableSeverity); } } } @@ -207,6 +222,16 @@ public class PeerConnectionFactory { if (options.enableInternalTracer && !internalTracerInitialized) { initializeInternalTracer(); } + if (options.loggable != null) { + Logging.injectLoggable(options.loggable, options.loggableSeverity); + nativeInjectLoggable(new JNILogging(options.loggable), options.loggableSeverity.ordinal()); + } else { + Logging.d(TAG, + "PeerConnectionFactory was initialized without an injected Loggable. " + + "Any existing Loggable will be deleted."); + Logging.deleteInjectedLoggable(); + nativeDeleteLoggable(); + } } private void checkInitializeHasBeenCalled() { @@ -482,4 +507,6 @@ public class PeerConnectionFactory { private static native void nativeInvokeThreadsCallbacks(long factory); private static native void nativeFreeFactory(long factory); private static native long nativeGetNativePeerConnectionFactory(long factory); + private static native void nativeInjectLoggable(JNILogging jniLogging, int severity); + private static native void nativeDeleteLoggable(); } diff --git a/sdk/android/instrumentationtests/loggable_test.cc b/sdk/android/instrumentationtests/loggable_test.cc new file mode 100644 index 0000000000..1a11075216 --- /dev/null +++ b/sdk/android/instrumentationtests/loggable_test.cc @@ -0,0 +1,31 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + +#include "rtc_base/logging.h" +#include "sdk/android/native_api/jni/java_types.h" +#include "sdk/android/src/jni/jni_helpers.h" + +namespace webrtc { +namespace jni { + +JNI_FUNCTION_DECLARATION(void, + LoggableTest_nativeLogInfoTestMessage, + JNIEnv* jni, + jclass, + jstring j_message) { + std::string message = + JavaToNativeString(jni, JavaParamRef(j_message)); + RTC_LOG(LS_INFO) << message; +} + +} // namespace jni +} // namespace webrtc diff --git a/sdk/android/instrumentationtests/src/org/webrtc/LoggableTest.java b/sdk/android/instrumentationtests/src/org/webrtc/LoggableTest.java new file mode 100644 index 0000000000..3831345cb2 --- /dev/null +++ b/sdk/android/instrumentationtests/src/org/webrtc/LoggableTest.java @@ -0,0 +1,164 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import java.util.ArrayList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.webrtc.PeerConnectionFactory; +import org.webrtc.Logging.Severity; +import org.webrtc.Loggable; + +@RunWith(AndroidJUnit4.class) +public class LoggableTest { + private static String TAG = "LoggableTest"; + private static String NATIVE_FILENAME_TAG = "loggable_test.cc"; + + private static class MockLoggable implements Loggable { + private ArrayList messages = new ArrayList<>(); + private ArrayList sevs = new ArrayList<>(); + private ArrayList tags = new ArrayList<>(); + + @Override + public void onLogMessage(String message, Severity sev, String tag) { + messages.add(message); + sevs.add(sev); + tags.add(tag); + } + + public boolean isMessageReceived(String message) { + for (int i = 0; i < messages.size(); i++) { + if (messages.get(i).contains(message)) { + return true; + } + } + return false; + } + + public boolean isMessageReceived(String message, Severity sev, String tag) { + for (int i = 0; i < messages.size(); i++) { + if (messages.get(i).contains(message) && sevs.get(i) == sev && tags.get(i).equals(tag)) { + return true; + } + } + return false; + } + } + + private final MockLoggable mockLoggable = new MockLoggable(); + + @Test + @SmallTest + public void testLoggableSetWithoutError() throws InterruptedException { + PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions + .builder(InstrumentationRegistry.getTargetContext()) + .setInjectableLogger(mockLoggable, Severity.LS_INFO) + .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) + .createInitializationOptions()); + } + + @Test + @SmallTest + public void testMessageIsLoggedCorrectly() throws InterruptedException { + PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions + .builder(InstrumentationRegistry.getTargetContext()) + .setInjectableLogger(mockLoggable, Severity.LS_INFO) + .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) + .createInitializationOptions()); + String msg = "Message that should be logged"; + Logging.d(TAG, msg); + assertTrue(mockLoggable.isMessageReceived(msg, Severity.LS_INFO, TAG)); + } + + @Test + @SmallTest + public void testLowSeverityIsFiltered() throws InterruptedException { + // Set severity to LS_WARNING to filter out LS_INFO and below. + PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions + .builder(InstrumentationRegistry.getTargetContext()) + .setInjectableLogger(mockLoggable, Severity.LS_WARNING) + .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) + .createInitializationOptions()); + String msg = "Message that should NOT be logged"; + Logging.d(TAG, msg); + assertFalse(mockLoggable.isMessageReceived(msg)); + } + + @Test + @SmallTest + public void testLoggableDoesNotReceiveMessagesAfterUnsetting() { + PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions + .builder(InstrumentationRegistry.getTargetContext()) + .setInjectableLogger(mockLoggable, Severity.LS_INFO) + .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) + .createInitializationOptions()); + // Reinitialize without Loggable + PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions + .builder(InstrumentationRegistry.getTargetContext()) + .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) + .createInitializationOptions()); + String msg = "Message that should NOT be logged"; + Logging.d(TAG, msg); + assertFalse(mockLoggable.isMessageReceived(msg)); + } + + @Test + @SmallTest + public void testNativeMessageIsLoggedCorrectly() throws InterruptedException { + PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions + .builder(InstrumentationRegistry.getTargetContext()) + .setInjectableLogger(mockLoggable, Severity.LS_INFO) + .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) + .createInitializationOptions()); + String msg = "Message that should be logged"; + nativeLogInfoTestMessage(msg); + assertTrue(mockLoggable.isMessageReceived(msg, Severity.LS_INFO, NATIVE_FILENAME_TAG)); + } + + @Test + @SmallTest + public void testNativeLowSeverityIsFiltered() throws InterruptedException { + PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions + .builder(InstrumentationRegistry.getTargetContext()) + .setInjectableLogger(mockLoggable, Severity.LS_WARNING) + .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) + .createInitializationOptions()); + String msg = "Message that should NOT be logged"; + nativeLogInfoTestMessage(msg); + assertFalse(mockLoggable.isMessageReceived(msg)); + } + + @Test + @SmallTest + public void testNativeLoggableDoesNotReceiveMessagesAfterUnsetting() { + PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions + .builder(InstrumentationRegistry.getTargetContext()) + .setInjectableLogger(mockLoggable, Severity.LS_INFO) + .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) + .createInitializationOptions()); + // Reinitialize without Loggable + PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions + .builder(InstrumentationRegistry.getTargetContext()) + .setNativeLibraryName(TestConstants.NATIVE_LIBRARY) + .createInitializationOptions()); + String msg = "Message that should NOT be logged"; + nativeLogInfoTestMessage(msg); + assertFalse(mockLoggable.isMessageReceived(msg)); + } + + private static native void nativeLogInfoTestMessage(String message); +} diff --git a/sdk/android/src/java/org/webrtc/JNILogging.java b/sdk/android/src/java/org/webrtc/JNILogging.java new file mode 100644 index 0000000000..f391db61a1 --- /dev/null +++ b/sdk/android/src/java/org/webrtc/JNILogging.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +import org.webrtc.CalledByNative; +import org.webrtc.Loggable; +import org.webrtc.Logging.Severity; + +class JNILogging { + private final Loggable loggable; + + public JNILogging(Loggable loggable) { + this.loggable = loggable; + } + + @CalledByNative + public void logToInjectable(String message, Integer severity, String tag) { + loggable.onLogMessage(message, Severity.values()[severity], tag); + } +} diff --git a/sdk/android/src/jni/logging/logsink.cc b/sdk/android/src/jni/logging/logsink.cc new file mode 100644 index 0000000000..cfa3c60abb --- /dev/null +++ b/sdk/android/src/jni/logging/logsink.cc @@ -0,0 +1,35 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "sdk/android/src/jni/logging/logsink.h" + +#include "sdk/android/generated_logging_jni/jni/JNILogging_jni.h" + +namespace webrtc { +namespace jni { + +JNILogSink::JNILogSink(JNIEnv* env, const JavaRef& j_logging) + : j_logging_(env, j_logging) {} +JNILogSink::~JNILogSink() = default; + +void JNILogSink::OnLogMessage(const std::string& msg, + rtc::LoggingSeverity severity, + const char* tag) { + JNIEnv* env = AttachCurrentThreadIfNeeded(); + Java_JNILogging_logToInjectable(env, j_logging_, NativeToJavaString(env, msg), + NativeToJavaInteger(env, severity), + NativeToJavaString(env, tag)); +} + +void JNILogSink::OnLogMessage(const std::string& msg) { + RTC_NOTREACHED(); +} + +} // namespace jni +} // namespace webrtc diff --git a/sdk/android/src/jni/logging/logsink.h b/sdk/android/src/jni/logging/logsink.h new file mode 100644 index 0000000000..bac51a06da --- /dev/null +++ b/sdk/android/src/jni/logging/logsink.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef SDK_ANDROID_SRC_JNI_LOGGING_LOGSINK_H_ +#define SDK_ANDROID_SRC_JNI_LOGGING_LOGSINK_H_ + +#include + +#include "rtc_base/logging.h" +#include "sdk/android/native_api/jni/java_types.h" +#include "sdk/android/src/jni/jni_helpers.h" + +namespace webrtc { +namespace jni { + +class JNILogSink : public rtc::LogSink { + public: + JNILogSink(JNIEnv* env, const JavaRef& j_logging); + ~JNILogSink() override; + + void OnLogMessage(const std::string& msg, + rtc::LoggingSeverity severity, + const char* tag) override; + void OnLogMessage(const std::string& msg) override; + + private: + const ScopedJavaGlobalRef j_logging_; +}; + +} // namespace jni +} // namespace webrtc + +#endif // SDK_ANDROID_SRC_JNI_LOGGING_LOGSINK_H_ diff --git a/sdk/android/src/jni/pc/peerconnectionfactory.cc b/sdk/android/src/jni/pc/peerconnectionfactory.cc index 5730c209df..211d583a71 100644 --- a/sdk/android/src/jni/pc/peerconnectionfactory.cc +++ b/sdk/android/src/jni/pc/peerconnectionfactory.cc @@ -27,6 +27,7 @@ #include "sdk/android/generated_peerconnection_jni/jni/PeerConnectionFactory_jni.h" #include "sdk/android/native_api/jni/java_types.h" #include "sdk/android/src/jni/jni_helpers.h" +#include "sdk/android/src/jni/logging/logsink.h" #include "sdk/android/src/jni/pc/androidnetworkmonitor.h" #include "sdk/android/src/jni/pc/audio.h" #include "sdk/android/src/jni/pc/icecandidate.h" @@ -81,6 +82,9 @@ static std::unique_ptr field_trials_init_string; static bool factory_static_initialized = false; static bool video_hw_acceleration_enabled = true; +// Set in PeerConnectionFactory_InjectLoggable(). +static std::unique_ptr jni_log_sink; + void PeerConnectionFactoryNetworkThreadReady() { RTC_LOG(LS_INFO) << "Network thread JavaCallback"; JNIEnv* env = AttachCurrentThreadIfNeeded(); @@ -497,5 +501,29 @@ static jlong JNI_PeerConnectionFactory_GetNativePeerConnectionFactory( return jlongFromPointer(factoryFromJava(native_factory)); } +static void JNI_PeerConnectionFactory_InjectLoggable( + JNIEnv* jni, + const JavaParamRef&, + const JavaParamRef& j_logging, + jint nativeSeverity) { + // If there is already a LogSink, remove it from LogMessage. + if (jni_log_sink) { + rtc::LogMessage::RemoveLogToStream(jni_log_sink.get()); + } + jni_log_sink = rtc::MakeUnique(jni, j_logging); + rtc::LogMessage::AddLogToStream( + jni_log_sink.get(), static_cast(nativeSeverity)); + rtc::LogMessage::LogToDebug(rtc::LS_NONE); +} + +static void JNI_PeerConnectionFactory_DeleteLoggable( + JNIEnv* jni, + const JavaParamRef&) { + if (jni_log_sink) { + rtc::LogMessage::RemoveLogToStream(jni_log_sink.get()); + jni_log_sink.reset(); + } +} + } // namespace jni } // namespace webrtc