Remove the restriction on importing bridge:cxxreact
Reviewed By: javache Differential Revision: D5724406 fbshipit-source-id: 24974601d161fd23805d8e925b2b20a1cf11850d
This commit is contained in:
parent
dd92dba3da
commit
de01f09b5d
|
@ -5,6 +5,7 @@ include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := reactnativejni
|
LOCAL_MODULE := reactnativejni
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
|
AndroidJSCFactory.cpp \
|
||||||
CatalystInstanceImpl.cpp \
|
CatalystInstanceImpl.cpp \
|
||||||
CxxModuleWrapper.cpp \
|
CxxModuleWrapper.cpp \
|
||||||
JavaModuleWrapper.cpp \
|
JavaModuleWrapper.cpp \
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#include <cxxreact/JSCExecutor.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <cxxreact/Platform.h>
|
||||||
|
#include <fb/fbjni.h>
|
||||||
|
#include <folly/Conv.h>
|
||||||
|
#include <folly/dynamic.h>
|
||||||
|
#include <folly/Memory.h>
|
||||||
|
#include <jschelpers/JSCHelpers.h>
|
||||||
|
|
||||||
|
#include "JSCPerfLogging.h"
|
||||||
|
#include "JSLogging.h"
|
||||||
|
|
||||||
|
using namespace facebook::jni;
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class JReactMarker : public JavaClass<JReactMarker> {
|
||||||
|
public:
|
||||||
|
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/ReactMarker;";
|
||||||
|
|
||||||
|
static void logMarker(const std::string& marker) {
|
||||||
|
static auto cls = javaClassStatic();
|
||||||
|
static auto meth = cls->getStaticMethod<void(std::string)>("logMarker");
|
||||||
|
meth(cls, marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logMarker(const std::string& marker, const std::string& tag) {
|
||||||
|
static auto cls = javaClassStatic();
|
||||||
|
static auto meth = cls->getStaticMethod<void(std::string, std::string)>("logMarker");
|
||||||
|
meth(cls, marker, tag);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void logPerfMarker(const ReactMarker::ReactMarkerId markerId, const char* tag) {
|
||||||
|
switch (markerId) {
|
||||||
|
case ReactMarker::RUN_JS_BUNDLE_START:
|
||||||
|
JReactMarker::logMarker("RUN_JS_BUNDLE_START", tag);
|
||||||
|
break;
|
||||||
|
case ReactMarker::RUN_JS_BUNDLE_STOP:
|
||||||
|
JReactMarker::logMarker("RUN_JS_BUNDLE_END", tag);
|
||||||
|
break;
|
||||||
|
case ReactMarker::CREATE_REACT_CONTEXT_STOP:
|
||||||
|
JReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
||||||
|
break;
|
||||||
|
case ReactMarker::JS_BUNDLE_STRING_CONVERT_START:
|
||||||
|
JReactMarker::logMarker("loadApplicationScript_startStringConvert");
|
||||||
|
break;
|
||||||
|
case ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP:
|
||||||
|
JReactMarker::logMarker("loadApplicationScript_endStringConvert");
|
||||||
|
break;
|
||||||
|
case ReactMarker::NATIVE_MODULE_SETUP_START:
|
||||||
|
JReactMarker::logMarker("NATIVE_MODULE_SETUP_START", tag);
|
||||||
|
break;
|
||||||
|
case ReactMarker::NATIVE_MODULE_SETUP_STOP:
|
||||||
|
JReactMarker::logMarker("NATIVE_MODULE_SETUP_END", tag);
|
||||||
|
break;
|
||||||
|
case ReactMarker::NATIVE_REQUIRE_START:
|
||||||
|
case ReactMarker::NATIVE_REQUIRE_STOP:
|
||||||
|
// These are not used on Android.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExceptionHandling::ExtractedEror extractJniError(const std::exception& ex, const char *context) {
|
||||||
|
auto jniEx = dynamic_cast<const jni::JniException *>(&ex);
|
||||||
|
if (!jniEx) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto stackTrace = jniEx->getThrowable()->getStackTrace();
|
||||||
|
std::ostringstream stackStr;
|
||||||
|
for (int i = 0, count = stackTrace->size(); i < count; ++i) {
|
||||||
|
auto frame = stackTrace->getElement(i);
|
||||||
|
|
||||||
|
auto methodName = folly::to<std::string>(frame->getClassName(), ".",
|
||||||
|
frame->getMethodName());
|
||||||
|
|
||||||
|
// Cut off stack traces at the Android looper, to keep them simple
|
||||||
|
if (methodName == "android.os.Looper.loop") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stackStr << std::move(methodName) << '@' << frame->getFileName();
|
||||||
|
if (frame->getLineNumber() > 0) {
|
||||||
|
stackStr << ':' << frame->getLineNumber();
|
||||||
|
}
|
||||||
|
stackStr << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto msg = folly::to<std::string>("Java exception in '", context, "'\n\n", jniEx->what());
|
||||||
|
return {.message = msg, .stack = stackStr.str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValueRef nativePerformanceNow(
|
||||||
|
JSContextRef ctx,
|
||||||
|
JSObjectRef function,
|
||||||
|
JSObjectRef thisObject,
|
||||||
|
size_t argumentCount,
|
||||||
|
const JSValueRef arguments[], JSValueRef *exception) {
|
||||||
|
static const int64_t NANOSECONDS_IN_SECOND = 1000000000LL;
|
||||||
|
static const int64_t NANOSECONDS_IN_MILLISECOND = 1000000LL;
|
||||||
|
|
||||||
|
// Since SystemClock.uptimeMillis() is commonly used for performance measurement in Java
|
||||||
|
// and uptimeMillis() internally uses clock_gettime(CLOCK_MONOTONIC),
|
||||||
|
// we use the same API here.
|
||||||
|
// We need that to make sure we use the same time system on both JS and Java sides.
|
||||||
|
// Links to the source code:
|
||||||
|
// https://android.googlesource.com/platform/frameworks/native/+/jb-mr1-release/libs/utils/SystemClock.cpp
|
||||||
|
// https://android.googlesource.com/platform/system/core/+/master/libutils/Timers.cpp
|
||||||
|
struct timespec now;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
int64_t nano = now.tv_sec * NANOSECONDS_IN_SECOND + now.tv_nsec;
|
||||||
|
return Value::makeNumber(ctx, (nano / (double)NANOSECONDS_IN_MILLISECOND));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
void injectJSCExecutorAndroidPlatform() {
|
||||||
|
// Inject some behavior into react/
|
||||||
|
ReactMarker::logTaggedMarker = logPerfMarker;
|
||||||
|
ExceptionHandling::platformErrorExtractor = extractJniError;
|
||||||
|
JSCNativeHooks::loggingHook = nativeLoggingHook;
|
||||||
|
JSCNativeHooks::nowHook = nativePerformanceNow;
|
||||||
|
JSCNativeHooks::installPerfHooks = addNativePerfLoggingHooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<JSExecutorFactory> makeAndroidJSCExecutorFactory(
|
||||||
|
const folly::dynamic& jscConfig) {
|
||||||
|
detail::injectJSCExecutorAndroidPlatform();
|
||||||
|
return folly::make_unique<JSCExecutorFactory>(std::move(jscConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace folly {
|
||||||
|
|
||||||
|
class dynamic;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace react {
|
||||||
|
|
||||||
|
class JSExecutorFactory;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// This is only exposed so instrumentation tests can call it.
|
||||||
|
void injectJSCExecutorAndroidPlatform();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<JSExecutorFactory> makeAndroidJSCExecutorFactory(
|
||||||
|
const folly::dynamic& jscConfig);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
include_defs("//ReactAndroid/DEFS")
|
include_defs("//ReactAndroid/DEFS")
|
||||||
|
|
||||||
EXPORTED_HEADERS = [
|
EXPORTED_HEADERS = [
|
||||||
|
"AndroidJSCFactory.h",
|
||||||
"CxxModuleWrapper.h",
|
"CxxModuleWrapper.h",
|
||||||
"CxxModuleWrapperBase.h",
|
"CxxModuleWrapperBase.h",
|
||||||
"CxxSharedModuleWrapper.h",
|
"CxxSharedModuleWrapper.h",
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <jschelpers/JSCHelpers.h>
|
#include <jschelpers/JSCHelpers.h>
|
||||||
#include <cxxreact/JSExecutor.h>
|
|
||||||
#include <cxxreact/JSCExecutor.h>
|
#include <cxxreact/JSCExecutor.h>
|
||||||
#include <cxxreact/Platform.h>
|
#include <cxxreact/Platform.h>
|
||||||
#include <fb/fbjni.h>
|
#include <fb/fbjni.h>
|
||||||
|
@ -12,12 +11,11 @@
|
||||||
#include <folly/dynamic.h>
|
#include <folly/dynamic.h>
|
||||||
#include <jschelpers/Value.h>
|
#include <jschelpers/Value.h>
|
||||||
|
|
||||||
|
#include "AndroidJSCFactory.h"
|
||||||
#include "CatalystInstanceImpl.h"
|
#include "CatalystInstanceImpl.h"
|
||||||
#include "CxxModuleWrapper.h"
|
#include "CxxModuleWrapper.h"
|
||||||
#include "JavaScriptExecutorHolder.h"
|
#include "JavaScriptExecutorHolder.h"
|
||||||
#include "JCallback.h"
|
#include "JCallback.h"
|
||||||
#include "JSCPerfLogging.h"
|
|
||||||
#include "JSLogging.h"
|
|
||||||
#include "ProxyExecutor.h"
|
#include "ProxyExecutor.h"
|
||||||
#include "WritableNativeArray.h"
|
#include "WritableNativeArray.h"
|
||||||
#include "WritableNativeMap.h"
|
#include "WritableNativeMap.h"
|
||||||
|
@ -40,9 +38,7 @@ class JSCJavaScriptExecutorHolder : public HybridClass<JSCJavaScriptExecutorHold
|
||||||
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/JSCJavaScriptExecutor;";
|
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/JSCJavaScriptExecutor;";
|
||||||
|
|
||||||
static local_ref<jhybriddata> initHybrid(alias_ref<jclass>, ReadableNativeMap* jscConfig) {
|
static local_ref<jhybriddata> initHybrid(alias_ref<jclass>, ReadableNativeMap* jscConfig) {
|
||||||
// See JSCJavaScriptExecutor.Factory() for the other side of this hack.
|
return makeCxxInstance(makeAndroidJSCExecutorFactory(jscConfig->consume()));
|
||||||
folly::dynamic jscConfigMap = jscConfig->consume();
|
|
||||||
return makeCxxInstance(std::make_shared<JSCExecutorFactory>(std::move(jscConfigMap)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerNatives() {
|
static void registerNatives() {
|
||||||
|
@ -83,116 +79,11 @@ class ProxyJavaScriptExecutorHolder : public HybridClass<ProxyJavaScriptExecutor
|
||||||
using HybridBase::HybridBase;
|
using HybridBase::HybridBase;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JReactMarker : public JavaClass<JReactMarker> {
|
|
||||||
public:
|
|
||||||
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/ReactMarker;";
|
|
||||||
|
|
||||||
static void logMarker(const std::string& marker) {
|
|
||||||
static auto cls = javaClassStatic();
|
|
||||||
static auto meth = cls->getStaticMethod<void(std::string)>("logMarker");
|
|
||||||
meth(cls, marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void logMarker(const std::string& marker, const std::string& tag) {
|
|
||||||
static auto cls = javaClassStatic();
|
|
||||||
static auto meth = cls->getStaticMethod<void(std::string, std::string)>("logMarker");
|
|
||||||
meth(cls, marker, tag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static JSValueRef nativePerformanceNow(
|
|
||||||
JSContextRef ctx,
|
|
||||||
JSObjectRef function,
|
|
||||||
JSObjectRef thisObject,
|
|
||||||
size_t argumentCount,
|
|
||||||
const JSValueRef arguments[], JSValueRef *exception) {
|
|
||||||
static const int64_t NANOSECONDS_IN_SECOND = 1000000000LL;
|
|
||||||
static const int64_t NANOSECONDS_IN_MILLISECOND = 1000000LL;
|
|
||||||
|
|
||||||
// Since SystemClock.uptimeMillis() is commonly used for performance measurement in Java
|
|
||||||
// and uptimeMillis() internally uses clock_gettime(CLOCK_MONOTONIC),
|
|
||||||
// we use the same API here.
|
|
||||||
// We need that to make sure we use the same time system on both JS and Java sides.
|
|
||||||
// Links to the source code:
|
|
||||||
// https://android.googlesource.com/platform/frameworks/native/+/jb-mr1-release/libs/utils/SystemClock.cpp
|
|
||||||
// https://android.googlesource.com/platform/system/core/+/master/libutils/Timers.cpp
|
|
||||||
struct timespec now;
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
||||||
int64_t nano = now.tv_sec * NANOSECONDS_IN_SECOND + now.tv_nsec;
|
|
||||||
return Value::makeNumber(ctx, (nano / (double)NANOSECONDS_IN_MILLISECOND));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void logPerfMarker(const ReactMarker::ReactMarkerId markerId, const char* tag) {
|
|
||||||
switch (markerId) {
|
|
||||||
case ReactMarker::RUN_JS_BUNDLE_START:
|
|
||||||
JReactMarker::logMarker("RUN_JS_BUNDLE_START", tag);
|
|
||||||
break;
|
|
||||||
case ReactMarker::RUN_JS_BUNDLE_STOP:
|
|
||||||
JReactMarker::logMarker("RUN_JS_BUNDLE_END", tag);
|
|
||||||
break;
|
|
||||||
case ReactMarker::CREATE_REACT_CONTEXT_STOP:
|
|
||||||
JReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
|
||||||
break;
|
|
||||||
case ReactMarker::JS_BUNDLE_STRING_CONVERT_START:
|
|
||||||
JReactMarker::logMarker("loadApplicationScript_startStringConvert");
|
|
||||||
break;
|
|
||||||
case ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP:
|
|
||||||
JReactMarker::logMarker("loadApplicationScript_endStringConvert");
|
|
||||||
break;
|
|
||||||
case ReactMarker::NATIVE_MODULE_SETUP_START:
|
|
||||||
JReactMarker::logMarker("NATIVE_MODULE_SETUP_START", tag);
|
|
||||||
break;
|
|
||||||
case ReactMarker::NATIVE_MODULE_SETUP_STOP:
|
|
||||||
JReactMarker::logMarker("NATIVE_MODULE_SETUP_END", tag);
|
|
||||||
break;
|
|
||||||
case ReactMarker::NATIVE_REQUIRE_START:
|
|
||||||
case ReactMarker::NATIVE_REQUIRE_STOP:
|
|
||||||
// These are not used on Android.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ExceptionHandling::ExtractedEror extractJniError(const std::exception& ex, const char *context) {
|
|
||||||
auto jniEx = dynamic_cast<const jni::JniException *>(&ex);
|
|
||||||
if (!jniEx) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto stackTrace = jniEx->getThrowable()->getStackTrace();
|
|
||||||
std::ostringstream stackStr;
|
|
||||||
for (int i = 0, count = stackTrace->size(); i < count; ++i) {
|
|
||||||
auto frame = stackTrace->getElement(i);
|
|
||||||
|
|
||||||
auto methodName = folly::to<std::string>(frame->getClassName(), ".",
|
|
||||||
frame->getMethodName());
|
|
||||||
|
|
||||||
// Cut off stack traces at the Android looper, to keep them simple
|
|
||||||
if (methodName == "android.os.Looper.loop") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
stackStr << std::move(methodName) << '@' << frame->getFileName();
|
|
||||||
if (frame->getLineNumber() > 0) {
|
|
||||||
stackStr << ':' << frame->getLineNumber();
|
|
||||||
}
|
|
||||||
stackStr << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto msg = folly::to<std::string>("Java exception in '", context, "'\n\n", jniEx->what());
|
|
||||||
return {.message = msg, .stack = stackStr.str()};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||||
return initialize(vm, [] {
|
return initialize(vm, [] {
|
||||||
gloginit::initialize();
|
gloginit::initialize();
|
||||||
// Inject some behavior into react/
|
|
||||||
ReactMarker::logTaggedMarker = logPerfMarker;
|
|
||||||
ExceptionHandling::platformErrorExtractor = extractJniError;
|
|
||||||
JSCNativeHooks::loggingHook = nativeLoggingHook;
|
|
||||||
JSCNativeHooks::nowHook = nativePerformanceNow;
|
|
||||||
JSCNativeHooks::installPerfHooks = addNativePerfLoggingHooks;
|
|
||||||
JSCJavaScriptExecutorHolder::registerNatives();
|
JSCJavaScriptExecutorHolder::registerNatives();
|
||||||
ProxyJavaScriptExecutorHolder::registerNatives();
|
ProxyJavaScriptExecutorHolder::registerNatives();
|
||||||
CatalystInstanceImpl::registerNatives();
|
CatalystInstanceImpl::registerNatives();
|
||||||
|
|
|
@ -122,28 +122,11 @@ rn_xplat_cxx_library(
|
||||||
"-DWITH_JSC_MEMORY_PRESSURE=1",
|
"-DWITH_JSC_MEMORY_PRESSURE=1",
|
||||||
"-DWITH_FB_MEMORY_PROFILING=1",
|
"-DWITH_FB_MEMORY_PROFILING=1",
|
||||||
],
|
],
|
||||||
fbandroid_visibility = [
|
|
||||||
# TL;DR: If you depend on this target directly, you're gonna have a
|
|
||||||
# Bad Time(TM).
|
|
||||||
#
|
|
||||||
# `facebook::react::JSCExecutor::initOnJSVMThread` (in `:bridge`) does
|
|
||||||
# some platform-dependant setup. Exactly what setup to do is
|
|
||||||
# determined by some static functors, defined in `Platform.h`, which
|
|
||||||
# are initially `nullptr`. On Android, these functors are properly
|
|
||||||
# assigned as part of `react/jni`'s `JNI_OnLoad`. By depending directly
|
|
||||||
# on the bridge, we can mess up the SO initialisation order, causing
|
|
||||||
# `initOnJSVMThread` to be called before the platform-specific hooks
|
|
||||||
# have been properly initialised. Bad Times(TM).
|
|
||||||
# -- @ashokmenon (2017/01/03)
|
|
||||||
react_native_target("jni/react/jni:jni"),
|
|
||||||
react_native_xplat_target("cxxreact/..."),
|
|
||||||
],
|
|
||||||
fbobjc_frameworks = [
|
fbobjc_frameworks = [
|
||||||
"$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework",
|
"$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework",
|
||||||
],
|
],
|
||||||
fbobjc_inherited_buck_flags = STATIC_LIBRARY_IOS_FLAGS,
|
fbobjc_inherited_buck_flags = STATIC_LIBRARY_IOS_FLAGS,
|
||||||
fbobjc_preprocessor_flags = DEBUG_PREPROCESSOR_FLAGS,
|
fbobjc_preprocessor_flags = DEBUG_PREPROCESSOR_FLAGS,
|
||||||
fbobjc_visibility = ["PUBLIC"],
|
|
||||||
force_static = True,
|
force_static = True,
|
||||||
preprocessor_flags = [
|
preprocessor_flags = [
|
||||||
"-DLOG_TAG=\"ReactNative\"",
|
"-DLOG_TAG=\"ReactNative\"",
|
||||||
|
@ -152,6 +135,7 @@ rn_xplat_cxx_library(
|
||||||
tests = [
|
tests = [
|
||||||
react_native_xplat_target("cxxreact/tests:tests"),
|
react_native_xplat_target("cxxreact/tests:tests"),
|
||||||
],
|
],
|
||||||
|
visibility = ["PUBLIC"],
|
||||||
deps = [
|
deps = [
|
||||||
":module",
|
":module",
|
||||||
":jsbigstring",
|
":jsbigstring",
|
||||||
|
|
Loading…
Reference in New Issue