123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- /*
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
- #include "Instance.h"
- #include "JSBigString.h"
- #include "JSBundleType.h"
- #include "JSExecutor.h"
- #include "MessageQueueThread.h"
- #include "MethodCall.h"
- #include "NativeToJsBridge.h"
- #include "RAMBundleRegistry.h"
- #include "RecoverableError.h"
- #include "SystraceSection.h"
- #include <cxxreact/JSIndexedRAMBundle.h>
- #include <folly/MoveWrapper.h>
- #include <folly/json.h>
- #include <glog/logging.h>
- #include <condition_variable>
- #include <exception>
- #include <fstream>
- #include <memory>
- #include <mutex>
- #include <string>
- namespace facebook {
- namespace react {
- Instance::~Instance() {
- if (nativeToJsBridge_) {
- nativeToJsBridge_->destroy();
- }
- }
- void Instance::initializeBridge(
- std::unique_ptr<InstanceCallback> callback,
- std::shared_ptr<JSExecutorFactory> jsef,
- std::shared_ptr<MessageQueueThread> jsQueue,
- std::shared_ptr<ModuleRegistry> moduleRegistry) {
- callback_ = std::move(callback);
- moduleRegistry_ = std::move(moduleRegistry);
- jsQueue->runOnQueueSync([this, &jsef, jsQueue]() mutable {
- nativeToJsBridge_ = std::make_shared<NativeToJsBridge>(
- jsef.get(), moduleRegistry_, jsQueue, callback_);
- nativeToJsBridge_->initializeRuntime();
- /**
- * After NativeToJsBridge is created, the jsi::Runtime should exist.
- * Also, the JS message queue thread exists. So, it's safe to
- * schedule all queued up js Calls.
- */
- jsCallInvoker_->setNativeToJsBridgeAndFlushCalls(nativeToJsBridge_);
- std::lock_guard<std::mutex> lock(m_syncMutex);
- m_syncReady = true;
- m_syncCV.notify_all();
- });
- CHECK(nativeToJsBridge_);
- }
- void Instance::loadBundle(
- std::unique_ptr<RAMBundleRegistry> bundleRegistry,
- std::unique_ptr<const JSBigString> string,
- std::string sourceURL) {
- callback_->incrementPendingJSCalls();
- SystraceSection s("Instance::loadBundle", "sourceURL", sourceURL);
- nativeToJsBridge_->loadBundle(
- std::move(bundleRegistry), std::move(string), std::move(sourceURL));
- }
- void Instance::loadBundleSync(
- std::unique_ptr<RAMBundleRegistry> bundleRegistry,
- std::unique_ptr<const JSBigString> string,
- std::string sourceURL) {
- std::unique_lock<std::mutex> lock(m_syncMutex);
- m_syncCV.wait(lock, [this] { return m_syncReady; });
- SystraceSection s("Instance::loadBundleSync", "sourceURL", sourceURL);
- nativeToJsBridge_->loadBundleSync(
- std::move(bundleRegistry), std::move(string), std::move(sourceURL));
- }
- void Instance::setSourceURL(std::string sourceURL) {
- callback_->incrementPendingJSCalls();
- SystraceSection s("Instance::setSourceURL", "sourceURL", sourceURL);
- nativeToJsBridge_->loadBundle(nullptr, nullptr, std::move(sourceURL));
- }
- void Instance::loadScriptFromString(
- std::unique_ptr<const JSBigString> string,
- std::string sourceURL,
- bool loadSynchronously) {
- SystraceSection s("Instance::loadScriptFromString", "sourceURL", sourceURL);
- if (loadSynchronously) {
- loadBundleSync(nullptr, std::move(string), std::move(sourceURL));
- } else {
- loadBundle(nullptr, std::move(string), std::move(sourceURL));
- }
- }
- bool Instance::isIndexedRAMBundle(const char *sourcePath) {
- std::ifstream bundle_stream(sourcePath, std::ios_base::in);
- BundleHeader header;
- if (!bundle_stream ||
- !bundle_stream.read(reinterpret_cast<char *>(&header), sizeof(header))) {
- return false;
- }
- return parseTypeFromHeader(header) == ScriptTag::RAMBundle;
- }
- bool Instance::isIndexedRAMBundle(std::unique_ptr<const JSBigString> *script) {
- BundleHeader header;
- strncpy(
- reinterpret_cast<char *>(&header),
- script->get()->c_str(),
- sizeof(header));
- return parseTypeFromHeader(header) == ScriptTag::RAMBundle;
- }
- void Instance::loadRAMBundleFromString(
- std::unique_ptr<const JSBigString> script,
- const std::string &sourceURL) {
- auto bundle = std::make_unique<JSIndexedRAMBundle>(std::move(script));
- auto startupScript = bundle->getStartupCode();
- auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
- loadRAMBundle(std::move(registry), std::move(startupScript), sourceURL, true);
- }
- void Instance::loadRAMBundleFromFile(
- const std::string &sourcePath,
- const std::string &sourceURL,
- bool loadSynchronously) {
- auto bundle = std::make_unique<JSIndexedRAMBundle>(sourcePath.c_str());
- auto startupScript = bundle->getStartupCode();
- auto registry = RAMBundleRegistry::multipleBundlesRegistry(
- std::move(bundle), JSIndexedRAMBundle::buildFactory());
- loadRAMBundle(
- std::move(registry),
- std::move(startupScript),
- sourceURL,
- loadSynchronously);
- }
- void Instance::loadRAMBundle(
- std::unique_ptr<RAMBundleRegistry> bundleRegistry,
- std::unique_ptr<const JSBigString> startupScript,
- std::string startupScriptSourceURL,
- bool loadSynchronously) {
- if (loadSynchronously) {
- loadBundleSync(
- std::move(bundleRegistry),
- std::move(startupScript),
- std::move(startupScriptSourceURL));
- } else {
- loadBundle(
- std::move(bundleRegistry),
- std::move(startupScript),
- std::move(startupScriptSourceURL));
- }
- }
- void Instance::setGlobalVariable(
- std::string propName,
- std::unique_ptr<const JSBigString> jsonValue) {
- nativeToJsBridge_->setGlobalVariable(
- std::move(propName), std::move(jsonValue));
- }
- void *Instance::getJavaScriptContext() {
- return nativeToJsBridge_ ? nativeToJsBridge_->getJavaScriptContext()
- : nullptr;
- }
- bool Instance::isInspectable() {
- return nativeToJsBridge_ ? nativeToJsBridge_->isInspectable() : false;
- }
- bool Instance::isBatchActive() {
- return nativeToJsBridge_ ? nativeToJsBridge_->isBatchActive() : false;
- }
- void Instance::callJSFunction(
- std::string &&module,
- std::string &&method,
- folly::dynamic &¶ms) {
- callback_->incrementPendingJSCalls();
- nativeToJsBridge_->callFunction(
- std::move(module), std::move(method), std::move(params));
- }
- void Instance::callJSCallback(uint64_t callbackId, folly::dynamic &¶ms) {
- SystraceSection s("Instance::callJSCallback");
- callback_->incrementPendingJSCalls();
- nativeToJsBridge_->invokeCallback((double)callbackId, std::move(params));
- }
- void Instance::registerBundle(
- uint32_t bundleId,
- const std::string &bundlePath) {
- nativeToJsBridge_->registerBundle(bundleId, bundlePath);
- }
- const ModuleRegistry &Instance::getModuleRegistry() const {
- return *moduleRegistry_;
- }
- ModuleRegistry &Instance::getModuleRegistry() {
- return *moduleRegistry_;
- }
- void Instance::handleMemoryPressure(int pressureLevel) {
- nativeToJsBridge_->handleMemoryPressure(pressureLevel);
- }
- std::shared_ptr<CallInvoker> Instance::getJSCallInvoker() {
- return std::static_pointer_cast<CallInvoker>(jsCallInvoker_);
- }
- std::shared_ptr<CallInvoker> Instance::getDecoratedNativeCallInvoker(
- std::shared_ptr<CallInvoker> nativeInvoker) {
- return nativeToJsBridge_->getDecoratedNativeCallInvoker(nativeInvoker);
- }
- void Instance::JSCallInvoker::setNativeToJsBridgeAndFlushCalls(
- std::weak_ptr<NativeToJsBridge> nativeToJsBridge) {
- std::lock_guard<std::mutex> guard(m_mutex);
- m_shouldBuffer = false;
- m_nativeToJsBridge = nativeToJsBridge;
- while (m_workBuffer.size() > 0) {
- scheduleAsync(std::move(m_workBuffer.front()));
- m_workBuffer.pop_front();
- }
- }
- void Instance::JSCallInvoker::invokeSync(std::function<void()> &&work) {
- // TODO: Replace JS Callinvoker with RuntimeExecutor.
- throw std::runtime_error(
- "Synchronous native -> JS calls are currently not supported.");
- }
- void Instance::JSCallInvoker::invokeAsync(std::function<void()> &&work) {
- std::lock_guard<std::mutex> guard(m_mutex);
- /**
- * Why is is necessary to queue up async work?
- *
- * 1. TurboModuleManager must be created synchronously after the Instance,
- * before we load the source code. This is when the NativeModule system
- * is initialized. RCTDevLoadingView shows bundle download progress.
- * 2. TurboModuleManager requires a JS CallInvoker.
- * 3. The JS CallInvoker requires the NativeToJsBridge, which is created on
- * the JS thread in Instance::initializeBridge.
- *
- * Therefore, although we don't call invokeAsync before the JS bundle is
- * executed, this buffering is implemented anyways to ensure that work
- * isn't discarded.
- */
- if (m_shouldBuffer) {
- m_workBuffer.push_back(std::move(work));
- return;
- }
- scheduleAsync(std::move(work));
- }
- void Instance::JSCallInvoker::scheduleAsync(std::function<void()> &&work) {
- if (auto strongNativeToJsBridge = m_nativeToJsBridge.lock()) {
- strongNativeToJsBridge->runOnExecutorQueue(
- [work = std::move(work)](JSExecutor *executor) {
- work();
- executor->flush();
- });
- }
- }
- } // namespace react
- } // namespace facebook
|