@arms/rum-reactnative 0.1.2 → 0.1.3-beta.1

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.
Files changed (172) hide show
  1. package/README.md +79 -1
  2. package/RumSdkReactnative.podspec +28 -0
  3. package/android/build.gradle +83 -0
  4. package/android/gradle.properties +6 -0
  5. package/android/src/main/AndroidManifest.xml +13 -0
  6. package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativeModule.kt +512 -0
  7. package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativePackage.kt +33 -0
  8. package/android/src/main/java/com/rumsdkreactnative/crash/CrashContextManager.kt +157 -0
  9. package/android/src/main/java/com/rumsdkreactnative/crash/CrashHandler.kt +444 -0
  10. package/android/src/main/java/com/rumsdkreactnative/crash/CrashInitProvider.kt +50 -0
  11. package/android/src/main/java/com/rumsdkreactnative/crash/NdkCrashHandler.kt +66 -0
  12. package/android/src/main/jni/CMakeLists.txt +21 -0
  13. package/android/src/main/jni/rum_backtrace.c +144 -0
  14. package/android/src/main/jni/rum_crash_handler.c +200 -0
  15. package/android/src/main/jni/rum_crash_writer.c +436 -0
  16. package/android/src/main/jni/rum_module_info.c +355 -0
  17. package/android/src/main/jni/rum_module_info.h +58 -0
  18. package/android/src/main/jni/rum_test_crash.cpp +55 -0
  19. package/app.plugin.js +11 -0
  20. package/docs/ReactNative SDK/351/205/215/347/275/256/345/217/202/350/200/203.md" +671 -0
  21. package/docs/SDK /347/211/210/346/234/254/350/257/264/346/230/216.md" +12 -0
  22. package/docs//346/216/245/345/205/245ReactNative/345/272/224/347/224/250.md +238 -0
  23. package/ios/PrivacyInfo.xcprivacy +93 -0
  24. package/ios/RumCrashReporter.h +38 -0
  25. package/ios/RumCrashReporter.mm +861 -0
  26. package/ios/RumSdkReactnative.h +5 -0
  27. package/ios/RumSdkReactnative.mm +291 -0
  28. package/ios/fishhook/fishhook.c +264 -0
  29. package/ios/fishhook/fishhook.h +76 -0
  30. package/lib/commonjs/NativeRumSdkReactnative.js +50 -0
  31. package/lib/commonjs/collector/action/index.js +108 -0
  32. package/lib/commonjs/collector/exception/crash.js +148 -0
  33. package/lib/commonjs/collector/exception/index.js +238 -0
  34. package/lib/commonjs/collector/index.js +42 -0
  35. package/lib/commonjs/collector/resource/api.js +286 -0
  36. package/lib/commonjs/collector/view/perf.js +79 -0
  37. package/lib/commonjs/collector/view/pv.js +88 -0
  38. package/lib/commonjs/expoConfigPlugin.js +37 -0
  39. package/lib/commonjs/index.js +29 -0
  40. package/lib/commonjs/package.json +1 -0
  41. package/lib/commonjs/plugin.js +47 -0
  42. package/lib/commonjs/processor/default-processor.js +27 -0
  43. package/lib/commonjs/processor/session-processor.js +47 -0
  44. package/lib/commonjs/reporter/index.js +148 -0
  45. package/lib/commonjs/reporter/monitor-reporter.js +43 -0
  46. package/lib/commonjs/shell.js +91 -0
  47. package/lib/commonjs/types/client.js +6 -0
  48. package/lib/commonjs/types/crash.js +37 -0
  49. package/lib/commonjs/types/index.js +2 -0
  50. package/lib/commonjs/utils/action.js +305 -0
  51. package/lib/commonjs/utils/api.js +83 -0
  52. package/lib/commonjs/utils/base.js +95 -0
  53. package/lib/commonjs/utils/crash.js +149 -0
  54. package/lib/commonjs/utils/platform.js +162 -0
  55. package/lib/commonjs/utils/session.js +158 -0
  56. package/lib/commonjs/utils/url.js +59 -0
  57. package/lib/commonjs/utils/view.js +93 -0
  58. package/lib/module/NativeRumSdkReactnative.js +47 -0
  59. package/lib/module/collector/action/index.js +45 -10
  60. package/lib/module/collector/exception/crash.js +143 -0
  61. package/lib/module/collector/exception/index.js +144 -46
  62. package/lib/module/collector/index.js +8 -0
  63. package/lib/module/collector/resource/api.js +6 -6
  64. package/lib/module/collector/view/pv.js +11 -0
  65. package/lib/module/expoConfigPlugin.js +33 -0
  66. package/lib/module/index.js +1 -0
  67. package/lib/module/processor/session-processor.js +22 -0
  68. package/lib/module/reporter/index.js +102 -16
  69. package/lib/module/reporter/monitor-reporter.js +38 -0
  70. package/lib/module/shell.js +11 -7
  71. package/lib/module/types/crash.js +33 -0
  72. package/lib/module/utils/action.js +299 -0
  73. package/lib/module/utils/crash.js +144 -0
  74. package/lib/module/utils/platform.js +124 -72
  75. package/lib/module/utils/session.js +23 -4
  76. package/lib/typescript/commonjs/package.json +1 -0
  77. package/lib/typescript/commonjs/src/NativeRumSdkReactnative.d.ts +49 -0
  78. package/lib/typescript/{src → commonjs/src}/collector/action/index.d.ts +6 -0
  79. package/lib/typescript/commonjs/src/collector/exception/crash.d.ts +28 -0
  80. package/lib/typescript/{src → commonjs/src}/collector/exception/index.d.ts +7 -0
  81. package/lib/typescript/commonjs/src/collector/index.d.ts +6 -0
  82. package/lib/typescript/commonjs/src/expoConfigPlugin.d.ts +28 -0
  83. package/lib/typescript/commonjs/src/index.d.ts +6 -0
  84. package/lib/typescript/{src → commonjs/src}/processor/session-processor.d.ts +2 -0
  85. package/lib/typescript/{src → commonjs/src}/reporter/index.d.ts +3 -1
  86. package/lib/typescript/commonjs/src/reporter/monitor-reporter.d.ts +8 -0
  87. package/lib/typescript/{src → commonjs/src}/shell.d.ts +11 -0
  88. package/lib/typescript/commonjs/src/types/crash.d.ts +95 -0
  89. package/lib/typescript/commonjs/src/utils/action.d.ts +63 -0
  90. package/lib/typescript/commonjs/src/utils/crash.d.ts +12 -0
  91. package/lib/typescript/commonjs/src/utils/platform.d.ts +22 -0
  92. package/lib/typescript/{src → commonjs/src}/utils/session.d.ts +4 -0
  93. package/lib/typescript/module/src/NativeRumSdkReactnative.d.ts +49 -0
  94. package/lib/typescript/module/src/collector/action/index.d.ts +21 -0
  95. package/lib/typescript/module/src/collector/exception/crash.d.ts +28 -0
  96. package/lib/typescript/module/src/collector/exception/index.d.ts +32 -0
  97. package/lib/typescript/module/src/collector/index.d.ts +6 -0
  98. package/lib/typescript/module/src/collector/resource/api.d.ts +21 -0
  99. package/lib/typescript/module/src/collector/view/perf.d.ts +1 -0
  100. package/lib/typescript/module/src/collector/view/pv.d.ts +16 -0
  101. package/lib/typescript/module/src/expoConfigPlugin.d.ts +28 -0
  102. package/lib/typescript/module/src/index.d.ts +6 -0
  103. package/lib/typescript/module/src/plugin.d.ts +3 -0
  104. package/lib/typescript/module/src/processor/default-processor.d.ts +6 -0
  105. package/lib/typescript/module/src/processor/session-processor.d.ts +11 -0
  106. package/lib/typescript/module/src/reporter/index.d.ts +18 -0
  107. package/lib/typescript/module/src/reporter/monitor-reporter.d.ts +8 -0
  108. package/lib/typescript/module/src/shell.d.ts +57 -0
  109. package/lib/typescript/module/src/types/client.d.ts +27 -0
  110. package/lib/typescript/module/src/types/crash.d.ts +95 -0
  111. package/lib/typescript/module/src/types/index.d.ts +118 -0
  112. package/lib/typescript/module/src/utils/action.d.ts +63 -0
  113. package/lib/typescript/module/src/utils/api.d.ts +59 -0
  114. package/lib/typescript/module/src/utils/base.d.ts +8 -0
  115. package/lib/typescript/module/src/utils/crash.d.ts +12 -0
  116. package/lib/typescript/module/src/utils/platform.d.ts +22 -0
  117. package/lib/typescript/module/src/utils/session.d.ts +41 -0
  118. package/lib/typescript/module/src/utils/url.d.ts +17 -0
  119. package/lib/typescript/module/src/utils/view.d.ts +13 -0
  120. package/package.json +51 -28
  121. package/lib/module/collector/action/index.js.map +0 -1
  122. package/lib/module/collector/exception/index.js.map +0 -1
  123. package/lib/module/collector/resource/api.js.map +0 -1
  124. package/lib/module/collector/view/perf.js.map +0 -1
  125. package/lib/module/collector/view/pv.js.map +0 -1
  126. package/lib/module/index.js.map +0 -1
  127. package/lib/module/plugin.js.map +0 -1
  128. package/lib/module/processor/default-processor.js.map +0 -1
  129. package/lib/module/processor/session-processor.js.map +0 -1
  130. package/lib/module/reporter/index.js.map +0 -1
  131. package/lib/module/shell.js.map +0 -1
  132. package/lib/module/types/client.js.map +0 -1
  133. package/lib/module/types/index.js.map +0 -1
  134. package/lib/module/utils/api.js.map +0 -1
  135. package/lib/module/utils/base.js.map +0 -1
  136. package/lib/module/utils/platform.js.map +0 -1
  137. package/lib/module/utils/session.js.map +0 -1
  138. package/lib/module/utils/url.js.map +0 -1
  139. package/lib/module/utils/view.js.map +0 -1
  140. package/lib/typescript/src/collector/action/index.d.ts.map +0 -1
  141. package/lib/typescript/src/collector/exception/index.d.ts.map +0 -1
  142. package/lib/typescript/src/collector/resource/api.d.ts.map +0 -1
  143. package/lib/typescript/src/collector/view/perf.d.ts.map +0 -1
  144. package/lib/typescript/src/collector/view/pv.d.ts.map +0 -1
  145. package/lib/typescript/src/index.d.ts +0 -4
  146. package/lib/typescript/src/index.d.ts.map +0 -1
  147. package/lib/typescript/src/plugin.d.ts.map +0 -1
  148. package/lib/typescript/src/processor/default-processor.d.ts.map +0 -1
  149. package/lib/typescript/src/processor/session-processor.d.ts.map +0 -1
  150. package/lib/typescript/src/reporter/index.d.ts.map +0 -1
  151. package/lib/typescript/src/shell.d.ts.map +0 -1
  152. package/lib/typescript/src/types/client.d.ts.map +0 -1
  153. package/lib/typescript/src/types/index.d.ts.map +0 -1
  154. package/lib/typescript/src/utils/api.d.ts.map +0 -1
  155. package/lib/typescript/src/utils/base.d.ts.map +0 -1
  156. package/lib/typescript/src/utils/platform.d.ts +0 -15
  157. package/lib/typescript/src/utils/platform.d.ts.map +0 -1
  158. package/lib/typescript/src/utils/session.d.ts.map +0 -1
  159. package/lib/typescript/src/utils/url.d.ts.map +0 -1
  160. package/lib/typescript/src/utils/view.d.ts.map +0 -1
  161. /package/lib/typescript/{src → commonjs/src}/collector/resource/api.d.ts +0 -0
  162. /package/lib/typescript/{src → commonjs/src}/collector/view/perf.d.ts +0 -0
  163. /package/lib/typescript/{src → commonjs/src}/collector/view/pv.d.ts +0 -0
  164. /package/lib/typescript/{src → commonjs/src}/plugin.d.ts +0 -0
  165. /package/lib/typescript/{src → commonjs/src}/processor/default-processor.d.ts +0 -0
  166. /package/lib/typescript/{src → commonjs/src}/types/client.d.ts +0 -0
  167. /package/lib/typescript/{src → commonjs/src}/types/index.d.ts +0 -0
  168. /package/lib/typescript/{src → commonjs/src}/utils/api.d.ts +0 -0
  169. /package/lib/typescript/{src → commonjs/src}/utils/base.d.ts +0 -0
  170. /package/lib/typescript/{src → commonjs/src}/utils/url.d.ts +0 -0
  171. /package/lib/typescript/{src → commonjs/src}/utils/view.d.ts +0 -0
  172. /package/lib/typescript/{package.json → module/package.json} +0 -0
@@ -0,0 +1,5 @@
1
+ #import <RumSdkReactnativeSpec/RumSdkReactnativeSpec.h>
2
+
3
+ @interface RumSdkReactnative : NSObject <NativeRumSdkReactnativeSpec>
4
+
5
+ @end
@@ -0,0 +1,291 @@
1
+ #import "RumSdkReactnative.h"
2
+ #import "RumCrashReporter.h"
3
+ #import <UIKit/UIKit.h>
4
+ #import <sys/utsname.h>
5
+ #import <signal.h>
6
+ #include <stdexcept>
7
+
8
+ static NSString *const kRumSdkDefaultsSuiteName = @"com.aliyun.rum.reactnative";
9
+ static NSString *const kLegacyDefaultsSuiteName = @"com.aliyun.arms.rum.reactnative";
10
+
11
+ @implementation RumSdkReactnative
12
+
13
+ RCT_EXPORT_MODULE()
14
+
15
+ - (instancetype)init
16
+ {
17
+ if ((self = [super init])) {
18
+ // 模块实例化时安装崩溃监控(dispatch_once 内部保证幂等)
19
+ [RumCrashReporter install];
20
+ }
21
+ return self;
22
+ }
23
+
24
+ // MARK: - Storage Helpers
25
+
26
+ - (NSUserDefaults *)defaults
27
+ {
28
+ static NSUserDefaults *defaults = nil;
29
+ static dispatch_once_t onceToken;
30
+ dispatch_once(&onceToken, ^{
31
+ defaults = [[NSUserDefaults alloc] initWithSuiteName:kRumSdkDefaultsSuiteName];
32
+ if (defaults == nil) {
33
+ defaults = [NSUserDefaults standardUserDefaults];
34
+ }
35
+ // 迁移旧版 suite 数据(com.aliyun.arms.rum.reactnative → com.aliyun.rum.reactnative)
36
+ NSUserDefaults *legacy = [[NSUserDefaults alloc] initWithSuiteName:kLegacyDefaultsSuiteName];
37
+ if (legacy != nil) {
38
+ NSDictionary *oldData = [legacy persistentDomainForName:kLegacyDefaultsSuiteName];
39
+ if (oldData.count > 0) {
40
+ NSMutableDictionary *current = [[defaults persistentDomainForName:kRumSdkDefaultsSuiteName] mutableCopy] ?: [NSMutableDictionary dictionary];
41
+ for (NSString *key in oldData) {
42
+ if (current[key] == nil) {
43
+ current[key] = oldData[key];
44
+ }
45
+ }
46
+ [defaults setPersistentDomain:current forName:kRumSdkDefaultsSuiteName];
47
+ [legacy removePersistentDomainForName:kLegacyDefaultsSuiteName];
48
+ }
49
+ }
50
+ });
51
+ return defaults;
52
+ }
53
+
54
+ - (void)getItem:(NSString *)key
55
+ resolve:(RCTPromiseResolveBlock)resolve
56
+ reject:(RCTPromiseRejectBlock)reject
57
+ {
58
+ NSString *value = [[self defaults] stringForKey:key];
59
+ resolve(value ?: [NSNull null]);
60
+ }
61
+
62
+ - (void)setItem:(NSString *)key
63
+ value:(NSString *)value
64
+ resolve:(RCTPromiseResolveBlock)resolve
65
+ reject:(RCTPromiseRejectBlock)reject
66
+ {
67
+ [[self defaults] setObject:value forKey:key];
68
+ resolve(nil);
69
+ }
70
+
71
+ - (void)removeItem:(NSString *)key
72
+ resolve:(RCTPromiseResolveBlock)resolve
73
+ reject:(RCTPromiseRejectBlock)reject
74
+ {
75
+ [[self defaults] removeObjectForKey:key];
76
+ resolve(nil);
77
+ }
78
+
79
+ - (void)clear:(RCTPromiseResolveBlock)resolve
80
+ reject:(RCTPromiseRejectBlock)reject
81
+ {
82
+ [[self defaults] removePersistentDomainForName:kRumSdkDefaultsSuiteName];
83
+ resolve(nil);
84
+ }
85
+
86
+ - (void)getAllKeys:(RCTPromiseResolveBlock)resolve
87
+ reject:(RCTPromiseRejectBlock)reject
88
+ {
89
+ NSDictionary<NSString *, id> *suite =
90
+ [[self defaults] persistentDomainForName:kRumSdkDefaultsSuiteName];
91
+ resolve(suite ? [suite allKeys] : @[]);
92
+ }
93
+
94
+ // MARK: - Device Info
95
+
96
+ - (void)getDeviceInfo:(RCTPromiseResolveBlock)resolve
97
+ reject:(RCTPromiseRejectBlock)reject
98
+ {
99
+ @try {
100
+ NSMutableDictionary *info = [NSMutableDictionary dictionary];
101
+ UIDevice *device = [UIDevice currentDevice];
102
+
103
+ // device.id - IDFV,应用供应商标识,同一开发商的 App 共享
104
+ NSUUID *idfv = [device identifierForVendor];
105
+ if (idfv) {
106
+ info[@"device_id"] = [idfv UUIDString];
107
+ }
108
+
109
+ // device.brand - iOS 设备品牌固定为 Apple
110
+ info[@"device_brand"] = @"Apple";
111
+
112
+ // device.model - 通过 sysctl hw.machine 获取硬件标识(如 iPhone14,5)
113
+ struct utsname systemInfo;
114
+ uname(&systemInfo);
115
+ NSString *machine = [NSString stringWithCString:systemInfo.machine
116
+ encoding:NSUTF8StringEncoding];
117
+ info[@"device_model"] = machine ?: @"";
118
+
119
+ // device.name - 用户自定义设备名称(如 "小明的 iPhone")
120
+ info[@"device_name"] = [device name] ?: @"";
121
+
122
+ // device.type - iOS 设备类型,根据 userInterfaceIdiom 判断
123
+ NSString *deviceType;
124
+ switch ([device userInterfaceIdiom]) {
125
+ case UIUserInterfaceIdiomPad:
126
+ deviceType = @"tablet";
127
+ break;
128
+ case UIUserInterfaceIdiomTV:
129
+ deviceType = @"tv";
130
+ break;
131
+ default:
132
+ deviceType = @"mobile";
133
+ break;
134
+ }
135
+ info[@"device_type"] = deviceType;
136
+
137
+ // os.type - 操作系统名称(如 "iOS")
138
+ info[@"os_type"] = [device systemName] ?: @"iOS";
139
+
140
+ // os.version - 操作系统版本(如 "17.4")
141
+ info[@"os_version"] = [device systemVersion] ?: @"";
142
+
143
+ // app.package - Bundle Identifier
144
+ NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier];
145
+ info[@"app_package"] = bundleId ?: @"";
146
+
147
+ // app.version - 应用版本号(CFBundleShortVersionString)
148
+ NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
149
+ info[@"app_version"] = appVersion ?: @"";
150
+
151
+ // viewport - 主屏幕物理像素尺寸
152
+ UIScreen *mainScreen = [UIScreen mainScreen];
153
+ CGSize nativeSize = mainScreen.nativeBounds.size;
154
+ info[@"viewport_width"] = @((NSInteger)nativeSize.width);
155
+ info[@"viewport_height"] = @((NSInteger)nativeSize.height);
156
+
157
+ resolve(info);
158
+ } @catch (NSException *exception) {
159
+ reject(@"RUM_DEVICE_INFO_ERROR", exception.reason, nil);
160
+ }
161
+ }
162
+
163
+ // MARK: - TurboModule
164
+
165
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
166
+ (const facebook::react::ObjCTurboModule::InitParams &)params
167
+ {
168
+ return std::make_shared<facebook::react::NativeRumSdkReactnativeSpecJSI>(params);
169
+ }
170
+
171
+ // MARK: - Crash Reporting
172
+
173
+ - (void)getPendingCrashes:(RCTPromiseResolveBlock)resolve
174
+ reject:(RCTPromiseRejectBlock)reject
175
+ {
176
+ @try {
177
+ NSArray<NSDictionary *> *reports = [RumCrashReporter pendingCrashReports];
178
+ NSError *error = nil;
179
+ NSData *jsonData = [NSJSONSerialization dataWithJSONObject:reports
180
+ options:0
181
+ error:&error];
182
+ if (jsonData == nil) {
183
+ resolve(@"[]");
184
+ return;
185
+ }
186
+ NSString *jsonString = [[NSString alloc] initWithData:jsonData
187
+ encoding:NSUTF8StringEncoding];
188
+ resolve(jsonString ?: @"[]");
189
+ } @catch (NSException *exception) {
190
+ reject(@"RUM_CRASH_GET_PENDING_ERROR", exception.reason, nil);
191
+ }
192
+ }
193
+
194
+ - (void)clearCrashReports:(NSString *)crashIds
195
+ resolve:(RCTPromiseResolveBlock)resolve
196
+ reject:(RCTPromiseRejectBlock)reject
197
+ {
198
+ @try {
199
+ NSArray *ids = @[];
200
+ if (crashIds.length > 0) {
201
+ NSData *data = [crashIds dataUsingEncoding:NSUTF8StringEncoding];
202
+ id parsed = data ? [NSJSONSerialization JSONObjectWithData:data
203
+ options:0
204
+ error:nil]
205
+ : nil;
206
+ if ([parsed isKindOfClass:[NSArray class]]) {
207
+ ids = (NSArray *)parsed;
208
+ }
209
+ }
210
+ [RumCrashReporter clearCrashReportsWithIds:ids];
211
+ resolve(nil);
212
+ } @catch (NSException *exception) {
213
+ reject(@"RUM_CRASH_CLEAR_ERROR", exception.reason, nil);
214
+ }
215
+ }
216
+
217
+ - (void)clearAllCrashReports:(RCTPromiseResolveBlock)resolve
218
+ reject:(RCTPromiseRejectBlock)reject
219
+ {
220
+ @try {
221
+ [RumCrashReporter clearAllCrashReports];
222
+ resolve(nil);
223
+ } @catch (NSException *exception) {
224
+ reject(@"RUM_CRASH_CLEAR_ALL_ERROR", exception.reason, nil);
225
+ }
226
+ }
227
+
228
+ - (void)cleanupOldCrashes:(double)maxFiles
229
+ maxAgeMs:(double)maxAgeMs
230
+ resolve:(RCTPromiseResolveBlock)resolve
231
+ reject:(RCTPromiseRejectBlock)reject
232
+ {
233
+ @try {
234
+ [RumCrashReporter cleanupOldCrashesWithMaxFiles:(NSInteger)maxFiles maxAgeMs:maxAgeMs];
235
+ resolve(nil);
236
+ } @catch (NSException *exception) {
237
+ reject(@"RUM_CRASH_CLEANUP_ERROR", exception.reason, nil);
238
+ }
239
+ }
240
+
241
+ - (void)crashedLastRun:(RCTPromiseResolveBlock)resolve
242
+ reject:(RCTPromiseRejectBlock)reject
243
+ {
244
+ resolve(@([RumCrashReporter crashedLastRun]));
245
+ }
246
+
247
+ - (void)updateCrashContext:(NSString *)context
248
+ {
249
+ [RumCrashReporter updateCrashContext:context];
250
+ }
251
+
252
+ RCT_EXPORT_METHOD(triggerTestCrash:(NSString *)crashType)
253
+ {
254
+ if ([crashType isEqualToString:@"sigsegv"]) {
255
+ // Null pointer dereference - triggers SIGSEGV/EXC_BAD_ACCESS.
256
+ // 用 volatile 防止编译器在 -O 下消除死存储。
257
+ volatile int *p = (volatile int *)0;
258
+ *p = 42;
259
+ } else if ([crashType isEqualToString:@"sigabrt"]) {
260
+ // Triggers SIGABRT
261
+ abort();
262
+ } else if ([crashType isEqualToString:@"sigfpe"]) {
263
+ // ARM 不对整数除零触发 SIGFPE(结果为 0),显式 raise 才能保证崩溃。
264
+ raise(SIGFPE);
265
+ } else if ([crashType isEqualToString:@"cpp_exception"]) {
266
+ // TurboModule 架构下 RCT_EXPORT_METHOD 中的 C++ 异常会被 bridge 的 try/catch 拦截,
267
+ // KSCrash 的 std::set_terminate handler 收不到。在新 NSThread 中抛出以绕过拦截。
268
+ NSThread *t = [[NSThread alloc] initWithBlock:^{
269
+ throw std::runtime_error("RUM SDK Test: Unhandled C++ Exception");
270
+ }];
271
+ t.name = @"rum-test-crash";
272
+ [t start];
273
+ [NSThread sleepForTimeInterval:0.1];
274
+ } else if ([crashType isEqualToString:@"objc_exception"]) {
275
+ // TurboModule 架构下 RCT_EXPORT_METHOD 中的 ObjC 异常会被 bridge 的 @try/@catch 拦截,
276
+ // KSCrash 的 NSException monitor 收不到。在新 NSThread 中抛出以绕过拦截。
277
+ NSThread *t = [[NSThread alloc] initWithBlock:^{
278
+ @throw [NSException exceptionWithName:@"RUMTestCrash"
279
+ reason:@"RUM SDK Test: Unhandled ObjC Exception"
280
+ userInfo:nil];
281
+ }];
282
+ t.name = @"rum-test-crash";
283
+ [t start];
284
+ [NSThread sleepForTimeInterval:0.1];
285
+ } else if ([crashType isEqualToString:@"stack_overflow"]) {
286
+ // Infinite recursion to trigger stack overflow
287
+ [self triggerTestCrash:@"stack_overflow"];
288
+ }
289
+ }
290
+
291
+ @end
@@ -0,0 +1,264 @@
1
+ // Copyright (c) 2013, Facebook, Inc.
2
+ // All rights reserved.
3
+ // Redistribution and use in source and binary forms, with or without
4
+ // modification, are permitted provided that the following conditions are met:
5
+ // * Redistributions of source code must retain the above copyright notice,
6
+ // this list of conditions and the following disclaimer.
7
+ // * Redistributions in binary form must reproduce the above copyright notice,
8
+ // this list of conditions and the following disclaimer in the documentation
9
+ // and/or other materials provided with the distribution.
10
+ // * Neither the name Facebook nor the names of its contributors may be used to
11
+ // endorse or promote products derived from this software without specific
12
+ // prior written permission.
13
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14
+ // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
+ // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17
+ // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
+ // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
+ // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20
+ // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21
+ // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ #include "fishhook.h"
25
+
26
+ #include <dlfcn.h>
27
+ #include <stdbool.h>
28
+ #include <stdlib.h>
29
+ #include <string.h>
30
+ #include <sys/mman.h>
31
+ #include <sys/types.h>
32
+ #include <mach/mach.h>
33
+ #include <mach/vm_map.h>
34
+ #include <mach/vm_region.h>
35
+ #include <mach-o/dyld.h>
36
+ #include <mach-o/loader.h>
37
+ #include <mach-o/nlist.h>
38
+
39
+ #ifdef __LP64__
40
+ typedef struct mach_header_64 mach_header_t;
41
+ typedef struct segment_command_64 segment_command_t;
42
+ typedef struct section_64 section_t;
43
+ typedef struct nlist_64 nlist_t;
44
+ #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64
45
+ #else
46
+ typedef struct mach_header mach_header_t;
47
+ typedef struct segment_command segment_command_t;
48
+ typedef struct section section_t;
49
+ typedef struct nlist nlist_t;
50
+ #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT
51
+ #endif
52
+
53
+ #ifndef SEG_DATA_CONST
54
+ #define SEG_DATA_CONST "__DATA_CONST"
55
+ #endif
56
+
57
+ struct rebindings_entry {
58
+ struct rebinding *rebindings;
59
+ size_t rebindings_nel;
60
+ struct rebindings_entry *next;
61
+ };
62
+
63
+ static struct rebindings_entry *_rebindings_head;
64
+
65
+ static int prepend_rebindings(struct rebindings_entry **rebindings_head,
66
+ struct rebinding rebindings[],
67
+ size_t nel) {
68
+ struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry));
69
+ if (!new_entry) {
70
+ return -1;
71
+ }
72
+ new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel);
73
+ if (!new_entry->rebindings) {
74
+ free(new_entry);
75
+ return -1;
76
+ }
77
+ memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel);
78
+ new_entry->rebindings_nel = nel;
79
+ new_entry->next = *rebindings_head;
80
+ *rebindings_head = new_entry;
81
+ return 0;
82
+ }
83
+
84
+ #if 0
85
+ static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) {
86
+ mach_port_t task = mach_task_self();
87
+ vm_size_t size = 0;
88
+ vm_address_t address = (vm_address_t)addr;
89
+ memory_object_name_t object;
90
+ #ifdef __LP64__
91
+ mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
92
+ vm_region_basic_info_data_64_t info;
93
+ kern_return_t info_ret = vm_region_64(
94
+ task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object);
95
+ #else
96
+ mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT;
97
+ vm_region_basic_info_data_t info;
98
+ kern_return_t info_ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object);
99
+ #endif
100
+ if (info_ret == KERN_SUCCESS) {
101
+ if (prot != NULL)
102
+ *prot = info.protection;
103
+
104
+ if (max_prot != NULL)
105
+ *max_prot = info.max_protection;
106
+
107
+ return 0;
108
+ }
109
+
110
+ return -1;
111
+ }
112
+ #endif
113
+
114
+ static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
115
+ section_t *section,
116
+ intptr_t slide,
117
+ nlist_t *symtab,
118
+ char *strtab,
119
+ uint32_t *indirect_symtab) {
120
+ uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
121
+ void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
122
+
123
+ for (uint i = 0; i < section->size / sizeof(void *); i++) {
124
+ uint32_t symtab_index = indirect_symbol_indices[i];
125
+ if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL ||
126
+ symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) {
127
+ continue;
128
+ }
129
+ uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;
130
+ char *symbol_name = strtab + strtab_offset;
131
+ bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1];
132
+ struct rebindings_entry *cur = rebindings;
133
+ while (cur) {
134
+ for (uint j = 0; j < cur->rebindings_nel; j++) {
135
+ if (symbol_name_longer_than_1 && strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) {
136
+ kern_return_t err;
137
+
138
+ if (cur->rebindings[j].replaced != NULL && indirect_symbol_bindings[i] != cur->rebindings[j].replacement)
139
+ *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i];
140
+
141
+ /**
142
+ * 1. Moved the vm protection modifying codes to here to reduce the
143
+ * changing scope.
144
+ * 2. Adding VM_PROT_WRITE mode unconditionally because vm_region
145
+ * API on some iOS/Mac reports mismatch vm protection attributes.
146
+ * -- Lianfu Hao Jun 16th, 2021
147
+ **/
148
+ err = vm_protect (mach_task_self (), (uintptr_t)indirect_symbol_bindings, section->size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
149
+ if (err == KERN_SUCCESS) {
150
+ /**
151
+ * Once we failed to change the vm protection, we
152
+ * MUST NOT continue the following write actions!
153
+ * iOS 15 has corrected the const segments prot.
154
+ * -- Lionfore Hao Jun 11th, 2021
155
+ **/
156
+ indirect_symbol_bindings[i] = cur->rebindings[j].replacement;
157
+ }
158
+ goto symbol_loop;
159
+ }
160
+ }
161
+ cur = cur->next;
162
+ }
163
+ symbol_loop:;
164
+ }
165
+ }
166
+
167
+ static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
168
+ const struct mach_header *header,
169
+ intptr_t slide) {
170
+ Dl_info info;
171
+ if (dladdr(header, &info) == 0) {
172
+ return;
173
+ }
174
+
175
+ segment_command_t *cur_seg_cmd;
176
+ segment_command_t *linkedit_segment = NULL;
177
+ struct symtab_command* symtab_cmd = NULL;
178
+ struct dysymtab_command* dysymtab_cmd = NULL;
179
+
180
+ uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t);
181
+ for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
182
+ cur_seg_cmd = (segment_command_t *)cur;
183
+ if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
184
+ if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) {
185
+ linkedit_segment = cur_seg_cmd;
186
+ }
187
+ } else if (cur_seg_cmd->cmd == LC_SYMTAB) {
188
+ symtab_cmd = (struct symtab_command*)cur_seg_cmd;
189
+ } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) {
190
+ dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd;
191
+ }
192
+ }
193
+
194
+ if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment ||
195
+ !dysymtab_cmd->nindirectsyms) {
196
+ return;
197
+ }
198
+
199
+ // Find base symbol/string table addresses
200
+ uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
201
+ nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
202
+ char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
203
+
204
+ // Get indirect symbol table (array of uint32_t indices into symbol table)
205
+ uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);
206
+
207
+ cur = (uintptr_t)header + sizeof(mach_header_t);
208
+ for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
209
+ cur_seg_cmd = (segment_command_t *)cur;
210
+ if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
211
+ if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 &&
212
+ strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) {
213
+ continue;
214
+ }
215
+ for (uint j = 0; j < cur_seg_cmd->nsects; j++) {
216
+ section_t *sect =
217
+ (section_t *)(cur + sizeof(segment_command_t)) + j;
218
+ if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {
219
+ perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
220
+ }
221
+ if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) {
222
+ perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
223
+ }
224
+ }
225
+ }
226
+ }
227
+ }
228
+
229
+ static void _rebind_symbols_for_image(const struct mach_header *header,
230
+ intptr_t slide) {
231
+ rebind_symbols_for_image(_rebindings_head, header, slide);
232
+ }
233
+
234
+ int rebind_symbols_image(void *header,
235
+ intptr_t slide,
236
+ struct rebinding rebindings[],
237
+ size_t rebindings_nel) {
238
+ struct rebindings_entry *rebindings_head = NULL;
239
+ int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
240
+ rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);
241
+ if (rebindings_head) {
242
+ free(rebindings_head->rebindings);
243
+ }
244
+ free(rebindings_head);
245
+ return retval;
246
+ }
247
+
248
+ int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {
249
+ int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel);
250
+ if (retval < 0) {
251
+ return retval;
252
+ }
253
+ // If this was the first call, register callback for image additions (which is also invoked for
254
+ // existing images, otherwise, just run on existing images
255
+ if (!_rebindings_head->next) {
256
+ _dyld_register_func_for_add_image(_rebind_symbols_for_image);
257
+ } else {
258
+ uint32_t c = _dyld_image_count();
259
+ for (uint32_t i = 0; i < c; i++) {
260
+ _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
261
+ }
262
+ }
263
+ return retval;
264
+ }
@@ -0,0 +1,76 @@
1
+ // Copyright (c) 2013, Facebook, Inc.
2
+ // All rights reserved.
3
+ // Redistribution and use in source and binary forms, with or without
4
+ // modification, are permitted provided that the following conditions are met:
5
+ // * Redistributions of source code must retain the above copyright notice,
6
+ // this list of conditions and the following disclaimer.
7
+ // * Redistributions in binary form must reproduce the above copyright notice,
8
+ // this list of conditions and the following disclaimer in the documentation
9
+ // and/or other materials provided with the distribution.
10
+ // * Neither the name Facebook nor the names of its contributors may be used to
11
+ // endorse or promote products derived from this software without specific
12
+ // prior written permission.
13
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14
+ // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
+ // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17
+ // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
+ // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
+ // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20
+ // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21
+ // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ #ifndef fishhook_h
25
+ #define fishhook_h
26
+
27
+ #include <stddef.h>
28
+ #include <stdint.h>
29
+
30
+ #if !defined(FISHHOOK_EXPORT)
31
+ #define FISHHOOK_VISIBILITY __attribute__((visibility("hidden")))
32
+ #else
33
+ #define FISHHOOK_VISIBILITY __attribute__((visibility("default")))
34
+ #endif
35
+
36
+ #ifdef __cplusplus
37
+ extern "C" {
38
+ #endif //__cplusplus
39
+
40
+ /*
41
+ * A structure representing a particular intended rebinding from a symbol
42
+ * name to its replacement
43
+ */
44
+ struct rebinding {
45
+ const char *name;
46
+ void *replacement;
47
+ void **replaced;
48
+ };
49
+
50
+ /*
51
+ * For each rebinding in rebindings, rebinds references to external, indirect
52
+ * symbols with the specified name to instead point at replacement for each
53
+ * image in the calling process as well as for all future images that are loaded
54
+ * by the process. If rebind_functions is called more than once, the symbols to
55
+ * rebind are added to the existing list of rebindings, and if a given symbol
56
+ * is rebound more than once, the later rebinding will take precedence.
57
+ */
58
+ FISHHOOK_VISIBILITY
59
+ int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
60
+
61
+ /*
62
+ * Rebinds as above, but only in the specified image. The header should point
63
+ * to the mach-o header, the slide should be the slide offset. Others as above.
64
+ */
65
+ FISHHOOK_VISIBILITY
66
+ int rebind_symbols_image(void *header,
67
+ intptr_t slide,
68
+ struct rebinding rebindings[],
69
+ size_t rebindings_nel);
70
+
71
+ #ifdef __cplusplus
72
+ }
73
+ #endif //__cplusplus
74
+
75
+ #endif //fishhook_h
76
+
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _reactNative = require("react-native");
8
+ /**
9
+ * 原生设备信息,对应存储模型中的公共属性:
10
+ * - device.* (id / type / brand / model / name)
11
+ * - os.* (type / version / container / container_version)
12
+ * - app.package
13
+ * - viewport.width / viewport.height
14
+ */
15
+
16
+ /**
17
+ * 获取原生模块。
18
+ *
19
+ * 使用非强制的 `TurboModuleRegistry.get`(而非 `getEnforcing`),避免在原生
20
+ * 二进制未注册该模块时于「模块加载阶段」直接抛异常——那会连锁导致整个 JS
21
+ * bundle 评估失败(表现为所有路由丢失 default export、App 白屏)。
22
+ *
23
+ * 当原生模块缺失时(通常是新增原生代码后未重新编译原生 App,只重跑了 Metro),
24
+ * 返回一组空实现兜底:崩溃采集与原生设备信息降级为不可用,但 PV / 行为 / API /
25
+ * JS 异常等纯 JS 能力不受影响。需重新构建原生工程(如 `expo run:ios` /
26
+ * `pod install` + 重新编译)后崩溃采集才会真正生效。
27
+ */
28
+ const nativeModule = _reactNative.TurboModuleRegistry.get('RumSdkReactnative');
29
+ if (!nativeModule) {
30
+ console.warn("[rum] Native module 'RumSdkReactnative' not found in the native binary. " + 'Crash reporting and native device info are disabled. ' + 'Rebuild the native app (e.g. `expo run:ios` / `expo run:android`, ' + 'or `pod install` + rebuild) so the module gets registered.');
31
+ }
32
+
33
+ /** 原生模块缺失时的空实现,保证调用方不会因缺方法而抛错。 */
34
+ const fallback = {
35
+ getItem: async () => null,
36
+ setItem: async () => {},
37
+ removeItem: async () => {},
38
+ clear: async () => {},
39
+ getAllKeys: async () => [],
40
+ getDeviceInfo: async () => ({}),
41
+ getPendingCrashes: async () => '[]',
42
+ clearCrashReports: async () => {},
43
+ clearAllCrashReports: async () => {},
44
+ cleanupOldCrashes: async () => {},
45
+ crashedLastRun: async () => false,
46
+ updateCrashContext: () => {},
47
+ triggerTestCrash: () => {}
48
+ };
49
+ var _default = exports.default = nativeModule ?? fallback;
50
+ //# sourceMappingURL=NativeRumSdkReactnative.js.map