Inject some behavior from react/jni/ to react/

Summary:
So, this makes it so a set of behaviors that require accessing java can be injected from the jni/ folder. The behaviors are logging, perf logging, log markers and loading script from assets.

I'd argue that these should all actually be encapsulated by interfaces that are passed to the JSCExecutor/others (and I'd say that's regardless of whether they are injected from jni/ or not), but I wanted to stick to the least disruptive pattern for these changes.

public

Reviewed By: astreet

Differential Revision: D2905168

fb-gh-sync-id: 7c8c16cb77b8fc3d42750dacc6574259ad512ac2
This commit is contained in:
Chris Hopman 2016-02-05 18:09:24 -08:00 committed by facebook-github-bot-2
parent 2c8802f316
commit 75ca46e332
13 changed files with 160 additions and 56 deletions

View File

@ -46,15 +46,14 @@ react_library(
'JSCExecutor.cpp',
'JSCTracing.cpp',
'JSCMemory.cpp',
'JSCPerfLogging.cpp',
'JSCLegacyProfiler.cpp',
'JSCWebWorker.cpp',
'Platform.cpp',
],
headers = [
'JSCTracing.h',
'JSCPerfLogging.h',
'JSCLegacyProfiler.h',
'JSCMemory.h'
'JSCMemory.h',
],
exported_headers = [
'Bridge.h',
@ -65,6 +64,7 @@ react_library(
'MethodCall.h',
'JSModulesUnbundle.h',
'Value.h',
'Platform.h',
],
compiler_flags = [
'-Wall',

View File

@ -15,6 +15,7 @@
#include "jni/JMessageQueueThread.h"
#include "jni/OnLoad.h"
#include <react/JSCHelpers.h>
#include "Platform.h"
#ifdef WITH_JSC_EXTRA_TRACING
#include <react/JSCTracing.h>
@ -31,9 +32,6 @@
using fbsystrace::FbSystraceSection;
#endif
// Add native performance markers support
#include <react/JSCPerfLogging.h>
#ifdef WITH_FB_MEMORY_PROFILING
#include <react/JSCMemory.h>
#endif
@ -59,13 +57,6 @@ static JSValueRef nativeFlushQueueImmediate(
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception);
static JSValueRef nativeLoggingHook(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception);
static JSValueRef nativePerformanceNow(
JSContextRef ctx,
JSObjectRef function,
@ -103,12 +94,13 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
m_messageQueueThread = JMessageQueueThread::currentMessageQueueThread();
s_globalContextRefToJSCExecutor[m_context] = this;
installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
installGlobalFunction(m_context, "nativeLoggingHook", nativeLoggingHook);
installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow);
installGlobalFunction(m_context, "nativeStartWorker", nativeStartWorker);
installGlobalFunction(m_context, "nativePostMessageToWorker", nativePostMessageToWorker);
installGlobalFunction(m_context, "nativeTerminateWorker", nativeTerminateWorker);
installGlobalFunction(m_context, "nativeLoggingHook", JSLogging::nativeHook);
#ifdef WITH_FB_JSC_TUNING
configureJSCForAndroid();
#endif
@ -116,7 +108,7 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
#ifdef WITH_JSC_EXTRA_TRACING
addNativeTracingHooks(m_context);
addNativeProfilingHooks(m_context);
addNativePerfLoggingHooks(m_context);
PerfLogging::installNativeHooks(m_context);
#endif
#ifdef WITH_FB_MEMORY_PROFILING
@ -164,17 +156,9 @@ std::string JSCExecutor::getDeviceCacheDir(){
void JSCExecutor::executeApplicationScript(
const std::string& script,
const std::string& sourceURL) {
JNIEnv* env = Environment::current();
jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
jmethodID logMarkerMethod = facebook::react::getLogMarkerMethod();
jstring startStringMarker = env->NewStringUTF("executeApplicationScript_startStringConvert");
jstring endStringMarker = env->NewStringUTF("executeApplicationScript_endStringConvert");
env->CallStaticVoidMethod(markerClass, logMarkerMethod, startStringMarker);
ReactMarker::logMarker("executeApplicationScript_startStringConvert");
String jsScript = String::createExpectingAscii(script);
env->CallStaticVoidMethod(markerClass, logMarkerMethod, endStringMarker);
env->DeleteLocalRef(startStringMarker);
env->DeleteLocalRef(endStringMarker);
ReactMarker::logMarker("executeApplicationScript_endStringConvert");
String jsSourceURL(sourceURL.c_str());
#ifdef WITH_FBSYSTRACE
@ -504,29 +488,6 @@ JSValueRef JSCExecutor::nativeTerminateWorker(
return JSValueMakeUndefined(ctx);
}
static JSValueRef nativeLoggingHook(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[], JSValueRef *exception) {
android_LogPriority logLevel = ANDROID_LOG_DEBUG;
if (argumentCount > 1) {
int level = (int) JSValueToNumber(ctx, arguments[1], NULL);
// The lowest log level we get from JS is 0. We shift and cap it to be
// in the range the Android logging method expects.
logLevel = std::min(
static_cast<android_LogPriority>(level + ANDROID_LOG_DEBUG),
ANDROID_LOG_FATAL);
}
if (argumentCount > 0) {
JSStringRef jsString = JSValueToStringCopy(ctx, arguments[0], NULL);
String message = String::adopt(jsString);
FBLOG_PRI(logLevel, "ReactNativeJS", "%s", message.str().c_str());
}
return JSValueMakeUndefined(ctx);
}
static JSValueRef nativePerformanceNow(
JSContextRef ctx,
JSObjectRef function,

View File

@ -16,6 +16,7 @@
#include "jni/JMessageQueueThread.h"
#include "jni/JSLoader.h"
#include "jni/WebWorkers.h"
#include "Platform.h"
#include "Value.h"
#include <JavaScriptCore/JSValueRef.h>
@ -109,7 +110,7 @@ void JSCWebWorker::initJSVMAndLoadScript() {
s_globalContextRefToJSCWebWorker[context_] = this;
// TODO(9604438): Protect against script does not exist
std::string script = loadScriptFromAssets(scriptName_);
std::string script = WebWorkerUtil::loadScriptFromAssets(scriptName_);
evaluateScript(context_, String(script.c_str()), String(scriptName_.c_str()));
installGlobalFunction(context_, "postMessage", nativePostMessage);

View File

@ -0,0 +1,24 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "Platform.h"
namespace facebook {
namespace react {
namespace ReactMarker {
LogMarker logMarker;
};
namespace WebWorkerUtil {
LoadScriptFromAssets loadScriptFromAssets;
};
namespace PerfLogging {
InstallNativeHooks installNativeHooks;
}
namespace JSLogging {
JSCNativeHook nativeHook = nullptr;
}
} }

View File

@ -0,0 +1,39 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <JavaScriptCore/JSContextRef.h>
namespace facebook {
namespace react {
namespace ReactMarker {
using LogMarker = std::function<void(const std::string&)>;
extern LogMarker logMarker;
};
namespace WebWorkerUtil {
using LoadScriptFromAssets = std::function<std::string(const std::string& assetName)>;
extern LoadScriptFromAssets loadScriptFromAssets;
};
namespace PerfLogging {
using InstallNativeHooks = std::function<void(JSGlobalContextRef)>;
extern InstallNativeHooks installNativeHooks;
}
namespace JSLogging {
using JSCNativeHook = JSValueRef (*) (
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[], JSValueRef *exception);
extern JSCNativeHook nativeHook;
}
} }

View File

@ -5,6 +5,7 @@ SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
DEPS = [
'//native/jni:jni',
'//native/third-party/android-ndk:android',
'//xplat/folly:molly',
]
@ -28,14 +29,18 @@ jni_library(
supported_platforms_regex = SUPPORTED_PLATFORMS,
srcs = [
'JMessageQueueThread.cpp',
'JSCPerfLogging.cpp',
'JSLoader.cpp',
'NativeArray.cpp',
'OnLoad.cpp',
'ProxyExecutor.cpp',
'JSLogging.cpp',
],
headers = [
'JSLoader.h',
'ProxyExecutor.h',
'JSCPerfLogging.h',
'JSLogging.h',
],
exported_headers = [
'JMessageQueueThread.h',

View File

@ -1,8 +1,10 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "JSCHelpers.h"
#include "JSCPerfLogging.h"
#include <fb/log.h>
#include <jni/fbjni.h>
#include <react/JSCHelpers.h>
using namespace facebook::jni;

View File

@ -21,7 +21,7 @@ static jclass gApplicationHolderClass;
static jmethodID gGetApplicationMethod;
static jmethodID gGetAssetManagerMethod;
std::string loadScriptFromAssets(std::string assetName) {
std::string loadScriptFromAssets(const std::string& assetName) {
JNIEnv *env = jni::Environment::current();
jobject application = env->CallStaticObjectMethod(
gApplicationHolderClass,
@ -32,7 +32,7 @@ std::string loadScriptFromAssets(std::string assetName) {
std::string loadScriptFromAssets(
AAssetManager *manager,
std::string assetName) {
const std::string& assetName) {
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromAssets",
"assetName", assetName);
@ -59,7 +59,7 @@ std::string loadScriptFromAssets(
return "";
}
std::string loadScriptFromFile(std::string fileName) {
std::string loadScriptFromFile(const std::string& fileName) {
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromFile",
"fileName", fileName);

View File

@ -13,17 +13,17 @@ namespace react {
* Helper method for loading a JS script from Android assets without
* a reference to an AssetManager.
*/
std::string loadScriptFromAssets(std::string assetName);
std::string loadScriptFromAssets(const std::string& assetName);
/**
* Helper method for loading JS script from android asset
*/
std::string loadScriptFromAssets(AAssetManager *assetManager, std::string assetName);
std::string loadScriptFromAssets(AAssetManager *assetManager, const std::string& assetName);
/**
* Helper method for loading JS script from a file
*/
std::string loadScriptFromFile(std::string fileName);
std::string loadScriptFromFile(const std::string& fileName);
void registerJSLoaderNatives();

View File

@ -0,0 +1,36 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "JSLogging.h"
#include <android/log.h>
#include <algorithm>
#include <react/Value.h>
#include <fb/log.h>
namespace facebook {
namespace react {
JSValueRef nativeLoggingHook(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[], JSValueRef *exception) {
android_LogPriority logLevel = ANDROID_LOG_DEBUG;
if (argumentCount > 1) {
int level = (int) JSValueToNumber(ctx, arguments[1], NULL);
// The lowest log level we get from JS is 0. We shift and cap it to be
// in the range the Android logging method expects.
logLevel = std::min(
static_cast<android_LogPriority>(level + ANDROID_LOG_DEBUG),
ANDROID_LOG_FATAL);
}
if (argumentCount > 0) {
JSStringRef jsString = JSValueToStringCopy(ctx, arguments[0], NULL);
String message = String::adopt(jsString);
FBLOG_PRI(logLevel, "ReactNativeJS", "%s", message.str().c_str());
}
return JSValueMakeUndefined(ctx);
}
}};

View File

@ -0,0 +1,15 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <JavaScriptCore/JSContextRef.h>
namespace facebook {
namespace react {
JSValueRef nativeLoggingHook(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[], JSValueRef *exception);
}}

View File

@ -15,11 +15,14 @@
#include <react/Executor.h>
#include <react/JSCExecutor.h>
#include <react/JSModulesUnbundle.h>
#include <react/Platform.h>
#include "JNativeRunnable.h"
#include "JSLoader.h"
#include "ReadableNativeArray.h"
#include "ProxyExecutor.h"
#include "OnLoad.h"
#include "JSLogging.h"
#include "JSCPerfLogging.h"
#include <algorithm>
#ifdef WITH_FBSYSTRACE
@ -561,6 +564,15 @@ static jmethodID gCallbackMethod;
static jmethodID gOnBatchCompleteMethod;
static jmethodID gLogMarkerMethod;
static void logMarker(const std::string& marker) {
JNIEnv* env = Environment::current();
jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
jstring jmarker = env->NewStringUTF(marker.c_str());
env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, jmarker);
env->DeleteLocalRef(markerClass);
env->DeleteLocalRef(jmarker);
}
static void makeJavaCall(JNIEnv* env, jobject callback, MethodCall&& call) {
if (call.arguments.isNull()) {
return;
@ -801,6 +813,15 @@ jmethodID getLogMarkerMethod() {
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return initialize(vm, [] {
// Inject some behavior into react/
ReactMarker::logMarker = bridge::logMarker;
WebWorkerUtil::loadScriptFromAssets =
[] (const std::string& assetName) {
return loadScriptFromAssets(assetName);
};
PerfLogging::installNativeHooks = addNativePerfLoggingHooks;
JSLogging::nativeHook = nativeLoggingHook;
// get the current env
JNIEnv* env = Environment::current();