@arms/rum-reactnative 0.1.1 → 0.1.3-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +399 -15
- package/RumSdkReactnative.podspec +28 -0
- package/android/build.gradle +83 -0
- package/android/gradle.properties +6 -0
- package/android/src/main/AndroidManifest.xml +13 -0
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativeModule.kt +512 -0
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativePackage.kt +33 -0
- package/android/src/main/java/com/rumsdkreactnative/crash/CrashContextManager.kt +157 -0
- package/android/src/main/java/com/rumsdkreactnative/crash/CrashHandler.kt +444 -0
- package/android/src/main/java/com/rumsdkreactnative/crash/CrashInitProvider.kt +50 -0
- package/android/src/main/java/com/rumsdkreactnative/crash/NdkCrashHandler.kt +66 -0
- package/android/src/main/jni/CMakeLists.txt +21 -0
- package/android/src/main/jni/rum_backtrace.c +144 -0
- package/android/src/main/jni/rum_crash_handler.c +200 -0
- package/android/src/main/jni/rum_crash_writer.c +442 -0
- package/android/src/main/jni/rum_module_info.c +316 -0
- package/android/src/main/jni/rum_module_info.h +54 -0
- package/android/src/main/jni/rum_test_crash.cpp +55 -0
- package/app.plugin.js +11 -0
- package/docs/ReactNative SDK/351/205/215/347/275/256/345/217/202/350/200/203.md" +671 -0
- package/docs/SDK /347/211/210/346/234/254/350/257/264/346/230/216.md" +12 -0
- package/docs//346/216/245/345/205/245ReactNative/345/272/224/347/224/250.md +238 -0
- package/ios/PrivacyInfo.xcprivacy +93 -0
- package/ios/RumCrashReporter.h +38 -0
- package/ios/RumCrashReporter.mm +861 -0
- package/ios/RumSdkReactnative.h +5 -0
- package/ios/RumSdkReactnative.mm +291 -0
- package/ios/fishhook/fishhook.c +264 -0
- package/ios/fishhook/fishhook.h +76 -0
- package/lib/commonjs/NativeRumSdkReactnative.js +50 -0
- package/lib/commonjs/collector/action/index.js +108 -0
- package/lib/commonjs/collector/exception/crash.js +148 -0
- package/lib/commonjs/collector/exception/index.js +238 -0
- package/lib/commonjs/collector/index.js +42 -0
- package/lib/commonjs/collector/resource/api.js +286 -0
- package/lib/commonjs/collector/view/perf.js +79 -0
- package/lib/commonjs/collector/view/pv.js +88 -0
- package/lib/commonjs/expoConfigPlugin.js +37 -0
- package/lib/commonjs/index.js +29 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/plugin.js +47 -0
- package/lib/commonjs/processor/default-processor.js +27 -0
- package/lib/commonjs/processor/session-processor.js +47 -0
- package/lib/commonjs/reporter/index.js +148 -0
- package/lib/commonjs/reporter/monitor-reporter.js +43 -0
- package/lib/commonjs/shell.js +91 -0
- package/lib/commonjs/types/client.js +6 -0
- package/lib/commonjs/types/crash.js +37 -0
- package/lib/commonjs/types/index.js +2 -0
- package/lib/commonjs/utils/action.js +305 -0
- package/lib/commonjs/utils/api.js +83 -0
- package/lib/commonjs/utils/base.js +95 -0
- package/lib/commonjs/utils/crash.js +146 -0
- package/lib/commonjs/utils/platform.js +162 -0
- package/lib/commonjs/utils/session.js +158 -0
- package/lib/commonjs/utils/url.js +59 -0
- package/lib/commonjs/utils/view.js +93 -0
- package/lib/module/NativeRumSdkReactnative.js +47 -0
- package/lib/module/collector/action/index.js +45 -10
- package/lib/module/collector/exception/crash.js +143 -0
- package/lib/module/collector/exception/index.js +144 -46
- package/lib/module/collector/index.js +8 -0
- package/lib/module/collector/resource/api.js +6 -6
- package/lib/module/collector/view/pv.js +13 -2
- package/lib/module/expoConfigPlugin.js +33 -0
- package/lib/module/index.js +1 -0
- package/lib/module/plugin.js +4 -1
- package/lib/module/processor/session-processor.js +22 -0
- package/lib/module/reporter/index.js +102 -16
- package/lib/module/reporter/monitor-reporter.js +38 -0
- package/lib/module/shell.js +32 -7
- package/lib/module/types/crash.js +33 -0
- package/lib/module/utils/action.js +299 -0
- package/lib/module/utils/api.js +10 -10
- package/lib/module/utils/base.js +9 -9
- package/lib/module/utils/crash.js +141 -0
- package/lib/module/utils/platform.js +127 -72
- package/lib/module/utils/session.js +23 -4
- package/lib/module/utils/view.js +2 -1
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/src/NativeRumSdkReactnative.d.ts +49 -0
- package/lib/typescript/{src → commonjs/src}/collector/action/index.d.ts +7 -1
- package/lib/typescript/commonjs/src/collector/exception/crash.d.ts +28 -0
- package/lib/typescript/{src → commonjs/src}/collector/exception/index.d.ts +7 -0
- package/lib/typescript/commonjs/src/collector/index.d.ts +6 -0
- package/lib/typescript/{src → commonjs/src}/collector/view/pv.d.ts +2 -2
- package/lib/typescript/commonjs/src/expoConfigPlugin.d.ts +28 -0
- package/lib/typescript/commonjs/src/index.d.ts +6 -0
- package/lib/typescript/{src → commonjs/src}/processor/session-processor.d.ts +2 -0
- package/lib/typescript/{src → commonjs/src}/reporter/index.d.ts +3 -1
- package/lib/typescript/commonjs/src/reporter/monitor-reporter.d.ts +8 -0
- package/lib/typescript/commonjs/src/shell.d.ts +57 -0
- package/lib/typescript/{src → commonjs/src}/types/client.d.ts +2 -2
- package/lib/typescript/commonjs/src/types/crash.d.ts +95 -0
- package/lib/typescript/commonjs/src/utils/action.d.ts +63 -0
- package/lib/typescript/{src → commonjs/src}/utils/api.d.ts +1 -1
- package/lib/typescript/commonjs/src/utils/crash.d.ts +12 -0
- package/lib/typescript/commonjs/src/utils/platform.d.ts +22 -0
- package/lib/typescript/{src → commonjs/src}/utils/session.d.ts +4 -0
- package/lib/typescript/module/src/NativeRumSdkReactnative.d.ts +49 -0
- package/lib/typescript/module/src/collector/action/index.d.ts +21 -0
- package/lib/typescript/module/src/collector/exception/crash.d.ts +28 -0
- package/lib/typescript/module/src/collector/exception/index.d.ts +32 -0
- package/lib/typescript/module/src/collector/index.d.ts +6 -0
- package/lib/typescript/module/src/collector/resource/api.d.ts +21 -0
- package/lib/typescript/module/src/collector/view/perf.d.ts +1 -0
- package/lib/typescript/module/src/collector/view/pv.d.ts +16 -0
- package/lib/typescript/module/src/expoConfigPlugin.d.ts +28 -0
- package/lib/typescript/module/src/index.d.ts +6 -0
- package/lib/typescript/module/src/plugin.d.ts +3 -0
- package/lib/typescript/module/src/processor/default-processor.d.ts +6 -0
- package/lib/typescript/module/src/processor/session-processor.d.ts +11 -0
- package/lib/typescript/module/src/reporter/index.d.ts +18 -0
- package/lib/typescript/module/src/reporter/monitor-reporter.d.ts +8 -0
- package/lib/typescript/module/src/shell.d.ts +57 -0
- package/lib/typescript/module/src/types/client.d.ts +27 -0
- package/lib/typescript/module/src/types/crash.d.ts +95 -0
- package/lib/typescript/module/src/types/index.d.ts +118 -0
- package/lib/typescript/module/src/utils/action.d.ts +63 -0
- package/lib/typescript/module/src/utils/api.d.ts +59 -0
- package/lib/typescript/module/src/utils/base.d.ts +8 -0
- package/lib/typescript/module/src/utils/crash.d.ts +12 -0
- package/lib/typescript/module/src/utils/platform.d.ts +22 -0
- package/lib/typescript/module/src/utils/session.d.ts +41 -0
- package/lib/typescript/module/src/utils/url.d.ts +17 -0
- package/lib/typescript/module/src/utils/view.d.ts +13 -0
- package/package.json +61 -26
- package/LICENSE +0 -20
- package/lib/module/collector/action/index.js.map +0 -1
- package/lib/module/collector/exception/index.js.map +0 -1
- package/lib/module/collector/resource/api.js.map +0 -1
- package/lib/module/collector/view/perf.js.map +0 -1
- package/lib/module/collector/view/pv.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/plugin.js.map +0 -1
- package/lib/module/processor/default-processor.js.map +0 -1
- package/lib/module/processor/session-processor.js.map +0 -1
- package/lib/module/reporter/index.js.map +0 -1
- package/lib/module/shell.js.map +0 -1
- package/lib/module/types/client.js.map +0 -1
- package/lib/module/types/index.js.map +0 -1
- package/lib/module/utils/api.js.map +0 -1
- package/lib/module/utils/base.js.map +0 -1
- package/lib/module/utils/platform.js.map +0 -1
- package/lib/module/utils/session.js.map +0 -1
- package/lib/module/utils/url.js.map +0 -1
- package/lib/module/utils/view.js.map +0 -1
- package/lib/typescript/src/collector/action/index.d.ts.map +0 -1
- package/lib/typescript/src/collector/exception/index.d.ts.map +0 -1
- package/lib/typescript/src/collector/resource/api.d.ts.map +0 -1
- package/lib/typescript/src/collector/view/perf.d.ts.map +0 -1
- package/lib/typescript/src/collector/view/pv.d.ts.map +0 -1
- package/lib/typescript/src/index.d.ts +0 -4
- package/lib/typescript/src/index.d.ts.map +0 -1
- package/lib/typescript/src/plugin.d.ts.map +0 -1
- package/lib/typescript/src/processor/default-processor.d.ts.map +0 -1
- package/lib/typescript/src/processor/session-processor.d.ts.map +0 -1
- package/lib/typescript/src/reporter/index.d.ts.map +0 -1
- package/lib/typescript/src/shell.d.ts +0 -26
- package/lib/typescript/src/shell.d.ts.map +0 -1
- package/lib/typescript/src/types/client.d.ts.map +0 -1
- package/lib/typescript/src/types/index.d.ts.map +0 -1
- package/lib/typescript/src/utils/api.d.ts.map +0 -1
- package/lib/typescript/src/utils/base.d.ts.map +0 -1
- package/lib/typescript/src/utils/platform.d.ts +0 -15
- package/lib/typescript/src/utils/platform.d.ts.map +0 -1
- package/lib/typescript/src/utils/session.d.ts.map +0 -1
- package/lib/typescript/src/utils/url.d.ts.map +0 -1
- package/lib/typescript/src/utils/view.d.ts.map +0 -1
- /package/lib/typescript/{src → commonjs/src}/collector/resource/api.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/collector/view/perf.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/plugin.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/processor/default-processor.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/types/index.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/utils/base.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/utils/url.d.ts +0 -0
- /package/lib/typescript/{src → commonjs/src}/utils/view.d.ts +0 -0
- /package/lib/typescript/{package.json → module/package.json} +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#include <unwind.h>
|
|
2
|
+
#include <stdint.h>
|
|
3
|
+
#include <sys/ucontext.h>
|
|
4
|
+
|
|
5
|
+
typedef struct {
|
|
6
|
+
void **frames;
|
|
7
|
+
int max_frames;
|
|
8
|
+
int count;
|
|
9
|
+
int skip; // skip top frames (e.g. signal handler itself)
|
|
10
|
+
} backtrace_state_t;
|
|
11
|
+
|
|
12
|
+
static _Unwind_Reason_Code unwind_callback(struct _Unwind_Context *context, void *arg) {
|
|
13
|
+
backtrace_state_t *state = (backtrace_state_t *)arg;
|
|
14
|
+
|
|
15
|
+
uintptr_t pc = _Unwind_GetIP(context);
|
|
16
|
+
if (pc == 0) {
|
|
17
|
+
return _URC_END_OF_STACK;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (state->skip > 0) {
|
|
21
|
+
state->skip--;
|
|
22
|
+
} else if (state->count < state->max_frames) {
|
|
23
|
+
state->frames[state->count++] = (void *)pc;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (state->count >= state->max_frames) {
|
|
27
|
+
return _URC_END_OF_STACK;
|
|
28
|
+
}
|
|
29
|
+
return _URC_NO_REASON;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#if defined(__arm__)
|
|
33
|
+
/*
|
|
34
|
+
* ARM32 frame pointer 遍历(async-signal-safe fallback)。
|
|
35
|
+
* _Unwind_Backtrace 在 ARM32 + 旧版 Android 上可能死锁,
|
|
36
|
+
* 使用 frame pointer 遍历作为更安全的替代方案。
|
|
37
|
+
* 要求编译选项 -fno-omit-frame-pointer(已在 CMakeLists 中启用)。
|
|
38
|
+
*/
|
|
39
|
+
static int rum_fp_backtrace(void **buffer, int max_frames, ucontext_t *uc) {
|
|
40
|
+
if (buffer == NULL || max_frames <= 0 || uc == NULL) {
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
int count = 0;
|
|
45
|
+
// 从崩溃 PC 开始
|
|
46
|
+
buffer[count++] = (void *)(uintptr_t)uc->uc_mcontext.arm_pc;
|
|
47
|
+
|
|
48
|
+
// 使用 fp (frame pointer) 遍历调用栈
|
|
49
|
+
void *fp = (void *)(uintptr_t)uc->uc_mcontext.arm_fp;
|
|
50
|
+
while (count < max_frames && fp != NULL) {
|
|
51
|
+
// ARM32 栈帧布局:[fp_prev, lr, ...]
|
|
52
|
+
void **frame = (void **)fp;
|
|
53
|
+
void *lr = frame[1]; // link register (return address)
|
|
54
|
+
void *next_fp = frame[0]; // previous frame pointer
|
|
55
|
+
|
|
56
|
+
if (lr == NULL) break;
|
|
57
|
+
buffer[count++] = lr;
|
|
58
|
+
|
|
59
|
+
// 防止循环(fp 未变化)
|
|
60
|
+
if (next_fp == fp || next_fp == NULL) break;
|
|
61
|
+
fp = next_fp;
|
|
62
|
+
}
|
|
63
|
+
return count;
|
|
64
|
+
}
|
|
65
|
+
#endif
|
|
66
|
+
|
|
67
|
+
#if defined(__aarch64__)
|
|
68
|
+
/*
|
|
69
|
+
* ARM64 frame pointer 遍历(async-signal-safe)。
|
|
70
|
+
* _Unwind_Backtrace 在信号上下文中可能持有加载器/解锁器锁,
|
|
71
|
+
* 存在死锁风险;arm64 有稳定的 x29 帧指针链,改用 fp 遍历更安全。
|
|
72
|
+
* 要求 -fno-omit-frame-pointer(已在 CMakeLists 中启用)。
|
|
73
|
+
*
|
|
74
|
+
* arm64 栈帧布局(AAPCS64):fp -> [saved_fp(x29), saved_lr(x30)]
|
|
75
|
+
* 权衡:穿越未开启帧指针的系统库(libc/libart 等)时可能提前截断,
|
|
76
|
+
* 栈略短于 .eh_frame unwinding,但避免了信号上下文加锁风险。
|
|
77
|
+
*/
|
|
78
|
+
static int rum_fp_backtrace_arm64(void **buffer, int max_frames, ucontext_t *uc) {
|
|
79
|
+
if (buffer == NULL || max_frames <= 0 || uc == NULL) {
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
int count = 0;
|
|
84
|
+
// frame[0] = 崩溃 PC
|
|
85
|
+
buffer[count++] = (void *)(uintptr_t)uc->uc_mcontext.pc;
|
|
86
|
+
|
|
87
|
+
void **fp = (void **)(uintptr_t)uc->uc_mcontext.regs[29];
|
|
88
|
+
while (count < max_frames && fp != NULL) {
|
|
89
|
+
void *next_fp = fp[0]; // 上一帧 fp
|
|
90
|
+
void *lr = fp[1]; // 返回地址
|
|
91
|
+
|
|
92
|
+
if (lr == NULL) break;
|
|
93
|
+
buffer[count++] = lr;
|
|
94
|
+
|
|
95
|
+
if (next_fp == NULL) break;
|
|
96
|
+
// fp 必须单调递增(栈向低地址增长,调用者 fp 更高),防止循环
|
|
97
|
+
if ((uintptr_t)next_fp <= (uintptr_t)fp) break;
|
|
98
|
+
// fp 必须 16 字节对齐(AAPCS64 栈对齐要求)
|
|
99
|
+
if ((uintptr_t)next_fp & 0xf) break;
|
|
100
|
+
fp = (void **)next_fp;
|
|
101
|
+
}
|
|
102
|
+
return count;
|
|
103
|
+
}
|
|
104
|
+
#endif
|
|
105
|
+
|
|
106
|
+
/*
|
|
107
|
+
* Capture backtrace.
|
|
108
|
+
* - arm64/x86: 使用 _Unwind_Backtrace(通常安全)
|
|
109
|
+
* - arm32: 使用 frame pointer 遍历(避免 _Unwind_Backtrace 死锁风险)
|
|
110
|
+
* If uc is provided, the crash PC is inserted as frame[0].
|
|
111
|
+
*/
|
|
112
|
+
int rum_backtrace(void **buffer, int max_frames, ucontext_t *uc) {
|
|
113
|
+
if (buffer == NULL || max_frames <= 0) {
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#if defined(__arm__)
|
|
118
|
+
// ARM32: 使用 frame pointer 遍历,避免 _Unwind_Backtrace 死锁
|
|
119
|
+
return rum_fp_backtrace(buffer, max_frames, uc);
|
|
120
|
+
#elif defined(__aarch64__)
|
|
121
|
+
// ARM64: 使用 frame pointer 遍历,避免 _Unwind_Backtrace 信号内持锁死锁
|
|
122
|
+
return rum_fp_backtrace_arm64(buffer, max_frames, uc);
|
|
123
|
+
#else
|
|
124
|
+
// x86 / x86_64(主要为模拟器): 使用 _Unwind_Backtrace
|
|
125
|
+
backtrace_state_t state = { buffer, max_frames, 0, 0 };
|
|
126
|
+
|
|
127
|
+
// Insert crash PC first (per-architecture register extraction)
|
|
128
|
+
if (uc != NULL) {
|
|
129
|
+
#if defined(__aarch64__)
|
|
130
|
+
buffer[0] = (void *)(uintptr_t)uc->uc_mcontext.pc;
|
|
131
|
+
state.count = 1;
|
|
132
|
+
#elif defined(__x86_64__)
|
|
133
|
+
buffer[0] = (void *)(uintptr_t)uc->uc_mcontext.gregs[REG_RIP];
|
|
134
|
+
state.count = 1;
|
|
135
|
+
#elif defined(__i386__)
|
|
136
|
+
buffer[0] = (void *)(uintptr_t)uc->uc_mcontext.gregs[REG_EIP];
|
|
137
|
+
state.count = 1;
|
|
138
|
+
#endif
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
_Unwind_Backtrace(unwind_callback, &state);
|
|
142
|
+
return state.count;
|
|
143
|
+
#endif
|
|
144
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#include <signal.h>
|
|
2
|
+
#include <string.h>
|
|
3
|
+
#include <unistd.h>
|
|
4
|
+
#include <fcntl.h>
|
|
5
|
+
#include <time.h>
|
|
6
|
+
#include <stdint.h>
|
|
7
|
+
#include <sys/stat.h>
|
|
8
|
+
#include <sys/ucontext.h>
|
|
9
|
+
#include <android/log.h>
|
|
10
|
+
#include <jni.h>
|
|
11
|
+
|
|
12
|
+
#define TAG "RumCrash"
|
|
13
|
+
// 帧采集上限:与 rum_crash_writer.c 的 TRUNCATION_THRESHOLD 对齐。
|
|
14
|
+
// 递归崩溃(如 StackOverflow)可能产生数千帧,512 帧足以覆盖
|
|
15
|
+
// 大多数崩溃场景,同时在信号处理器栈上占用可控(512 * sizeof(void*) = 4KB)。
|
|
16
|
+
#define MAX_FRAMES 512
|
|
17
|
+
|
|
18
|
+
// Signals to capture
|
|
19
|
+
static const int HANDLED_SIGNALS[] = { SIGSEGV, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGTRAP };
|
|
20
|
+
#define NUM_SIGNALS 6
|
|
21
|
+
|
|
22
|
+
// Previous signal handlers (for chain calling)
|
|
23
|
+
static struct sigaction g_old_actions[NUM_SIGNALS];
|
|
24
|
+
|
|
25
|
+
// Crash output directory
|
|
26
|
+
static char g_crash_dir[512] = {0};
|
|
27
|
+
static size_t g_crash_dir_len = 0;
|
|
28
|
+
|
|
29
|
+
// Alternate signal stack (32KB+)
|
|
30
|
+
static char g_alt_stack[SIGSTKSZ * 4];
|
|
31
|
+
|
|
32
|
+
// Reentrancy guard
|
|
33
|
+
static volatile sig_atomic_t g_handling_crash = 0;
|
|
34
|
+
|
|
35
|
+
// Forward declarations (implemented in companion files)
|
|
36
|
+
extern int rum_backtrace(void **buffer, int max_frames, ucontext_t *uc);
|
|
37
|
+
extern void rum_write_crash(int fd, int signum, siginfo_t *info, ucontext_t *uc,
|
|
38
|
+
void **frames, int frame_count);
|
|
39
|
+
|
|
40
|
+
// async-signal-safe: convert non-negative long long to decimal string
|
|
41
|
+
// returns length written (no null terminator)
|
|
42
|
+
static int safe_ltoa(char *buf, long long val) {
|
|
43
|
+
if (val < 0) {
|
|
44
|
+
buf[0] = '-';
|
|
45
|
+
// 使用 unsigned long long 避免 LLONG_MIN 取反溢出
|
|
46
|
+
unsigned long long uval = (unsigned long long)(-(val + 1)) + 1ULL;
|
|
47
|
+
char tmp[32];
|
|
48
|
+
int n = 0;
|
|
49
|
+
while (uval > 0) {
|
|
50
|
+
tmp[n++] = (char)('0' + (uval % 10));
|
|
51
|
+
uval /= 10;
|
|
52
|
+
}
|
|
53
|
+
if (n == 0) tmp[n++] = '0';
|
|
54
|
+
for (int i = 0; i < n; i++) {
|
|
55
|
+
buf[1 + i] = tmp[n - 1 - i];
|
|
56
|
+
}
|
|
57
|
+
return 1 + n;
|
|
58
|
+
}
|
|
59
|
+
char tmp[32];
|
|
60
|
+
int n = 0;
|
|
61
|
+
if (val == 0) {
|
|
62
|
+
tmp[n++] = '0';
|
|
63
|
+
} else {
|
|
64
|
+
while (val > 0) {
|
|
65
|
+
tmp[n++] = (char)('0' + (val % 10));
|
|
66
|
+
val /= 10;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
for (int i = 0; i < n; i++) {
|
|
70
|
+
buf[i] = tmp[n - 1 - i];
|
|
71
|
+
}
|
|
72
|
+
return n;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// async-signal-safe: append source string to buf at *pos, capped by cap
|
|
76
|
+
static void safe_append(char *buf, size_t *pos, size_t cap, const char *src) {
|
|
77
|
+
while (*src && *pos < cap - 1) {
|
|
78
|
+
buf[(*pos)++] = *src++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static void crash_signal_handler(int signum, siginfo_t *info, void *context) {
|
|
83
|
+
// 1. Reentrancy guard
|
|
84
|
+
if (g_handling_crash) {
|
|
85
|
+
// Restore default and re-raise to allow process termination
|
|
86
|
+
signal(signum, SIG_DFL);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
g_handling_crash = 1;
|
|
90
|
+
|
|
91
|
+
ucontext_t *uc = (ucontext_t *)context;
|
|
92
|
+
|
|
93
|
+
// 2. Capture backtrace
|
|
94
|
+
void *frames[MAX_FRAMES];
|
|
95
|
+
int frame_count = rum_backtrace(frames, MAX_FRAMES, uc);
|
|
96
|
+
|
|
97
|
+
// 3. Build file path: {dir}/crash_native_{timestamp}_{pid}.json
|
|
98
|
+
// Manual concatenation (no sprintf, async-signal-safe).
|
|
99
|
+
char filepath[768];
|
|
100
|
+
size_t fp_pos = 0;
|
|
101
|
+
if (g_crash_dir_len > 0 && g_crash_dir_len < sizeof(filepath) - 100) {
|
|
102
|
+
memcpy(filepath, g_crash_dir, g_crash_dir_len);
|
|
103
|
+
fp_pos = g_crash_dir_len;
|
|
104
|
+
// ensure trailing slash
|
|
105
|
+
if (filepath[fp_pos - 1] != '/') {
|
|
106
|
+
filepath[fp_pos++] = '/';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
safe_append(filepath, &fp_pos, sizeof(filepath), "crash_native_");
|
|
110
|
+
|
|
111
|
+
// timestamp via time(NULL) — async-signal-safe per POSIX
|
|
112
|
+
time_t now = time(NULL);
|
|
113
|
+
fp_pos += safe_ltoa(filepath + fp_pos, (long long)now);
|
|
114
|
+
|
|
115
|
+
// 追加 pid 防止同秒崩溃文件名冲突,同时作为 crash_id 的一部分
|
|
116
|
+
safe_append(filepath, &fp_pos, sizeof(filepath), "_");
|
|
117
|
+
fp_pos += safe_ltoa(filepath + fp_pos, (long long)getpid());
|
|
118
|
+
|
|
119
|
+
safe_append(filepath, &fp_pos, sizeof(filepath), ".json");
|
|
120
|
+
filepath[fp_pos] = '\0';
|
|
121
|
+
|
|
122
|
+
// 4. Open and write
|
|
123
|
+
int fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
|
124
|
+
if (fd >= 0) {
|
|
125
|
+
rum_write_crash(fd, signum, info, uc, frames, frame_count);
|
|
126
|
+
fsync(fd);
|
|
127
|
+
close(fd);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 5. Chain to previous handler
|
|
131
|
+
for (int i = 0; i < NUM_SIGNALS; i++) {
|
|
132
|
+
if (HANDLED_SIGNALS[i] == signum) {
|
|
133
|
+
sigaction(signum, &g_old_actions[i], NULL);
|
|
134
|
+
if (g_old_actions[i].sa_flags & SA_SIGINFO) {
|
|
135
|
+
if (g_old_actions[i].sa_sigaction != NULL) {
|
|
136
|
+
g_old_actions[i].sa_sigaction(signum, info, context);
|
|
137
|
+
}
|
|
138
|
+
} else if (g_old_actions[i].sa_handler != SIG_DFL &&
|
|
139
|
+
g_old_actions[i].sa_handler != SIG_IGN &&
|
|
140
|
+
g_old_actions[i].sa_handler != NULL) {
|
|
141
|
+
g_old_actions[i].sa_handler(signum);
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 6. Terminate process
|
|
148
|
+
_exit(128 + signum);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
JNIEXPORT void JNICALL
|
|
152
|
+
Java_com_rumsdkreactnative_crash_NdkCrashHandler_nativeInstall(JNIEnv *env, jclass clazz, jstring crash_dir_path) {
|
|
153
|
+
(void)clazz;
|
|
154
|
+
|
|
155
|
+
if (crash_dir_path == NULL) {
|
|
156
|
+
__android_log_print(ANDROID_LOG_WARN, TAG, "nativeInstall: null crash_dir_path");
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const char *dir = (*env)->GetStringUTFChars(env, crash_dir_path, NULL);
|
|
161
|
+
if (dir != NULL) {
|
|
162
|
+
size_t len = strlen(dir);
|
|
163
|
+
if (len >= sizeof(g_crash_dir)) {
|
|
164
|
+
len = sizeof(g_crash_dir) - 1;
|
|
165
|
+
}
|
|
166
|
+
memcpy(g_crash_dir, dir, len);
|
|
167
|
+
g_crash_dir[len] = '\0';
|
|
168
|
+
g_crash_dir_len = len;
|
|
169
|
+
(*env)->ReleaseStringUTFChars(env, crash_dir_path, dir);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Setup alternate signal stack (avoid stack overflow during crash)
|
|
173
|
+
stack_t ss;
|
|
174
|
+
memset(&ss, 0, sizeof(ss));
|
|
175
|
+
ss.ss_sp = g_alt_stack;
|
|
176
|
+
ss.ss_size = sizeof(g_alt_stack);
|
|
177
|
+
ss.ss_flags = 0;
|
|
178
|
+
sigaltstack(&ss, NULL);
|
|
179
|
+
|
|
180
|
+
// Setup sigaction template
|
|
181
|
+
struct sigaction sa;
|
|
182
|
+
memset(&sa, 0, sizeof(sa));
|
|
183
|
+
sa.sa_sigaction = crash_signal_handler;
|
|
184
|
+
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
|
185
|
+
sigemptyset(&sa.sa_mask);
|
|
186
|
+
for (int i = 0; i < NUM_SIGNALS; i++) {
|
|
187
|
+
sigaddset(&sa.sa_mask, HANDLED_SIGNALS[i]);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Register for each signal, preserving previous handler for chain calling
|
|
191
|
+
for (int i = 0; i < NUM_SIGNALS; i++) {
|
|
192
|
+
if (sigaction(HANDLED_SIGNALS[i], &sa, &g_old_actions[i]) != 0) {
|
|
193
|
+
__android_log_print(ANDROID_LOG_WARN, TAG,
|
|
194
|
+
"Failed to install handler for signal %d", HANDLED_SIGNALS[i]);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
__android_log_print(ANDROID_LOG_INFO, TAG,
|
|
199
|
+
"NDK crash handler installed at: %s", g_crash_dir);
|
|
200
|
+
}
|