Expose way for native modules to modify JSC context

Reviewed By: svcscm

Differential Revision: D2933197

fb-gh-sync-id: 32eb943ab341804343bbcadd29f0377fccf75de6
shipit-source-id: 32eb943ab341804343bbcadd29f0377fccf75de6
This commit is contained in:
Scott Kyle 2016-02-15 12:57:21 -08:00 committed by facebook-github-bot-1
parent 46a8f1d8e0
commit e5ba46c30d
13 changed files with 77 additions and 2 deletions

View File

@ -16,6 +16,15 @@
*/
RCT_EXTERN NSString *const RCTJSCThreadName;
/**
* This notification fires on the JS thread immediately after a `JSContext`
* is fully initialized, but before the JS bundle has been loaded. The object
* of this notification is the `JSContext`. Native modules should listen for
* notification only if they need to install custom functionality into the
* context. Note that this notification won't fire when debugging in Chrome.
*/
RCT_EXTERN NSString *const RCTJavaScriptContextCreatedNotification;
/**
* Uses a JavaScriptCore context as the execution engine.
*/

View File

@ -28,6 +28,8 @@
NSString *const RCTJSCThreadName = @"com.facebook.React.JavaScript";
NSString *const RCTJavaScriptContextCreatedNotification = @"RCTJavaScriptContextCreatedNotification";
static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled";
@interface RCTJavaScriptContext : NSObject <RCTInvalidating>
@ -332,7 +334,16 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
}];
[self executeBlockOnJavaScriptQueue:^{
RCTInstallJSCProfiler(_bridge, self.context.ctx);
RCTJSCExecutor *strongSelf = weakSelf;
if (!strongSelf.valid) {
return;
}
JSContext *context = strongSelf.context.context;
RCTInstallJSCProfiler(_bridge, context.JSGlobalContextRef);
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptContextCreatedNotification
object:context];
}];
for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {

View File

@ -332,6 +332,11 @@ public abstract class BaseJavaModule implements NativeModule {
return false;
}
@Override
public void onReactBridgeInitialized(ReactBridge bridge) {
// do nothing
}
@Override
public void onCatalystInstanceDestroy() {
// do nothing

View File

@ -127,6 +127,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
mJavaRegistry.notifyReactBridgeInitialized(bridge);
return bridge;
}

View File

@ -59,6 +59,15 @@ public interface NativeModule {
*/
boolean canOverrideExistingModule();
/**
* Called on the JS thread after a ReactBridge has been created. This is useful for native modules
* that need to do any setup before the JS bundle has been loaded. An example of this would be
* installing custom functionality into the JavaScriptCore context.
*
* @param bridge the ReactBridge instance that has just been created
*/
void onReactBridgeInitialized(ReactBridge bridge);
/**
* Called before {CatalystInstance#onHostDestroy}
*/

View File

@ -114,6 +114,19 @@ public class NativeModuleRegistry {
}
}
/* package */ void notifyReactBridgeInitialized(ReactBridge bridge) {
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"NativeModuleRegistry_notifyReactBridgeInitialized");
try {
for (NativeModule nativeModule : mModuleInstances.values()) {
nativeModule.onReactBridgeInitialized(bridge);
}
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
public void onBatchComplete() {
for (int i = 0; i < mBatchCompleteListenerModules.size(); i++) {
mBatchCompleteListenerModules.get(i).onBatchComplete();

View File

@ -87,4 +87,13 @@ public class ReactBridge extends Countable {
public native void stopProfiler(String title, String filename);
private native void handleMemoryPressureModerate();
private native void handleMemoryPressureCritical();
/**
* This method will return a long representing the underlying JSGlobalContextRef pointer or
* 0 (representing NULL) when in Chrome debug mode, and is only useful if passed back through
* the JNI to native code that will use it with the JavaScriptCore C API.
* **WARNING:** This method is *experimental* and should only be used when no other option is
* available. It will likely change in a future release!
*/
public native long getJavaScriptContextNativePtrExperimental();
}

View File

@ -57,6 +57,10 @@ void Bridge::setGlobalVariable(const std::string& propName, const std::string& j
m_mainExecutor->setGlobalVariable(propName, jsonValue);
}
void* Bridge::getJavaScriptContext() {
return m_mainExecutor->getJavaScriptContext();
}
bool Bridge::supportsProfiling() {
return m_mainExecutor->supportsProfiling();
}

View File

@ -54,6 +54,7 @@ public:
const std::string& startupCode,
const std::string& sourceURL);
void setGlobalVariable(const std::string& propName, const std::string& jsonValue);
void* getJavaScriptContext();
bool supportsProfiling();
void startProfiler(const std::string& title);
void stopProfiler(const std::string& title, const std::string& filename);

View File

@ -60,6 +60,9 @@ public:
virtual void setGlobalVariable(
const std::string& propName,
const std::string& jsonValue) = 0;
virtual void* getJavaScriptContext() {
return nullptr;
};
virtual bool supportsProfiling() {
return false;
};

View File

@ -198,6 +198,10 @@ void JSCExecutor::setGlobalVariable(const std::string& propName, const std::stri
JSObjectSetProperty(m_context, globalObject, jsPropertyName, valueToInject, 0, NULL);
}
void* JSCExecutor::getJavaScriptContext() {
return m_context;
}
bool JSCExecutor::supportsProfiling() {
#ifdef WITH_FBSYSTRACE
return true;

View File

@ -48,6 +48,7 @@ public:
virtual void setGlobalVariable(
const std::string& propName,
const std::string& jsonValue) override;
virtual void* getJavaScriptContext() override;
virtual bool supportsProfiling() override;
virtual void startProfiler(const std::string &titleString) override;
virtual void stopProfiler(const std::string &titleString, const std::string &filename) override;

View File

@ -760,6 +760,11 @@ static void setGlobalVariable(JNIEnv* env, jobject obj, jstring propName, jstrin
bridge->setGlobalVariable(fromJString(env, propName), fromJString(env, jsonValue));
}
static jlong getJavaScriptContext(JNIEnv *env, jobject obj) {
auto bridge = extractRefPtr<CountableBridge>(env, obj);
return (uintptr_t) bridge->getJavaScriptContext();
}
static jboolean supportsProfiling(JNIEnv* env, jobject obj) {
auto bridge = extractRefPtr<CountableBridge>(env, obj);
return bridge->supportsProfiling() ? JNI_TRUE : JNI_FALSE;
@ -944,7 +949,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
makeNativeMethod("stopProfiler", bridge::stopProfiler),
makeNativeMethod("handleMemoryPressureModerate", bridge::handleMemoryPressureModerate),
makeNativeMethod("handleMemoryPressureCritical", bridge::handleMemoryPressureCritical),
makeNativeMethod("getJavaScriptContextNativePtrExperimental", bridge::getJavaScriptContext),
});
jclass nativeRunnableClass = env->FindClass("com/facebook/react/bridge/queue/NativeRunnableDeprecated");