Flows between RN Threads
Reviewed By: tadeuzagallo Differential Revision: D2743733 fb-gh-sync-id: df4ae69a3501a37e08286857a8d4be3cd27c0ac3
This commit is contained in:
parent
cdad5c047a
commit
e42c6d4446
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue