diff --git a/ReactAndroid/DEFS b/ReactAndroid/DEFS index f9f43995ea..104c161896 100644 --- a/ReactAndroid/DEFS +++ b/ReactAndroid/DEFS @@ -6,7 +6,6 @@ import os - # Example: react_native_target('java/com/facebook/react/common:common') def react_native_target(path): return '//ReactAndroid/src/main/' + path @@ -34,6 +33,8 @@ JSC_INTERNAL_DEPS = [ '//native/third-party/jsc-internal:jsc_legacy_profiler', ] +FBGLOGINIT_TARGET = '//ReactAndroid/src/main/jni/first-party/fbgloginit:fbgloginit' + INTERNAL_APP = 'PUBLIC' # React property preprocessor @@ -96,4 +97,4 @@ def robolectric3_test(name, deps, vm_args=None, *args, **kwargs): vm_args=vm_args + extra_vm_args, *args, **kwargs - ) \ No newline at end of file + ) diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk b/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk new file mode 100644 index 0000000000..6d08079a7e --- /dev/null +++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + glog_init.cpp + +LOCAL_C_INCLUDES := $(LOCAL_PATH) +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) + +LOCAL_CFLAGS := -fexceptions -fno-omit-frame-pointer +LOCAL_CFLAGS += -Wall -Werror + +CXX11_FLAGS := -std=gnu++11 +LOCAL_CFLAGS += $(CXX11_FLAGS) + +LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS) + +LOCAL_LDLIBS := -llog + +LOCAL_SHARED_LIBRARIES := libglog + +LOCAL_MODULE := libglog_init + +include $(BUILD_SHARED_LIBRARY) diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK b/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK new file mode 100644 index 0000000000..e7188bd0ef --- /dev/null +++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK @@ -0,0 +1,19 @@ +cxx_library( + name = 'fbgloginit', + srcs = [ + 'glog_init.cpp', + ], + exported_headers = ['fb/glog_init.h'], + compiler_flags = [ + '-fexceptions', + '-fno-omit-frame-pointer', + ], + linker_flags = [ + '-llog', + ], + deps=[ + '//xplat/third-party/glog:glog', + ], + visibility=['PUBLIC'], +) + diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h b/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h new file mode 100644 index 0000000000..311f703500 --- /dev/null +++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h @@ -0,0 +1,11 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace facebook { namespace gloginit { + +void initialize(const char* tag = "ReactNativeJNI"); + +}} diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp b/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp new file mode 100644 index 0000000000..771516a2dc --- /dev/null +++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp @@ -0,0 +1,142 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "fb/glog_init.h" + +#include +#include +#include + +#include + +#ifdef __ANDROID__ + +#include + +static int toAndroidLevel(google::LogSeverity severity) { + switch (severity) { + case google::GLOG_INFO: + return ANDROID_LOG_INFO; + case google::GLOG_WARNING: + return ANDROID_LOG_WARN; + case google::GLOG_ERROR: + return ANDROID_LOG_ERROR; + case google::GLOG_FATAL: + return ANDROID_LOG_FATAL; + default: + return ANDROID_LOG_FATAL; + } +} + +/** + * Sends GLog output to adb logcat. + */ +class LogcatSink : public google::LogSink { + public: + void send( + google::LogSeverity severity, + const char* full_filename, + const char* base_filename, + int line, + const struct ::tm* tm_time, + const char* message, + size_t message_len) override { + auto level = toAndroidLevel(severity); + __android_log_print( + level, + base_filename, + "%.*s", + (int)message_len, + message); + } +}; + +/** + * Sends GLog output to adb logcat. + */ +class TaggedLogcatSink : public google::LogSink { + const std::string tag_; + + public: + TaggedLogcatSink(const std::string &tag) : tag_{tag} {} + + void send( + google::LogSeverity severity, + const char* full_filename, + const char* base_filename, + int line, + const struct ::tm* tm_time, + const char* message, + size_t message_len) override { + auto level = toAndroidLevel(severity); + __android_log_print( + level, + tag_.c_str(), + "%.*s", + (int)message_len, + message); + } +}; + +static google::LogSink* make_sink(const std::string& tag) { + if (tag.empty()) { + return new LogcatSink{}; + } else { + return new TaggedLogcatSink{tag}; + } +} + +static void sendGlogOutputToLogcat(const char* tag) { + google::AddLogSink(make_sink(tag)); + + // Disable logging to files + for (auto i = 0; i < google::NUM_SEVERITIES; ++i) { + google::SetLogDestination(i, ""); + } +} + +#endif // __ANDROID__ + +static void lastResort(const char* tag, const char* msg, const char* arg = nullptr) { +#ifdef __ANDROID__ + if (!arg) { + __android_log_write(ANDROID_LOG_ERROR, tag, msg); + } else { + __android_log_print(ANDROID_LOG_ERROR, tag, "%s: %s", msg, arg); + } +#else + std::cerr << msg; + if (arg) { + std::cerr << ": " << arg; + } + std::cerr << std::endl; +#endif +} + +namespace facebook { namespace gloginit { + +void initialize(const char* tag) { + static std::once_flag flag{}; + static auto failed = false; + + std::call_once(flag, [tag] { + try { + google::InitGoogleLogging(tag); + +#ifdef __ANDROID__ + sendGlogOutputToLogcat(tag); +#endif + } catch (std::exception& ex) { + lastResort(tag, "Failed to initialize glog", ex.what()); + failed = true; + } catch (...) { + lastResort(tag, "Failed to initialize glog"); + failed = true; + } + }); + + if (failed) { + throw std::runtime_error{"Failed to initialize glog"}; + } +} + +}} diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 7d46f9ef8b..46bf1d5251 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -23,7 +23,7 @@ LOCAL_CFLAGS += $(CXX11_FLAGS) LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS) LOCAL_LDLIBS += -landroid -LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc +LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc libglog_init LOCAL_STATIC_LIBRARIES := libreactnative include $(BUILD_SHARED_LIBRARY) @@ -31,5 +31,6 @@ include $(BUILD_SHARED_LIBRARY) $(call import-module,react) $(call import-module,jsc) $(call import-module,folly) +$(call import-module,fbgloginit) $(call import-module,jni) $(call import-module,jsc) diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK index 419cde76bf..be23d64cfe 100644 --- a/ReactAndroid/src/main/jni/react/jni/BUCK +++ b/ReactAndroid/src/main/jni/react/jni/BUCK @@ -4,6 +4,7 @@ include_defs('//ReactAndroid/DEFS') SUPPORTED_PLATFORMS = '^android-(armv7|x86)$' DEPS = [ + FBGLOGINIT_TARGET, '//native/jni:jni', '//native/third-party/android-ndk:android', '//xplat/folly:molly', diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp index 6dc5a0ca10..2ba6555313 100644 --- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp +++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -907,6 +908,7 @@ jmethodID getLogMarkerMethod() { extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { return initialize(vm, [] { + facebook::gloginit::initialize(); // Inject some behavior into react/ ReactMarker::logMarker = bridge::logMarker; WebWorkerUtil::createWebWorkerThread = WebWorkers::createWebWorkerThread;