fix indexed RAM bundle (#24967)
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
This commit is contained in:
Родитель
b45d3b8697
Коммит
d8fa1206c3
|
@ -199,6 +199,8 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
|
|||
sourceURL,
|
||||
loadSynchronously);
|
||||
return;
|
||||
} else if (Instance::isIndexedRAMBundle(&script)) {
|
||||
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
|
||||
} else {
|
||||
instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously);
|
||||
}
|
||||
|
|
|
@ -108,6 +108,24 @@ bool Instance::isIndexedRAMBundle(const char *sourcePath) {
|
|||
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) {
|
||||
|
|
|
@ -47,6 +47,8 @@ public:
|
|||
void loadScriptFromString(std::unique_ptr<const JSBigString> string,
|
||||
std::string sourceURL, bool loadSynchronously);
|
||||
static bool isIndexedRAMBundle(const char *sourcePath);
|
||||
static bool isIndexedRAMBundle(std::unique_ptr<const JSBigString>* string);
|
||||
void loadRAMBundleFromString(std::unique_ptr<const JSBigString> script, const std::string& sourceURL);
|
||||
void loadRAMBundleFromFile(const std::string& sourcePath,
|
||||
const std::string& sourceURL,
|
||||
bool loadSynchronously);
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#include "JSIndexedRAMBundle.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <folly/Memory.h>
|
||||
|
||||
namespace facebook {
|
||||
|
@ -18,14 +19,30 @@ std::function<std::unique_ptr<JSModulesUnbundle>(std::string)> JSIndexedRAMBundl
|
|||
};
|
||||
}
|
||||
|
||||
JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) :
|
||||
m_bundle (sourcePath, std::ios_base::in) {
|
||||
JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) {
|
||||
m_bundle = std::make_unique<std::ifstream>(sourcePath, std::ifstream::binary);
|
||||
if (!m_bundle) {
|
||||
throw std::ios_base::failure(
|
||||
folly::to<std::string>("Bundle ", sourcePath,
|
||||
"cannot be opened: ", m_bundle.rdstate()));
|
||||
"cannot be opened: ", m_bundle->rdstate()));
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
JSIndexedRAMBundle::JSIndexedRAMBundle(std::unique_ptr<const JSBigString> script) {
|
||||
// tmpStream is needed because m_bundle is std::istream type
|
||||
// which has no member 'write'
|
||||
std::unique_ptr<std::stringstream> tmpStream = std::make_unique<std::stringstream>();
|
||||
tmpStream->write(script->c_str(), script->size());
|
||||
m_bundle = std::move(tmpStream);
|
||||
if (!m_bundle) {
|
||||
throw std::ios_base::failure(
|
||||
folly::to<std::string>("Bundle from string cannot be opened: ", m_bundle->rdstate()));
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
void JSIndexedRAMBundle::init() {
|
||||
// read in magic header, number of entries, and length of the startup section
|
||||
uint32_t header[3];
|
||||
static_assert(
|
||||
|
@ -78,12 +95,12 @@ std::string JSIndexedRAMBundle::getModuleCode(const uint32_t id) const {
|
|||
}
|
||||
|
||||
void JSIndexedRAMBundle::readBundle(char *buffer, const std::streamsize bytes) const {
|
||||
if (!m_bundle.read(buffer, bytes)) {
|
||||
if (m_bundle.rdstate() & std::ios::eofbit) {
|
||||
if (!m_bundle->read(buffer, bytes)) {
|
||||
if (m_bundle->rdstate() & std::ios::eofbit) {
|
||||
throw std::ios_base::failure("Unexpected end of RAM Bundle file");
|
||||
}
|
||||
throw std::ios_base::failure(
|
||||
folly::to<std::string>("Error reading RAM Bundle: ", m_bundle.rdstate()));
|
||||
folly::to<std::string>("Error reading RAM Bundle: ", m_bundle->rdstate()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,9 +109,9 @@ void JSIndexedRAMBundle::readBundle(
|
|||
const std::streamsize bytes,
|
||||
const std::ifstream::pos_type position) const {
|
||||
|
||||
if (!m_bundle.seekg(position)) {
|
||||
if (!m_bundle->seekg(position)) {
|
||||
throw std::ios_base::failure(
|
||||
folly::to<std::string>("Error reading RAM Bundle: ", m_bundle.rdstate()));
|
||||
folly::to<std::string>("Error reading RAM Bundle: ", m_bundle->rdstate()));
|
||||
}
|
||||
readBundle(buffer, bytes);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
|
||||
#include <cxxreact/JSBigString.h>
|
||||
|
@ -24,6 +24,7 @@ public:
|
|||
|
||||
// Throws std::runtime_error on failure.
|
||||
JSIndexedRAMBundle(const char *sourceURL);
|
||||
JSIndexedRAMBundle(std::unique_ptr<const JSBigString> script);
|
||||
|
||||
// Throws std::runtime_error on failure.
|
||||
std::unique_ptr<const JSBigString> getStartupCode();
|
||||
|
@ -51,14 +52,15 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
void init();
|
||||
std::string getModuleCode(const uint32_t id) const;
|
||||
void readBundle(char *buffer, const std::streamsize bytes) const;
|
||||
void readBundle(
|
||||
char *buffer, const
|
||||
std::streamsize bytes,
|
||||
const std::ifstream::pos_type position) const;
|
||||
const std::istream::pos_type position) const;
|
||||
|
||||
mutable std::ifstream m_bundle;
|
||||
mutable std::unique_ptr<std::istream> m_bundle;
|
||||
ModuleTable m_table;
|
||||
size_t m_baseOffset;
|
||||
std::unique_ptr<JSBigBufferString> m_startupCode;
|
||||
|
|
Загрузка…
Ссылка в новой задаче