diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 9980ff8c1c67d7..d73c8f7e1eca2e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -65,6 +65,7 @@ import com.facebook.react.bridge.ProxyJavaScriptExecutor; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.ReactCxxErrorHandler; import com.facebook.react.bridge.ReactMarker; import com.facebook.react.bridge.ReactMarkerConstants; import com.facebook.react.bridge.ReactNoCrashSoftException; @@ -107,6 +108,7 @@ import com.facebook.soloader.SoLoader; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -291,6 +293,8 @@ public void invokeDefaultOnBackPressed() { if (mUseDeveloperSupport) { mDevSupportManager.startInspector(); } + + registerCxxErrorHandlerFunc(); } private ReactInstanceDevHelper createDevHelperInterface() { @@ -364,6 +368,22 @@ public List getPackages() { return new ArrayList<>(mPackages); } + public void handleCxxError(Exception e) { + mDevSupportManager.handleException(e); + } + + public void registerCxxErrorHandlerFunc() { + Class[] parameterTypes = new Class[1]; + parameterTypes[0] = Exception.class; + Method handleCxxErrorFunc = null; + try { + handleCxxErrorFunc = ReactInstanceManager.class.getMethod("handleCxxError", parameterTypes); + } catch (NoSuchMethodException e) { + FLog.e("ReactInstanceHolder", "Failed to set cxx error hanlder function", e); + } + ReactCxxErrorHandler.setHandleErrorFunc(this, handleCxxErrorFunc); + } + static void initializeSoLoaderIfNecessary(Context applicationContext) { // Call SoLoader.initialize here, this is required for apps that does not use exopackage and // does not use SoLoader for loading other native code except from the one used by React Native diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCxxErrorHandler.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCxxErrorHandler.java new file mode 100644 index 00000000000000..f5efbf1fadf930 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCxxErrorHandler.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +package com.facebook.react.bridge; + +import com.facebook.common.logging.FLog; +import com.facebook.proguard.annotations.DoNotStrip; +import java.lang.reflect.Method; + +@DoNotStrip +public class ReactCxxErrorHandler { + + private static Method mHandleErrorFunc; + private static Object mObject; + + @DoNotStrip + public static void setHandleErrorFunc(Object object, Method handleErrorFunc) { + mObject = object; + mHandleErrorFunc = handleErrorFunc; + } + + @DoNotStrip + // For use from within the C++ JReactCxxErrorHandler + private static void handleError(final String message) { + if (mHandleErrorFunc != null) { + try { + Object[] parameters = new Object[1]; + parameters[0] = new Exception(message); + mHandleErrorFunc.invoke(mObject, parameters); + } catch (Exception e) { + FLog.e("ReactCxxErrorHandler", "Failed to invole error hanlder function", e); + } + } + } +} diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index d9e5ac34b41124..6b1f09f2720f58 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -32,6 +32,7 @@ #include "CxxModuleWrapper.h" #include "JNativeRunnable.h" +#include "JReactCxxErrorHandler.h" #include "JReactSoftExceptionLogger.h" #include "JavaScriptExecutorHolder.h" #include "JniJSModulesUnbundle.h" @@ -155,6 +156,7 @@ void log(ReactNativeLogLevel level, const char *message) { break; case ReactNativeLogLevelError: LOG(ERROR) << message; + JReactCxxErrorHandler::handleError(message); break; case ReactNativeLogLevelFatal: LOG(FATAL) << message; diff --git a/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.cpp b/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.cpp new file mode 100644 index 00000000000000..5b3409eb1b47b3 --- /dev/null +++ b/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.cpp @@ -0,0 +1,18 @@ +/* + * 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 "JReactCxxErrorHandler.h" + +using namespace facebook::react; + +void JReactCxxErrorHandler::handleError(std::string message) { + static const auto handleError = + javaClassStatic()->getStaticMethod( + "handleError"); + + return handleError(javaClassStatic(), message); +} diff --git a/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.h b/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.h new file mode 100644 index 00000000000000..0ed379b9f139d3 --- /dev/null +++ b/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +class JReactCxxErrorHandler : public jni::JavaClass { + public: + static constexpr const char *kJavaDescriptor = + "Lcom/facebook/react/bridge/ReactCxxErrorHandler;"; + + static void handleError(std::string message); +}; + +} // namespace react +} // namespace facebook