174 lines
5.6 KiB
C
174 lines
5.6 KiB
C
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <atomic>
|
||
|
#include <functional>
|
||
|
#include <map>
|
||
|
#include <vector>
|
||
|
|
||
|
#include <folly/dynamic.h>
|
||
|
|
||
|
#include "Executor.h"
|
||
|
#include "ExecutorToken.h"
|
||
|
#include "ExecutorTokenFactory.h"
|
||
|
#include "JSModulesUnbundle.h"
|
||
|
#include "MessageQueueThread.h"
|
||
|
#include "MethodCall.h"
|
||
|
#include "NativeModule.h"
|
||
|
#include "Value.h"
|
||
|
|
||
|
namespace folly {
|
||
|
|
||
|
struct dynamic;
|
||
|
|
||
|
}
|
||
|
|
||
|
namespace facebook {
|
||
|
namespace react {
|
||
|
|
||
|
class BridgeCallback {
|
||
|
public:
|
||
|
virtual ~BridgeCallback() {};
|
||
|
|
||
|
virtual void onCallNativeModules(
|
||
|
ExecutorToken executorToken,
|
||
|
const std::string& callJSON,
|
||
|
bool isEndOfBatch) = 0;
|
||
|
|
||
|
virtual void onExecutorUnregistered(ExecutorToken executorToken) = 0;
|
||
|
|
||
|
virtual MethodCallResult callSerializableNativeHook(ExecutorToken token, unsigned int moduleId, unsigned int methodId, folly::dynamic&& args) = 0;
|
||
|
};
|
||
|
|
||
|
class Bridge;
|
||
|
class ExecutorRegistration {
|
||
|
public:
|
||
|
ExecutorRegistration(
|
||
|
std::unique_ptr<JSExecutor> executor,
|
||
|
std::shared_ptr<MessageQueueThread> executorMessageQueueThread) :
|
||
|
executor_(std::move(executor)),
|
||
|
messageQueueThread_(executorMessageQueueThread) {}
|
||
|
|
||
|
std::unique_ptr<JSExecutor> executor_;
|
||
|
std::shared_ptr<MessageQueueThread> messageQueueThread_;
|
||
|
};
|
||
|
|
||
|
class Bridge {
|
||
|
public:
|
||
|
/**
|
||
|
* This must be called on the main JS thread.
|
||
|
*/
|
||
|
Bridge(
|
||
|
JSExecutorFactory* jsExecutorFactory,
|
||
|
std::shared_ptr<MessageQueueThread> jsQueue,
|
||
|
std::unique_ptr<ExecutorTokenFactory> executorTokenFactory,
|
||
|
std::unique_ptr<BridgeCallback> callback);
|
||
|
virtual ~Bridge();
|
||
|
|
||
|
/**
|
||
|
* Executes a function with the module ID and method ID and any additional
|
||
|
* arguments in JS.
|
||
|
*/
|
||
|
void callFunction(
|
||
|
ExecutorToken executorToken,
|
||
|
const std::string& moduleId,
|
||
|
const std::string& methodId,
|
||
|
const folly::dynamic& args,
|
||
|
const std::string& tracingName);
|
||
|
|
||
|
/**
|
||
|
* Invokes a callback with the cbID, and optional additional arguments in JS.
|
||
|
*/
|
||
|
void invokeCallback(ExecutorToken executorToken, const double callbackId, const folly::dynamic& args);
|
||
|
|
||
|
/**
|
||
|
* Starts the JS application from an "bundle", i.e. a JavaScript file that
|
||
|
* contains code for all modules and a runtime that resolves and
|
||
|
* executes modules.
|
||
|
*/
|
||
|
void loadApplicationScript(const std::string& script, const std::string& sourceURL);
|
||
|
|
||
|
/**
|
||
|
* An "unbundle" is a backend that stores and injects JavaScript modules as
|
||
|
* individual scripts, rather than bundling all of them into a single scrupt.
|
||
|
*
|
||
|
* Loading an unbundle means setting the storage backend and executing the
|
||
|
* startup script.
|
||
|
*/
|
||
|
void loadApplicationUnbundle(
|
||
|
std::unique_ptr<JSModulesUnbundle> unbundle,
|
||
|
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);
|
||
|
void handleMemoryPressureModerate();
|
||
|
void handleMemoryPressureCritical();
|
||
|
|
||
|
/**
|
||
|
* Invokes a set of native module calls on behalf of the given executor.
|
||
|
*
|
||
|
* TODO: get rid of isEndOfBatch
|
||
|
*/
|
||
|
void callNativeModules(JSExecutor& executor, const std::string& callJSON, bool isEndOfBatch);
|
||
|
|
||
|
MethodCallResult callSerializableNativeHook(unsigned int moduleId, unsigned int methodId, const std::string& argsJSON);
|
||
|
|
||
|
/**
|
||
|
* Returns the ExecutorToken corresponding to the main JSExecutor.
|
||
|
*/
|
||
|
ExecutorToken getMainExecutorToken() const;
|
||
|
|
||
|
/**
|
||
|
* Registers the given JSExecutor which runs on the given MessageQueueThread
|
||
|
* with the Bridge. Part of this registration is transfering ownership of this
|
||
|
* JSExecutor to the Bridge for the duration of the registration.
|
||
|
*
|
||
|
* Returns a ExecutorToken which can be used to refer to this JSExecutor
|
||
|
* in the Bridge.
|
||
|
*/
|
||
|
ExecutorToken registerExecutor(
|
||
|
std::unique_ptr<JSExecutor> executor,
|
||
|
std::shared_ptr<MessageQueueThread> executorMessageQueueThread);
|
||
|
|
||
|
/**
|
||
|
* Unregisters a JSExecutor that was previously registered with this Bridge
|
||
|
* using registerExecutor. Use the ExecutorToken returned from this
|
||
|
* registerExecutor call. This method will return ownership of the unregistered
|
||
|
* executor to the caller for it to retain or tear down.
|
||
|
*
|
||
|
* Returns ownership of the unregistered executor.
|
||
|
*/
|
||
|
std::unique_ptr<JSExecutor> unregisterExecutor(ExecutorToken executorToken);
|
||
|
|
||
|
/**
|
||
|
* Synchronously tears down the bridge and the main executor.
|
||
|
*/
|
||
|
void destroy();
|
||
|
private:
|
||
|
void runOnExecutorQueue(ExecutorToken token, std::function<void(JSExecutor*)> task);
|
||
|
std::unique_ptr<BridgeCallback> m_callback;
|
||
|
// This is used to avoid a race condition where a proxyCallback gets queued after ~Bridge(),
|
||
|
// on the same thread. In that case, the callback will try to run the task on m_callback which
|
||
|
// will have been destroyed within ~Bridge(), thus causing a SIGSEGV.
|
||
|
std::shared_ptr<bool> m_destroyed;
|
||
|
JSExecutor* m_mainExecutor;
|
||
|
std::unique_ptr<ExecutorToken> m_mainExecutorToken;
|
||
|
std::unique_ptr<ExecutorTokenFactory> m_executorTokenFactory;
|
||
|
std::unordered_map<JSExecutor*, ExecutorToken> m_executorTokenMap;
|
||
|
std::unordered_map<ExecutorToken, std::unique_ptr<ExecutorRegistration>> m_executorMap;
|
||
|
std::mutex m_registrationMutex;
|
||
|
#ifdef WITH_FBSYSTRACE
|
||
|
std::atomic_uint_least32_t m_systraceCookie = ATOMIC_VAR_INIT();
|
||
|
#endif
|
||
|
|
||
|
MessageQueueThread* getMessageQueueThread(const ExecutorToken& executorToken);
|
||
|
JSExecutor* getExecutor(const ExecutorToken& executorToken);
|
||
|
inline ExecutorToken getTokenForExecutor(JSExecutor& executor);
|
||
|
};
|
||
|
|
||
|
} }
|