Catch JS bundle load failure and prevent calls to JS after that
Summary: There are cases where JS bundle fails to be evaluated, which throws an exception already, but then there were pending calls into JS which would fail in a weird way. This prevents those calls (because it's mostly meaningless at that point). For now, those extra calls will still throw an exception, but with a specific message so that it doesn't confuse people. Reviewed By: yungsters Differential Revision: D8961622 fbshipit-source-id: 3f67fb63fdfa9fc5b249de0096e893b07956776a
This commit is contained in:
parent
c36e8b3307
commit
201ba8c69d
|
@ -8,6 +8,7 @@
|
||||||
#include <folly/json.h>
|
#include <folly/json.h>
|
||||||
#include <folly/Memory.h>
|
#include <folly/Memory.h>
|
||||||
#include <folly/MoveWrapper.h>
|
#include <folly/MoveWrapper.h>
|
||||||
|
#include <glog/logging.h>
|
||||||
|
|
||||||
#include "Instance.h"
|
#include "Instance.h"
|
||||||
#include "JSBigString.h"
|
#include "JSBigString.h"
|
||||||
|
@ -99,7 +100,8 @@ void NativeToJsBridge::loadApplication(
|
||||||
std::unique_ptr<const JSBigString> startupScript,
|
std::unique_ptr<const JSBigString> startupScript,
|
||||||
std::string startupScriptSourceURL) {
|
std::string startupScriptSourceURL) {
|
||||||
runOnExecutorQueue(
|
runOnExecutorQueue(
|
||||||
[bundleRegistryWrap=folly::makeMoveWrapper(std::move(bundleRegistry)),
|
[this,
|
||||||
|
bundleRegistryWrap=folly::makeMoveWrapper(std::move(bundleRegistry)),
|
||||||
startupScript=folly::makeMoveWrapper(std::move(startupScript)),
|
startupScript=folly::makeMoveWrapper(std::move(startupScript)),
|
||||||
startupScriptSourceURL=std::move(startupScriptSourceURL)]
|
startupScriptSourceURL=std::move(startupScriptSourceURL)]
|
||||||
(JSExecutor* executor) mutable {
|
(JSExecutor* executor) mutable {
|
||||||
|
@ -107,8 +109,13 @@ void NativeToJsBridge::loadApplication(
|
||||||
if (bundleRegistry) {
|
if (bundleRegistry) {
|
||||||
executor->setBundleRegistry(std::move(bundleRegistry));
|
executor->setBundleRegistry(std::move(bundleRegistry));
|
||||||
}
|
}
|
||||||
executor->loadApplicationScript(std::move(*startupScript),
|
try {
|
||||||
std::move(startupScriptSourceURL));
|
executor->loadApplicationScript(std::move(*startupScript),
|
||||||
|
std::move(startupScriptSourceURL));
|
||||||
|
} catch (...) {
|
||||||
|
m_applicationScriptHasFailure = true;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,8 +126,13 @@ void NativeToJsBridge::loadApplicationSync(
|
||||||
if (bundleRegistry) {
|
if (bundleRegistry) {
|
||||||
m_executor->setBundleRegistry(std::move(bundleRegistry));
|
m_executor->setBundleRegistry(std::move(bundleRegistry));
|
||||||
}
|
}
|
||||||
m_executor->loadApplicationScript(std::move(startupScript),
|
try {
|
||||||
std::move(startupScriptSourceURL));
|
m_executor->loadApplicationScript(std::move(startupScript),
|
||||||
|
std::move(startupScriptSourceURL));
|
||||||
|
} catch (...) {
|
||||||
|
m_applicationScriptHasFailure = true;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeToJsBridge::callFunction(
|
void NativeToJsBridge::callFunction(
|
||||||
|
@ -136,8 +148,13 @@ void NativeToJsBridge::callFunction(
|
||||||
systraceCookie);
|
systraceCookie);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
runOnExecutorQueue([module = std::move(module), method = std::move(method), arguments = std::move(arguments), systraceCookie]
|
runOnExecutorQueue([this, module = std::move(module), method = std::move(method), arguments = std::move(arguments), systraceCookie]
|
||||||
(JSExecutor* executor) {
|
(JSExecutor* executor) {
|
||||||
|
if (m_applicationScriptHasFailure) {
|
||||||
|
LOG(ERROR) << "Attempting to call JS function on a bad application bundle: " << module.c_str() << "." << method.c_str() << "()";
|
||||||
|
throw std::runtime_error("Attempting to call JS function on a bad application bundle: " + module + "." + method + "()");
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WITH_FBSYSTRACE
|
#ifdef WITH_FBSYSTRACE
|
||||||
FbSystraceAsyncFlow::end(
|
FbSystraceAsyncFlow::end(
|
||||||
TRACE_TAG_REACT_CXX_BRIDGE,
|
TRACE_TAG_REACT_CXX_BRIDGE,
|
||||||
|
@ -162,8 +179,12 @@ void NativeToJsBridge::invokeCallback(double callbackId, folly::dynamic&& argume
|
||||||
systraceCookie);
|
systraceCookie);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
runOnExecutorQueue([callbackId, arguments = std::move(arguments), systraceCookie]
|
runOnExecutorQueue([this, callbackId, arguments = std::move(arguments), systraceCookie]
|
||||||
(JSExecutor* executor) {
|
(JSExecutor* executor) {
|
||||||
|
if (m_applicationScriptHasFailure) {
|
||||||
|
LOG(ERROR) << "Attempting to call JS callback on a bad application bundle: " << callbackId;
|
||||||
|
throw std::runtime_error("Attempting to invoke JS callback on a bad application bundle.");
|
||||||
|
}
|
||||||
#ifdef WITH_FBSYSTRACE
|
#ifdef WITH_FBSYSTRACE
|
||||||
FbSystraceAsyncFlow::end(
|
FbSystraceAsyncFlow::end(
|
||||||
TRACE_TAG_REACT_CXX_BRIDGE,
|
TRACE_TAG_REACT_CXX_BRIDGE,
|
||||||
|
|
|
@ -94,6 +94,11 @@ private:
|
||||||
std::unique_ptr<JSExecutor> m_executor;
|
std::unique_ptr<JSExecutor> m_executor;
|
||||||
std::shared_ptr<MessageQueueThread> m_executorMessageQueueThread;
|
std::shared_ptr<MessageQueueThread> m_executorMessageQueueThread;
|
||||||
|
|
||||||
|
// Keep track of whether the JS bundle containing the application logic causes
|
||||||
|
// exception when evaluated initially. If so, more calls to JS will very
|
||||||
|
// likely fail as well, so this flag can help prevent them.
|
||||||
|
bool m_applicationScriptHasFailure = false;
|
||||||
|
|
||||||
#ifdef WITH_FBSYSTRACE
|
#ifdef WITH_FBSYSTRACE
|
||||||
std::atomic_uint_least32_t m_systraceCookie = ATOMIC_VAR_INIT();
|
std::atomic_uint_least32_t m_systraceCookie = ATOMIC_VAR_INIT();
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue