iOS C++: Add ICxxExceptionManager to access RCTExceptionsManager native module

Summary: It is sometimes useful to report soft/fatal errors from C++ (native) to the same RCTExceptionsManager that is already handling JS exceptions. `ICxxExceptionManager` is an approach to provide such access, which impl provided for ObjC++.

Reviewed By: shergin

Differential Revision: D7224944

fbshipit-source-id: 8c607226b67851d46f4c787f5b6e6c8cb6a1afea
This commit is contained in:
Kevin Gozali 2018-03-18 23:49:51 -07:00 коммит произвёл Facebook Github Bot
Родитель 263d04d756
Коммит f42b5892a1
7 изменённых файлов: 168 добавлений и 29 удалений

Просмотреть файл

@ -120,6 +120,13 @@ RCT_EXTERN void RCTPerformBlockWithLogFunction(void (^block)(void), RCTLogFuncti
*/
RCT_EXTERN void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix);
/**
* This method computes the current call stack, useful for error reporting.
*/
RCT_EXTERN NSArray<NSDictionary *> *RCTGetCallStack(const char *fileName, int lineNumber);
#define RCT_CALLSTACK RCTGetCallStack(__FILE__, __LINE__)
/**
* Private logging function - ignore this.
*/

Просмотреть файл

@ -197,26 +197,8 @@ static NSRegularExpression *nativeStackFrameRegex()
return _regex;
}
void _RCTLogNativeInternal(RCTLogLevel level, const char *fileName, int lineNumber, NSString *format, ...)
NSArray<NSDictionary *>* RCTGetCallStack(const char *fileName, int lineNumber)
{
RCTLogFunction logFunction = RCTGetLocalLogFunction();
BOOL log = RCT_DEBUG || (logFunction != nil);
if (log && level >= RCTGetLogThreshold()) {
// Get message
va_list args;
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
// Call log function
if (logFunction) {
logFunction(level, RCTLogSourceNative, fileName ? @(fileName) : nil, lineNumber > 0 ? @(lineNumber) : nil, message);
}
#if RCT_DEBUG
// Log to red box in debug mode.
if (RCTSharedApplication() && level >= RCTLOG_REDBOX_LEVEL) {
NSArray<NSString *> *stackSymbols = [NSThread callStackSymbols];
NSMutableArray<NSDictionary *> *stack =
[NSMutableArray arrayWithCapacity:(stackSymbols.count - 1)];
@ -247,6 +229,31 @@ void _RCTLogNativeInternal(RCTLogLevel level, const char *fileName, int lineNumb
}
}];
return [stack copy];
}
void _RCTLogNativeInternal(RCTLogLevel level, const char *fileName, int lineNumber, NSString *format, ...)
{
RCTLogFunction logFunction = RCTGetLocalLogFunction();
BOOL log = RCT_DEBUG || (logFunction != nil);
if (log && level >= RCTGetLogThreshold()) {
// Get message
va_list args;
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
// Call log function
if (logFunction) {
logFunction(level, RCTLogSourceNative, fileName ? @(fileName) : nil, lineNumber > 0 ? @(lineNumber) : nil, message);
}
#if RCT_DEBUG
// Log to red box in debug mode.
if (RCTSharedApplication() && level >= RCTLOG_REDBOX_LEVEL) {
NSArray<NSDictionary *> *stack = RCT_CALLSTACK;
dispatch_async(dispatch_get_main_queue(), ^{
// red box is thread safe, but by deferring to main queue we avoid a startup
// race condition that causes the module to be accessed before it has loaded

Просмотреть файл

@ -0,0 +1,27 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* 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 <cxxreact/ExceptionManager.h>
namespace facebook {
namespace react {
/**
* Connector class (from C++ to ObjC++) to allow FabricUIManager to invoke native UI operations/updates.
* UIKit-related impl doesn't live here, but this class gets passed to the FabricUIManager C++ impl directly.
*/
class RCTCxxExceptionManager : public ExceptionManager {
public:
virtual void handleSoftException(const std::exception& e) const override;
virtual void handleFatalException(const std::exception& e) const override;
};
} // namespace react
} // namespace facebook

Просмотреть файл

@ -0,0 +1,31 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTCxxExceptionManager.h"
#import <Foundation/Foundation.h>
#import <React/RCTBridge.h>
#import <React/RCTBridge+Private.h>
#import <React/RCTExceptionsManager.h>
#import <React/RCTLog.h>
namespace facebook {
namespace react {
void RCTCxxExceptionManager::handleSoftException(const std::exception& e) const {
RCTExceptionsManager *manager = [[RCTBridge currentBridge] moduleForClass:[RCTExceptionsManager class]];
[manager reportSoftException:[NSString stringWithUTF8String:e.what()] stack:RCT_CALLSTACK exceptionId:@0];
}
void RCTCxxExceptionManager::handleFatalException(const std::exception& e) const {
RCTExceptionsManager *manager = [[RCTBridge currentBridge] moduleForClass:[RCTExceptionsManager class]];
[manager reportFatalException:[NSString stringWithUTF8String:e.what()] stack:RCT_CALLSTACK exceptionId:@0];
}
} // namespace react
} // namespace facebook

Просмотреть файл

@ -23,6 +23,9 @@
- (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate;
- (void)reportSoftException:(NSString *)message stack:(NSArray<NSDictionary *> *)stack exceptionId:(nonnull NSNumber *)exceptionId;
- (void)reportFatalException:(NSString *)message stack:(NSArray<NSDictionary *> *)stack exceptionId:(nonnull NSNumber *)exceptionId;
@property (nonatomic, weak) id<RCTExceptionsManagerDelegate> delegate;
@property (nonatomic, assign) NSUInteger maxReloadAttempts;

Просмотреть файл

@ -0,0 +1,40 @@
load("//configurations/buck/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load("//ReactNative:DEFS.bzl", "IS_OSS_BUILD", "react_native_xplat_target", "rn_xplat_cxx_library", "APPLE_INSPECTOR_FLAGS")
APPLE_COMPILER_FLAGS = []
if not IS_OSS_BUILD:
load("@xplat//configurations/buck/apple:flag_defs.bzl", "get_static_library_ios_flags", "flags")
APPLE_COMPILER_FLAGS = flags.get_flag_value(get_static_library_ios_flags(), 'compiler_flags')
rn_xplat_cxx_library(
name = "exceptions",
srcs = glob(["*.cpp"]),
header_namespace = "",
exported_headers = subdir_glob(
[
("", "*.h"),
],
prefix = "cxxreact",
),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + APPLE_INSPECTOR_FLAGS,
force_static = True,
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
visibility = [
"PUBLIC",
],
deps = [
"xplat//fbsystrace:fbsystrace",
"xplat//third-party/glog:glog",
],
)

Просмотреть файл

@ -0,0 +1,24 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <exception>
namespace facebook {
namespace react {
/**
* An abstract class for C++-based exception handling that differentiates
* soft exceptions from fatal exceptions.
*/
class ExceptionManager {
public:
virtual void handleSoftException(const std::exception &e) const = 0;
virtual void handleFatalException(const std::exception &e) const = 0;
};
} // namespace react
} // namespace facebook