Flows between RN Threads

Reviewed By: tadeuzagallo

Differential Revision: D2743733

fb-gh-sync-id: df4ae69a3501a37e08286857a8d4be3cd27c0ac3
This commit is contained in:
Mike Armstrong 2016-01-04 02:15:19 -08:00 committed by facebook-github-bot-3
parent cdad5c047a
commit e42c6d4446
8 changed files with 106 additions and 25 deletions

View File

@ -24,8 +24,11 @@ let stringifySafe = require('stringifySafe');
let MODULE_IDS = 0;
let METHOD_IDS = 1;
let PARAMS = 2;
let CALL_IDS = 3;
let MIN_TIME_BETWEEN_FLUSHES_MS = 5;
let TRACE_TAG_REACT_APPS = 1 << 17;
let SPY_MODE = false;
let MethodTypes = keyMirror({
@ -47,11 +50,12 @@ class MessageQueue {
this.RemoteModules = {};
this._callableModules = {};
this._queue = [[],[],[]];
this._queue = [[], [], [], 0];
this._moduleTable = {};
this._methodTable = {};
this._callbacks = [];
this._callbackID = 0;
this._callID = 0;
this._lastFlush = 0;
this._eventLoopStartTime = new Date().getTime();
@ -100,7 +104,7 @@ class MessageQueue {
this.__callImmediates();
let queue = this._queue;
this._queue = [[],[],[]];
this._queue = [[], [], [], this._callID];
return queue[0].length ? queue : null;
}
@ -136,6 +140,11 @@ class MessageQueue {
onSucc && params.push(this._callbackID);
this._callbacks[this._callbackID++] = onSucc;
}
global.nativeTraceBeginAsyncFlow &&
global.nativeTraceBeginAsyncFlow(TRACE_TAG_REACT_APPS, 'native', this._callID);
this._callID++;
this._queue[MODULE_IDS].push(module);
this._queue[METHOD_IDS].push(method);
this._queue[PARAMS].push(params);
@ -144,7 +153,7 @@ class MessageQueue {
if (global.nativeFlushQueueImmediate &&
now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS) {
global.nativeFlushQueueImmediate(this._queue);
this._queue = [[],[],[]];
this._queue = [[], [], [], this._callID];
this._lastFlush = now;
}
Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length);
@ -176,22 +185,22 @@ class MessageQueue {
}
__invokeCallback(cbID, args) {
Systrace.beginEvent(`MessageQueue.invokeCallback(${cbID})`);
this._lastFlush = new Date().getTime();
this._eventLoopStartTime = this._lastFlush;
let callback = this._callbacks[cbID];
if (!callback || __DEV__) {
let debug = this._debugInfo[cbID >> 1];
let module = debug && this._remoteModuleTable[debug[0]];
let method = debug && this._remoteMethodTable[debug[0]][debug[1]];
invariant(
callback,
`Callback with id ${cbID}: ${module}.${method}() not found`
);
if (callback && SPY_MODE) {
console.log('N->JS : <callback for ' + module + '.' + method + '>(' + JSON.stringify(args) + ')');
}
let debug = this._debugInfo[cbID >> 1];
let module = debug && this._remoteModuleTable[debug[0]];
let method = debug && this._remoteMethodTable[debug[0]][debug[1]];
invariant(
callback,
`Callback with id ${cbID}: ${module}.${method}() not found`
);
let profileName = debug ? '<callback for ' + module + '.' + method + '>' : cbID;
if (callback && SPY_MODE && __DEV__) {
console.log('N->JS : ' + profileName + '(' + JSON.stringify(args) + ')');
}
Systrace.beginEvent(
`MessageQueue.invokeCallback(${profileName}, ${stringifySafe(args)})`);
this._callbacks[cbID & ~1] = null;
this._callbacks[cbID | 1] = null;
callback.apply(null, args);

View File

@ -778,19 +778,18 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
}
}
- (void)handleBuffer:(NSArray<NSArray *> *)buffer
- (void)handleBuffer:(NSArray *)buffer
{
NSArray<NSArray *> *requestsArray = [RCTConvert NSArrayArray:buffer];
NSArray *requestsArray = [RCTConvert NSArray:buffer];
if (RCT_DEBUG && requestsArray.count <= RCTBridgeFieldParamss) {
RCTLogError(@"Buffer should contain at least %tu sub-arrays. Only found %tu",
RCTBridgeFieldParamss + 1, requestsArray.count);
RCTBridgeFieldParamss + 1, requestsArray.count);
return;
}
NSArray<NSNumber *> *moduleIDs = requestsArray[RCTBridgeFieldRequestModuleIDs];
NSArray<NSNumber *> *methodIDs = requestsArray[RCTBridgeFieldMethodIDs];
NSArray<NSArray *> *paramsArrays = requestsArray[RCTBridgeFieldParamss];
NSArray<NSNumber *> *moduleIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldRequestModuleIDs]];
NSArray<NSNumber *> *methodIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldMethodIDs]];
NSArray<NSArray *> *paramsArrays = [RCTConvert NSArrayArray:requestsArray[RCTBridgeFieldParamss]];
if (RCT_DEBUG && (moduleIDs.count != methodIDs.count || moduleIDs.count != paramsArrays.count)) {
RCTLogError(@"Invalid data message - all must be length: %zd", moduleIDs.count);

View File

@ -56,6 +56,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
private final TraceListener mTraceListener;
private final JavaScriptModuleRegistry mJSModuleRegistry;
private final JSBundleLoader mJSBundleLoader;
private volatile int mTraceID = 0;
// Access from native modules thread
private final NativeModuleRegistry mJavaRegistry;
@ -176,12 +177,23 @@ public class CatalystInstanceImpl implements CatalystInstance {
incrementPendingJSCalls();
final int traceID = mTraceID++;
Systrace.startAsyncFlow(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
tracingName,
traceID);
mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
new Runnable() {
@Override
public void run() {
mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
Systrace.endAsyncFlow(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
tracingName,
traceID);
if (mDestroyed) {
return;
}
@ -208,12 +220,23 @@ public class CatalystInstanceImpl implements CatalystInstance {
incrementPendingJSCalls();
final int traceID = mTraceID++;
Systrace.startAsyncFlow(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"<callback>",
traceID);
mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
new Runnable() {
@Override
public void run() {
mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
Systrace.endAsyncFlow(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"<callback>",
traceID);
if (mDestroyed) {
return;
}

View File

@ -18,9 +18,12 @@ package com.facebook.react.uimanager.events;
*/
public abstract class Event<T extends Event> {
private static int sUniqueID = 0;
private boolean mInitialized;
private int mViewTag;
private long mTimestampMs;
private int mUniqueID = sUniqueID++;
protected Event() {
}
@ -80,6 +83,13 @@ public abstract class Event<T extends Event> {
return 0;
}
/**
* @return The unique id of this event.
*/
public int getUniqueID() {
return mUniqueID;
}
/**
* Called when the EventDispatcher is done with an event, either because it was dispatched or
* because it was coalesced with another Event.

View File

@ -100,6 +100,7 @@ public class EventDispatcher implements LifecycleEventListener {
private volatile @Nullable ScheduleDispatchFrameCallback mCurrentFrameCallback;
private short mNextEventTypeId = 0;
private volatile boolean mHasDispatchScheduled = false;
private volatile int mHasDispatchScheduledCount = 0;
public EventDispatcher(ReactApplicationContext reactContext) {
mReactContext = reactContext;
@ -113,6 +114,10 @@ public class EventDispatcher implements LifecycleEventListener {
Assertions.assertCondition(event.isInitialized(), "Dispatched event hasn't been initialized");
synchronized (mEventsStagingLock) {
mEventStaging.add(event);
Systrace.startAsyncFlow(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
event.getEventName(),
event.getUniqueID());
}
}
@ -242,6 +247,10 @@ public class EventDispatcher implements LifecycleEventListener {
if (!mHasDispatchScheduled) {
mHasDispatchScheduled = true;
Systrace.startAsyncFlow(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"ScheduleDispatchFrameCallback",
mHasDispatchScheduledCount);
mReactContext.runOnJSQueueThread(mDispatchEventsRunnable);
}
@ -263,7 +272,12 @@ public class EventDispatcher implements LifecycleEventListener {
public void run() {
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "DispatchEventsRunnable");
try {
Systrace.endAsyncFlow(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"ScheduleDispatchFrameCallback",
mHasDispatchScheduledCount);
mHasDispatchScheduled = false;
mHasDispatchScheduledCount++;
Assertions.assertNotNull(mRCTEventEmitter);
synchronized (mEventsToDispatchLock) {
// We avoid allocating an array and iterator, and "sorting" if we don't need to.
@ -277,6 +291,10 @@ public class EventDispatcher implements LifecycleEventListener {
if (event == null) {
continue;
}
Systrace.endAsyncFlow(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
event.getEventName(),
event.getUniqueID());
event.dispatch(mRCTEventEmitter);
event.dispose();
}

View File

@ -12,6 +12,7 @@ namespace react {
#define REQUEST_MODULE_IDS 0
#define REQUEST_METHOD_IDS 1
#define REQUEST_PARAMSS 2
#define REQUEST_CALLID 3
std::vector<MethodCall> parseMethodCalls(const std::string& json) {
folly::dynamic jsonData = folly::parseJson(json);
@ -33,6 +34,7 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) {
auto moduleIds = jsonData[REQUEST_MODULE_IDS];
auto methodIds = jsonData[REQUEST_METHOD_IDS];
auto params = jsonData[REQUEST_PARAMSS];
int callId = -1;
if (!moduleIds.isArray() || !methodIds.isArray() || !params.isArray()) {
jni::throwNewJavaException(jni::gJavaLangIllegalArgumentException,
@ -40,6 +42,16 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) {
json.c_str());
}
if (jsonData.size() > REQUEST_CALLID) {
if (!jsonData[REQUEST_CALLID].isInt()) {
jni::throwNewJavaException(jni::gJavaLangIllegalArgumentException,
"Did not get valid calls back from JS: %s",
json.c_str());
} else {
callId = jsonData[REQUEST_CALLID].getInt();
}
}
std::vector<MethodCall> methodCalls;
for (size_t i = 0; i < moduleIds.size(); i++) {
auto paramsValue = params[i];
@ -51,7 +63,11 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) {
methodCalls.emplace_back(
moduleIds[i].getInt(),
methodIds[i].getInt(),
std::move(params[i]));
std::move(params[i]),
callId);
// only incremement callid if contains valid callid as callid is optional
callId += (callId != -1) ? 1 : 0;
}
return methodCalls;

View File

@ -15,11 +15,13 @@ struct MethodCall {
int moduleId;
int methodId;
folly::dynamic arguments;
int callId;
MethodCall(int mod, int meth, folly::dynamic args)
MethodCall(int mod, int meth, folly::dynamic args, int cid)
: moduleId(mod)
, methodId(meth)
, arguments(std::move(args)) {}
, arguments(std::move(args))
, callId(cid) {}
};
std::vector<MethodCall> parseMethodCalls(const std::string& json);

View File

@ -17,6 +17,7 @@
#include "ReadableNativeArray.h"
#include "ProxyExecutor.h"
#include "OnLoad.h"
#include <algorithm>
#ifdef WITH_FBSYSTRACE
#include <fbsystrace.h>
@ -561,6 +562,9 @@ static void makeJavaCall(JNIEnv* env, jobject callback, MethodCall&& call) {
if (call.arguments.isNull()) {
return;
}
if (call.callId != -1) {
fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", call.callId);
}
auto newArray = ReadableNativeArray::newObjectCxxArgs(std::move(call.arguments));
env->CallVoidMethod(callback, gCallbackMethod, call.moduleId, call.methodId, newArray.get());
}