mirror of
https://github.com/status-im/react-native.git
synced 2025-02-24 07:08:27 +00:00
Summary: Co-Authored: zamotany With React Native 0.59.8 the app keeps crashing with indexed RAM bundle on Android with the following error: ``` 2019-05-09 11:58:06.684 2793-2856/? E/AndroidRuntime: FATAL EXCEPTION: mqt_js Process: com.ramtestapp, PID: 2793 com.facebook.jni.CppException: getPropertyAsObject: property '__fbRequireBatchedBridge' is not an Object no stack at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29) at android.os.Looper.loop(Looper.java:193) at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232) at java.lang.Thread.run(Thread.java:764) ``` After investigation we found that when using any bundle, let it be non-ram, FIle RAM bundle or Index RAM bundle, the `CatalystInstanceImpl.java` is always using `loadScriptsFromAsset`, which is calling `CatalystInstanceImpl::jniLoadScriptFromAssets` in C++. This method when checking if bundle is a RAM bundle, uses `JniJSModulesUnbundle::isUnbundle` which only check for js-modules/UNBUNDLE - file generated when building File RAM bundle. There is no other logic to handle Indexed RAM bundle, so it figures that the bundle is not RAM, cause there is no js-modules/UNBUNDLE file and tries to load as regular bundle and fails. In this PR we added check if it is indexed RAM bundle in `jniLoadScriptFromAssets` and handle it if it is. ## Changelog [Android] [Fixed] fix indexed RAM bundle Solves https://github.com/facebook/react-native/issues/21282 Pull Request resolved: https://github.com/facebook/react-native/pull/24967 Differential Revision: D15575924 Pulled By: cpojer fbshipit-source-id: 5ea428e0b793edd8242243f39f933d1092b35260 # Conflicts: # ReactCommon/cxxreact/JSIndexedRAMBundle.cpp
203 lines
6.9 KiB
C++
203 lines
6.9 KiB
C++
// 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/Memory.h>
|
|
#include <folly/MoveWrapper.h>
|
|
#include <folly/json.h>
|
|
|
|
#include <glog/logging.h>
|
|
|
|
#include <condition_variable>
|
|
#include <fstream>
|
|
#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_ = folly::make_unique<NativeToJsBridge>(
|
|
jsef.get(), moduleRegistry_, jsQueue, callback_);
|
|
|
|
std::lock_guard<std::mutex> lock(m_syncMutex);
|
|
m_syncReady = true;
|
|
m_syncCV.notify_all();
|
|
});
|
|
|
|
CHECK(nativeToJsBridge_);
|
|
}
|
|
|
|
void Instance::loadApplication(std::unique_ptr<RAMBundleRegistry> bundleRegistry,
|
|
std::unique_ptr<const JSBigString> string,
|
|
std::string sourceURL) {
|
|
callback_->incrementPendingJSCalls();
|
|
SystraceSection s("Instance::loadApplication", "sourceURL",
|
|
sourceURL);
|
|
nativeToJsBridge_->loadApplication(std::move(bundleRegistry), std::move(string),
|
|
std::move(sourceURL));
|
|
}
|
|
|
|
void Instance::loadApplicationSync(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::loadApplicationSync", "sourceURL",
|
|
sourceURL);
|
|
nativeToJsBridge_->loadApplicationSync(std::move(bundleRegistry), std::move(string),
|
|
std::move(sourceURL));
|
|
}
|
|
|
|
void Instance::setSourceURL(std::string sourceURL) {
|
|
callback_->incrementPendingJSCalls();
|
|
SystraceSection s("Instance::setSourceURL", "sourceURL", sourceURL);
|
|
|
|
nativeToJsBridge_->loadApplication(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) {
|
|
loadApplicationSync(nullptr, std::move(string), std::move(sourceURL));
|
|
} else {
|
|
loadApplication(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 = folly::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 = folly::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) {
|
|
loadApplicationSync(std::move(bundleRegistry), std::move(startupScript),
|
|
std::move(startupScriptSourceURL));
|
|
} else {
|
|
loadApplication(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);
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|