Display JS exceptions and stacks in a red box
Reviewed By: astreet Differential Revision: D3510875 fbshipit-source-id: a7042434b68cb849f5b0c4ef782befff6a27ef5c
This commit is contained in:
parent
c4fc504094
commit
a7d032b707
|
@ -79,6 +79,7 @@ import com.facebook.react.modules.debug.DeveloperSettings;
|
|||
public class DevSupportManagerImpl implements DevSupportManager {
|
||||
|
||||
private static final int JAVA_ERROR_COOKIE = -1;
|
||||
private static final int JSEXCEPTION_ERROR_COOKIE = -1;
|
||||
private static final String JS_BUNDLE_FILE_NAME = "ReactNativeDevBundle.js";
|
||||
private static enum ErrorType {
|
||||
JS,
|
||||
|
@ -194,7 +195,13 @@ public class DevSupportManagerImpl implements DevSupportManager {
|
|||
public void handleException(Exception e) {
|
||||
if (mIsDevSupportEnabled) {
|
||||
FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
|
||||
showNewJavaError(e.getMessage(), e);
|
||||
if (e instanceof JSException) {
|
||||
// TODO #11638796: convert the stack into something useful
|
||||
showNewError(e.getMessage() + "\n\n" + ((JSException) e).getStack(), new StackFrame[] {},
|
||||
JSEXCEPTION_ERROR_COOKIE, ErrorType.JS);
|
||||
} else {
|
||||
showNewJavaError(e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
mDefaultNativeModuleCallExceptionHandler.handleException(e);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
|
||||
/**
|
||||
* This represents an error evaluating JavaScript. It includes the usual
|
||||
* message, and the raw JS stack where the error occurred (which may be empty).
|
||||
*/
|
||||
|
||||
@DoNotStrip
|
||||
public class JSException extends Exception {
|
||||
private final String mStack;
|
||||
|
||||
@DoNotStrip
|
||||
public JSException(String message, String stack, Throwable cause) {
|
||||
super(message, cause);
|
||||
mStack = stack;
|
||||
}
|
||||
|
||||
public JSException(String message, String stack) {
|
||||
super(message);
|
||||
mStack = stack;
|
||||
}
|
||||
|
||||
public String getStack() {
|
||||
return mStack;
|
||||
}
|
||||
}
|
|
@ -9,11 +9,37 @@
|
|||
#include <folly/Memory.h>
|
||||
#include <fb/fbjni.h>
|
||||
|
||||
#include <cxxreact/JSCHelpers.h>
|
||||
|
||||
#include "JNativeRunnable.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
namespace {
|
||||
|
||||
struct JavaJSException : jni::JavaClass<JavaJSException, JThrowable> {
|
||||
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/devsupport/JSException;";
|
||||
|
||||
static local_ref<JavaJSException> create(const char* message, const char* stack,
|
||||
const std::exception& ex) {
|
||||
local_ref<jthrowable> cause = jni::JCppException::create(ex);
|
||||
return newInstance(make_jstring(message), make_jstring(stack), cause.get());
|
||||
}
|
||||
};
|
||||
|
||||
std::function<void()> wrapRunnable(std::function<void()>&& runnable) {
|
||||
return [runnable=std::move(runnable)] {
|
||||
try {
|
||||
runnable();
|
||||
} catch (const JSException& ex) {
|
||||
throwNewJavaException(JavaJSException::create(ex.what(), ex.getStack().c_str(), ex).get());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
JMessageQueueThread::JMessageQueueThread(alias_ref<JavaMessageQueueThread::javaobject> jobj) :
|
||||
m_jobj(make_global(jobj)) {
|
||||
}
|
||||
|
@ -21,7 +47,7 @@ JMessageQueueThread::JMessageQueueThread(alias_ref<JavaMessageQueueThread::javao
|
|||
void JMessageQueueThread::runOnQueue(std::function<void()>&& runnable) {
|
||||
static auto method = JavaMessageQueueThread::javaClassStatic()->
|
||||
getMethod<void(Runnable::javaobject)>("runOnQueue");
|
||||
method(m_jobj, JNativeRunnable::newObjectCxxArgs(runnable).get());
|
||||
method(m_jobj, JNativeRunnable::newObjectCxxArgs(wrapRunnable(std::move(runnable))).get());
|
||||
}
|
||||
|
||||
void JMessageQueueThread::runOnQueueSync(std::function<void()>&& runnable) {
|
||||
|
@ -29,7 +55,7 @@ void JMessageQueueThread::runOnQueueSync(std::function<void()>&& runnable) {
|
|||
getMethod<jboolean()>("isOnThread");
|
||||
|
||||
if (jIsOnThread(m_jobj)) {
|
||||
runnable();
|
||||
wrapRunnable(std::move(runnable))();
|
||||
} else {
|
||||
std::mutex signalMutex;
|
||||
std::condition_variable signalCv;
|
||||
|
|
Loading…
Reference in New Issue