@rejourneyco/react-native 1.0.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/android/build.gradle.kts +135 -0
- package/android/consumer-rules.pro +10 -0
- package/android/proguard-rules.pro +1 -0
- package/android/src/main/AndroidManifest.xml +15 -0
- package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +2981 -0
- package/android/src/main/java/com/rejourney/capture/ANRHandler.kt +206 -0
- package/android/src/main/java/com/rejourney/capture/ActivityTracker.kt +98 -0
- package/android/src/main/java/com/rejourney/capture/CaptureEngine.kt +1553 -0
- package/android/src/main/java/com/rejourney/capture/CaptureHeuristics.kt +375 -0
- package/android/src/main/java/com/rejourney/capture/CrashHandler.kt +153 -0
- package/android/src/main/java/com/rejourney/capture/MotionEvent.kt +215 -0
- package/android/src/main/java/com/rejourney/capture/SegmentUploader.kt +512 -0
- package/android/src/main/java/com/rejourney/capture/VideoEncoder.kt +773 -0
- package/android/src/main/java/com/rejourney/capture/ViewHierarchyScanner.kt +633 -0
- package/android/src/main/java/com/rejourney/capture/ViewSerializer.kt +286 -0
- package/android/src/main/java/com/rejourney/core/Constants.kt +117 -0
- package/android/src/main/java/com/rejourney/core/Logger.kt +93 -0
- package/android/src/main/java/com/rejourney/core/Types.kt +124 -0
- package/android/src/main/java/com/rejourney/lifecycle/SessionLifecycleService.kt +162 -0
- package/android/src/main/java/com/rejourney/network/DeviceAuthManager.kt +747 -0
- package/android/src/main/java/com/rejourney/network/HttpClientProvider.kt +16 -0
- package/android/src/main/java/com/rejourney/network/NetworkMonitor.kt +272 -0
- package/android/src/main/java/com/rejourney/network/UploadManager.kt +1363 -0
- package/android/src/main/java/com/rejourney/network/UploadWorker.kt +492 -0
- package/android/src/main/java/com/rejourney/privacy/PrivacyMask.kt +645 -0
- package/android/src/main/java/com/rejourney/touch/GestureClassifier.kt +233 -0
- package/android/src/main/java/com/rejourney/touch/KeyboardTracker.kt +158 -0
- package/android/src/main/java/com/rejourney/touch/TextInputTracker.kt +181 -0
- package/android/src/main/java/com/rejourney/touch/TouchInterceptor.kt +591 -0
- package/android/src/main/java/com/rejourney/utils/EventBuffer.kt +284 -0
- package/android/src/main/java/com/rejourney/utils/OEMDetector.kt +154 -0
- package/android/src/main/java/com/rejourney/utils/PerfTiming.kt +235 -0
- package/android/src/main/java/com/rejourney/utils/Telemetry.kt +297 -0
- package/android/src/main/java/com/rejourney/utils/WindowUtils.kt +84 -0
- package/android/src/newarch/java/com/rejourney/RejourneyModule.kt +187 -0
- package/android/src/newarch/java/com/rejourney/RejourneyPackage.kt +40 -0
- package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +218 -0
- package/android/src/oldarch/java/com/rejourney/RejourneyPackage.kt +23 -0
- package/ios/Capture/RJANRHandler.h +42 -0
- package/ios/Capture/RJANRHandler.m +328 -0
- package/ios/Capture/RJCaptureEngine.h +275 -0
- package/ios/Capture/RJCaptureEngine.m +2062 -0
- package/ios/Capture/RJCaptureHeuristics.h +80 -0
- package/ios/Capture/RJCaptureHeuristics.m +903 -0
- package/ios/Capture/RJCrashHandler.h +46 -0
- package/ios/Capture/RJCrashHandler.m +313 -0
- package/ios/Capture/RJMotionEvent.h +183 -0
- package/ios/Capture/RJMotionEvent.m +183 -0
- package/ios/Capture/RJPerformanceManager.h +100 -0
- package/ios/Capture/RJPerformanceManager.m +373 -0
- package/ios/Capture/RJPixelBufferDownscaler.h +42 -0
- package/ios/Capture/RJPixelBufferDownscaler.m +85 -0
- package/ios/Capture/RJSegmentUploader.h +146 -0
- package/ios/Capture/RJSegmentUploader.m +778 -0
- package/ios/Capture/RJVideoEncoder.h +247 -0
- package/ios/Capture/RJVideoEncoder.m +1036 -0
- package/ios/Capture/RJViewControllerTracker.h +73 -0
- package/ios/Capture/RJViewControllerTracker.m +508 -0
- package/ios/Capture/RJViewHierarchyScanner.h +215 -0
- package/ios/Capture/RJViewHierarchyScanner.m +1464 -0
- package/ios/Capture/RJViewSerializer.h +119 -0
- package/ios/Capture/RJViewSerializer.m +498 -0
- package/ios/Core/RJConstants.h +124 -0
- package/ios/Core/RJConstants.m +88 -0
- package/ios/Core/RJLifecycleManager.h +85 -0
- package/ios/Core/RJLifecycleManager.m +308 -0
- package/ios/Core/RJLogger.h +61 -0
- package/ios/Core/RJLogger.m +211 -0
- package/ios/Core/RJTypes.h +176 -0
- package/ios/Core/RJTypes.m +66 -0
- package/ios/Core/Rejourney.h +64 -0
- package/ios/Core/Rejourney.mm +2495 -0
- package/ios/Network/RJDeviceAuthManager.h +94 -0
- package/ios/Network/RJDeviceAuthManager.m +967 -0
- package/ios/Network/RJNetworkMonitor.h +68 -0
- package/ios/Network/RJNetworkMonitor.m +267 -0
- package/ios/Network/RJRetryManager.h +73 -0
- package/ios/Network/RJRetryManager.m +325 -0
- package/ios/Network/RJUploadManager.h +267 -0
- package/ios/Network/RJUploadManager.m +2296 -0
- package/ios/Privacy/RJPrivacyMask.h +163 -0
- package/ios/Privacy/RJPrivacyMask.m +922 -0
- package/ios/Rejourney.h +63 -0
- package/ios/Touch/RJGestureClassifier.h +130 -0
- package/ios/Touch/RJGestureClassifier.m +333 -0
- package/ios/Touch/RJTouchInterceptor.h +169 -0
- package/ios/Touch/RJTouchInterceptor.m +772 -0
- package/ios/Utils/RJEventBuffer.h +112 -0
- package/ios/Utils/RJEventBuffer.m +358 -0
- package/ios/Utils/RJGzipUtils.h +33 -0
- package/ios/Utils/RJGzipUtils.m +89 -0
- package/ios/Utils/RJKeychainManager.h +48 -0
- package/ios/Utils/RJKeychainManager.m +111 -0
- package/ios/Utils/RJPerfTiming.h +209 -0
- package/ios/Utils/RJPerfTiming.m +264 -0
- package/ios/Utils/RJTelemetry.h +92 -0
- package/ios/Utils/RJTelemetry.m +320 -0
- package/ios/Utils/RJWindowUtils.h +66 -0
- package/ios/Utils/RJWindowUtils.m +133 -0
- package/lib/commonjs/NativeRejourney.js +40 -0
- package/lib/commonjs/components/Mask.js +79 -0
- package/lib/commonjs/index.js +1381 -0
- package/lib/commonjs/sdk/autoTracking.js +1259 -0
- package/lib/commonjs/sdk/constants.js +151 -0
- package/lib/commonjs/sdk/errorTracking.js +199 -0
- package/lib/commonjs/sdk/index.js +50 -0
- package/lib/commonjs/sdk/metricsTracking.js +204 -0
- package/lib/commonjs/sdk/navigation.js +151 -0
- package/lib/commonjs/sdk/networkInterceptor.js +412 -0
- package/lib/commonjs/sdk/utils.js +363 -0
- package/lib/commonjs/types/expo-router.d.js +2 -0
- package/lib/commonjs/types/index.js +2 -0
- package/lib/module/NativeRejourney.js +38 -0
- package/lib/module/components/Mask.js +72 -0
- package/lib/module/index.js +1284 -0
- package/lib/module/sdk/autoTracking.js +1233 -0
- package/lib/module/sdk/constants.js +145 -0
- package/lib/module/sdk/errorTracking.js +189 -0
- package/lib/module/sdk/index.js +12 -0
- package/lib/module/sdk/metricsTracking.js +187 -0
- package/lib/module/sdk/navigation.js +143 -0
- package/lib/module/sdk/networkInterceptor.js +401 -0
- package/lib/module/sdk/utils.js +342 -0
- package/lib/module/types/expo-router.d.js +2 -0
- package/lib/module/types/index.js +2 -0
- package/lib/typescript/NativeRejourney.d.ts +147 -0
- package/lib/typescript/components/Mask.d.ts +39 -0
- package/lib/typescript/index.d.ts +117 -0
- package/lib/typescript/sdk/autoTracking.d.ts +204 -0
- package/lib/typescript/sdk/constants.d.ts +120 -0
- package/lib/typescript/sdk/errorTracking.d.ts +32 -0
- package/lib/typescript/sdk/index.d.ts +9 -0
- package/lib/typescript/sdk/metricsTracking.d.ts +58 -0
- package/lib/typescript/sdk/navigation.d.ts +33 -0
- package/lib/typescript/sdk/networkInterceptor.d.ts +47 -0
- package/lib/typescript/sdk/utils.d.ts +148 -0
- package/lib/typescript/types/index.d.ts +624 -0
- package/package.json +102 -0
- package/rejourney.podspec +21 -0
- package/src/NativeRejourney.ts +165 -0
- package/src/components/Mask.tsx +80 -0
- package/src/index.ts +1459 -0
- package/src/sdk/autoTracking.ts +1373 -0
- package/src/sdk/constants.ts +134 -0
- package/src/sdk/errorTracking.ts +231 -0
- package/src/sdk/index.ts +11 -0
- package/src/sdk/metricsTracking.ts +232 -0
- package/src/sdk/navigation.ts +157 -0
- package/src/sdk/networkInterceptor.ts +440 -0
- package/src/sdk/utils.ts +369 -0
- package/src/types/expo-router.d.ts +7 -0
- package/src/types/index.ts +739 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJKeychainManager.m
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// Secure Keychain storage implementation.
|
|
6
|
+
//
|
|
7
|
+
// Copyright (c) 2026 Rejourney
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
#import "RJKeychainManager.h"
|
|
11
|
+
#import "../Core/RJLogger.h"
|
|
12
|
+
#import <Security/Security.h>
|
|
13
|
+
|
|
14
|
+
static NSString *const kRJKeychainServiceName = @"com.rejourney.sdk";
|
|
15
|
+
|
|
16
|
+
@implementation RJKeychainManager
|
|
17
|
+
|
|
18
|
+
#pragma mark - Singleton
|
|
19
|
+
|
|
20
|
+
+ (instancetype)sharedManager {
|
|
21
|
+
static RJKeychainManager *instance = nil;
|
|
22
|
+
static dispatch_once_t onceToken;
|
|
23
|
+
dispatch_once(&onceToken, ^{
|
|
24
|
+
instance = [[self alloc] init];
|
|
25
|
+
});
|
|
26
|
+
return instance;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#pragma mark - Query Building
|
|
30
|
+
|
|
31
|
+
- (NSMutableDictionary *)baseQueryForKey:(NSString *)key {
|
|
32
|
+
return [@{
|
|
33
|
+
(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
|
|
34
|
+
(__bridge id)kSecAttrService : kRJKeychainServiceName,
|
|
35
|
+
(__bridge id)kSecAttrAccount : key,
|
|
36
|
+
(__bridge id)kSecAttrAccessible :
|
|
37
|
+
(__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
|
38
|
+
} mutableCopy];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#pragma mark - Storage Operations
|
|
42
|
+
|
|
43
|
+
- (BOOL)setString:(NSString *)value forKey:(NSString *)key {
|
|
44
|
+
if (!value || !key)
|
|
45
|
+
return NO;
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
[self deleteValueForKey:key];
|
|
49
|
+
|
|
50
|
+
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
|
|
51
|
+
if (!valueData)
|
|
52
|
+
return NO;
|
|
53
|
+
|
|
54
|
+
NSMutableDictionary *query = [self baseQueryForKey:key];
|
|
55
|
+
query[(__bridge id)kSecValueData] = valueData;
|
|
56
|
+
|
|
57
|
+
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
|
|
58
|
+
|
|
59
|
+
if (status == errSecSuccess) {
|
|
60
|
+
RJLogDebug(@"Keychain: Stored value for key '%@'", key);
|
|
61
|
+
return YES;
|
|
62
|
+
} else {
|
|
63
|
+
RJLogWarning(@"Keychain: Failed to store value for key '%@' (status: %d)",
|
|
64
|
+
key, (int)status);
|
|
65
|
+
return NO;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
- (nullable NSString *)stringForKey:(NSString *)key {
|
|
70
|
+
if (!key)
|
|
71
|
+
return nil;
|
|
72
|
+
|
|
73
|
+
NSMutableDictionary *query = [self baseQueryForKey:key];
|
|
74
|
+
query[(__bridge id)kSecReturnData] = @YES;
|
|
75
|
+
query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
|
|
76
|
+
|
|
77
|
+
CFDataRef dataRef = NULL;
|
|
78
|
+
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query,
|
|
79
|
+
(CFTypeRef *)&dataRef);
|
|
80
|
+
|
|
81
|
+
if (status == errSecSuccess && dataRef) {
|
|
82
|
+
NSData *data = (__bridge_transfer NSData *)dataRef;
|
|
83
|
+
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return nil;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
- (BOOL)deleteValueForKey:(NSString *)key {
|
|
90
|
+
if (!key)
|
|
91
|
+
return NO;
|
|
92
|
+
|
|
93
|
+
NSMutableDictionary *query = [self baseQueryForKey:key];
|
|
94
|
+
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
|
|
95
|
+
|
|
96
|
+
return status == errSecSuccess || status == errSecItemNotFound;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
- (void)clearAll {
|
|
100
|
+
NSDictionary *query = @{
|
|
101
|
+
(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
|
|
102
|
+
(__bridge id)kSecAttrService : kRJKeychainServiceName
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
|
|
106
|
+
if (status == errSecSuccess) {
|
|
107
|
+
RJLogDebug(@"Keychain: Cleared all Rejourney items");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@end
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJPerfTiming.h
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// Wall-clock CPU timing using mach_absolute_time() with in-memory aggregation.
|
|
6
|
+
// Provides µs-level timing for internal SDK performance validation.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// - Enable by defining RJ_PERF=1 at compile time
|
|
10
|
+
// - Accumulates metrics in-memory, dumps periodically (every 5s or 100 frames)
|
|
11
|
+
// - Extremely low overhead (~20-30ns per timing call)
|
|
12
|
+
// - Works in release builds
|
|
13
|
+
//
|
|
14
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
|
+
// you may not use this file except in compliance with the License.
|
|
16
|
+
// You may obtain a copy of the License at
|
|
17
|
+
//
|
|
18
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
19
|
+
//
|
|
20
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
21
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
22
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
23
|
+
// See the License for the specific language governing permissions and
|
|
24
|
+
// limitations under the License.
|
|
25
|
+
//
|
|
26
|
+
// Copyright (c) 2026 Rejourney
|
|
27
|
+
//
|
|
28
|
+
|
|
29
|
+
#import <Foundation/Foundation.h>
|
|
30
|
+
|
|
31
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// COMPILE-TIME SWITCH
|
|
35
|
+
// Define RJ_PERF=1 in your build settings to enable performance timing
|
|
36
|
+
// Ship production with RJ_PERF=0 or undefined
|
|
37
|
+
// ============================================================================
|
|
38
|
+
#ifndef RJ_PERF
|
|
39
|
+
// Force enable for testing - change to 0 for production
|
|
40
|
+
#define RJ_PERF 1
|
|
41
|
+
#endif
|
|
42
|
+
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// TIMING MACROS (zero-cost when disabled)
|
|
45
|
+
// ============================================================================
|
|
46
|
+
#if RJ_PERF
|
|
47
|
+
|
|
48
|
+
/// Start timing a section. Call at the beginning of the code block to time.
|
|
49
|
+
#define RJ_TIME_START uint64_t __rj_t0 = rj_perf_now()
|
|
50
|
+
|
|
51
|
+
/// End timing and accumulate to the specified metric.
|
|
52
|
+
/// @param metric One of: RJPerfMetricFrame, RJPerfMetricScreenshot, etc.
|
|
53
|
+
#define RJ_TIME_END(metric) rj_perf_record(metric, __rj_t0, rj_perf_now())
|
|
54
|
+
|
|
55
|
+
/// Start timing with a custom variable name (for nested timing).
|
|
56
|
+
#define RJ_TIME_START_NAMED(name) uint64_t __rj_t0_##name = rj_perf_now()
|
|
57
|
+
|
|
58
|
+
/// End timing with a custom variable name.
|
|
59
|
+
#define RJ_TIME_END_NAMED(name, metric) \
|
|
60
|
+
rj_perf_record(metric, __rj_t0_##name, rj_perf_now())
|
|
61
|
+
|
|
62
|
+
/// Dump metrics if enough time has passed (call periodically from main loop).
|
|
63
|
+
#define RJ_PERF_DUMP_IF_NEEDED() rj_perf_dump_if_needed()
|
|
64
|
+
|
|
65
|
+
/// Force dump metrics immediately.
|
|
66
|
+
#define RJ_PERF_DUMP() rj_perf_dump()
|
|
67
|
+
|
|
68
|
+
/// Reset all metrics.
|
|
69
|
+
#define RJ_PERF_RESET() rj_perf_reset()
|
|
70
|
+
|
|
71
|
+
#else
|
|
72
|
+
|
|
73
|
+
// No-op when disabled
|
|
74
|
+
#define RJ_TIME_START
|
|
75
|
+
#define RJ_TIME_END(metric)
|
|
76
|
+
#define RJ_TIME_START_NAMED(name)
|
|
77
|
+
#define RJ_TIME_END_NAMED(name, metric)
|
|
78
|
+
#define RJ_PERF_DUMP_IF_NEEDED()
|
|
79
|
+
#define RJ_PERF_DUMP()
|
|
80
|
+
#define RJ_PERF_RESET()
|
|
81
|
+
|
|
82
|
+
#endif
|
|
83
|
+
|
|
84
|
+
// ============================================================================
|
|
85
|
+
// METRIC TYPES
|
|
86
|
+
// ============================================================================
|
|
87
|
+
|
|
88
|
+
/// Performance metrics that can be tracked.
|
|
89
|
+
typedef NS_ENUM(NSInteger, RJPerfMetric) {
|
|
90
|
+
/// Total frame processing time (screenshot + encode + upload)
|
|
91
|
+
RJPerfMetricFrame = 0,
|
|
92
|
+
|
|
93
|
+
/// Screenshot capture time (UIGraphics rendering)
|
|
94
|
+
RJPerfMetricScreenshot,
|
|
95
|
+
|
|
96
|
+
/// Raw Core Animation/Graphics rendering time (layer.render or
|
|
97
|
+
/// drawViewHierarchy)
|
|
98
|
+
RJPerfMetricRender,
|
|
99
|
+
|
|
100
|
+
/// Privacy mask drawing time
|
|
101
|
+
RJPerfMetricPrivacyMask,
|
|
102
|
+
|
|
103
|
+
/// View hierarchy scanning time
|
|
104
|
+
RJPerfMetricViewScan,
|
|
105
|
+
|
|
106
|
+
/// View hierarchy serialization time
|
|
107
|
+
RJPerfMetricViewSerialize,
|
|
108
|
+
|
|
109
|
+
/// Video encoding time (H.264 compression)
|
|
110
|
+
RJPerfMetricEncode,
|
|
111
|
+
|
|
112
|
+
/// Pixel buffer creation time (UIImage -> CVPixelBuffer)
|
|
113
|
+
RJPerfMetricPixelBuffer,
|
|
114
|
+
|
|
115
|
+
/// Downscaling time (vImage)
|
|
116
|
+
RJPerfMetricDownscale,
|
|
117
|
+
|
|
118
|
+
/// Buffer allocation time (CVPixelBufferPool)
|
|
119
|
+
RJPerfMetricBufferAlloc,
|
|
120
|
+
|
|
121
|
+
/// Encoder append time (pixel buffer -> H.264)
|
|
122
|
+
RJPerfMetricEncodeAppend,
|
|
123
|
+
|
|
124
|
+
/// Segment upload time (network)
|
|
125
|
+
RJPerfMetricUpload,
|
|
126
|
+
|
|
127
|
+
/// Number of metric types (keep last)
|
|
128
|
+
RJPerfMetricCount
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// ============================================================================
|
|
132
|
+
// C INTERFACE (for maximum performance)
|
|
133
|
+
// ============================================================================
|
|
134
|
+
|
|
135
|
+
#if RJ_PERF
|
|
136
|
+
|
|
137
|
+
/// Get current timestamp (mach_absolute_time).
|
|
138
|
+
FOUNDATION_EXPORT uint64_t rj_perf_now(void);
|
|
139
|
+
|
|
140
|
+
/// Record a timing measurement.
|
|
141
|
+
/// @param metric The metric to record to
|
|
142
|
+
/// @param start Start timestamp from rj_perf_now()
|
|
143
|
+
/// @param end End timestamp from rj_perf_now()
|
|
144
|
+
FOUNDATION_EXPORT void rj_perf_record(RJPerfMetric metric, uint64_t start,
|
|
145
|
+
uint64_t end);
|
|
146
|
+
|
|
147
|
+
/// Dump metrics if more than 5 seconds have passed since last dump.
|
|
148
|
+
FOUNDATION_EXPORT void rj_perf_dump_if_needed(void);
|
|
149
|
+
|
|
150
|
+
/// Force dump metrics immediately.
|
|
151
|
+
FOUNDATION_EXPORT void rj_perf_dump(void);
|
|
152
|
+
|
|
153
|
+
/// Reset all accumulated metrics.
|
|
154
|
+
FOUNDATION_EXPORT void rj_perf_reset(void);
|
|
155
|
+
|
|
156
|
+
/// Get a snapshot of current metrics (for programmatic access).
|
|
157
|
+
/// Returns dictionary with avg/max/count for each metric.
|
|
158
|
+
FOUNDATION_EXPORT
|
|
159
|
+
NSDictionary<NSString *, NSDictionary<NSString *, NSNumber *> *> *
|
|
160
|
+
rj_perf_snapshot(void);
|
|
161
|
+
|
|
162
|
+
#endif
|
|
163
|
+
|
|
164
|
+
// ============================================================================
|
|
165
|
+
// OBJECTIVE-C INTERFACE (for convenience)
|
|
166
|
+
// ============================================================================
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* RJPerfTiming provides wall-clock CPU timing with in-memory aggregation.
|
|
170
|
+
*
|
|
171
|
+
* This class is a thin wrapper around the C functions for ObjC convenience.
|
|
172
|
+
* For hot paths, use the C macros directly for best performance.
|
|
173
|
+
*
|
|
174
|
+
* ## Example Usage
|
|
175
|
+
*
|
|
176
|
+
* ```objc
|
|
177
|
+
* // In a hot loop:
|
|
178
|
+
* RJ_TIME_START;
|
|
179
|
+
* [self doExpensiveWork];
|
|
180
|
+
* RJ_TIME_END(RJPerfMetricFrame);
|
|
181
|
+
*
|
|
182
|
+
* // Periodically (e.g., in capture timer):
|
|
183
|
+
* RJ_PERF_DUMP_IF_NEEDED();
|
|
184
|
+
*
|
|
185
|
+
* // Or get metrics programmatically:
|
|
186
|
+
* NSDictionary *metrics = [RJPerfTiming snapshot];
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
@interface RJPerfTiming : NSObject
|
|
190
|
+
|
|
191
|
+
/// Whether performance timing is enabled (compile-time).
|
|
192
|
+
+ (BOOL)isEnabled;
|
|
193
|
+
|
|
194
|
+
/// Get current metrics snapshot.
|
|
195
|
+
+ (nullable NSDictionary<NSString *, NSDictionary<NSString *, NSNumber *> *> *)
|
|
196
|
+
snapshot;
|
|
197
|
+
|
|
198
|
+
/// Force dump metrics to console.
|
|
199
|
+
+ (void)dump;
|
|
200
|
+
|
|
201
|
+
/// Reset all metrics.
|
|
202
|
+
+ (void)reset;
|
|
203
|
+
|
|
204
|
+
/// Get human-readable name for a metric.
|
|
205
|
+
+ (NSString *)nameForMetric:(RJPerfMetric)metric;
|
|
206
|
+
|
|
207
|
+
@end
|
|
208
|
+
|
|
209
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJPerfTiming.m
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// Wall-clock CPU timing implementation using mach_absolute_time().
|
|
6
|
+
//
|
|
7
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
// you may not use this file except in compliance with the License.
|
|
9
|
+
// You may obtain a copy of the License at
|
|
10
|
+
//
|
|
11
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
//
|
|
13
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
// See the License for the specific language governing permissions and
|
|
17
|
+
// limitations under the License.
|
|
18
|
+
//
|
|
19
|
+
// Copyright (c) 2026 Rejourney
|
|
20
|
+
//
|
|
21
|
+
|
|
22
|
+
#import "RJPerfTiming.h"
|
|
23
|
+
#import "../Core/RJLogger.h"
|
|
24
|
+
#import <mach/mach_time.h>
|
|
25
|
+
#import <os/lock.h>
|
|
26
|
+
|
|
27
|
+
#if RJ_PERF
|
|
28
|
+
|
|
29
|
+
static mach_timebase_info_data_t rj_timebase;
|
|
30
|
+
|
|
31
|
+
static BOOL rj_perf_initialized = NO;
|
|
32
|
+
|
|
33
|
+
__attribute__((constructor)) static void RJPerfTimingInit(void) {
|
|
34
|
+
mach_timebase_info(&rj_timebase);
|
|
35
|
+
rj_perf_initialized = YES;
|
|
36
|
+
RJLogInfo(@"[Rejourney PERF] ✅ Performance timing initialized (RJ_PERF=1)");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static inline double rj_ms(uint64_t start, uint64_t end) {
|
|
40
|
+
return (double)(end - start) * rj_timebase.numer / rj_timebase.denom /
|
|
41
|
+
1000000.0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static const char *const rj_metric_names[] = {
|
|
45
|
+
"frame_total", "screenshot_ui", "render_draw", "privacy_mask",
|
|
46
|
+
"view_scan", "view_serialize", "encode_h264", "pixel_buffer",
|
|
47
|
+
"downscale", "buffer_alloc", "encode_append", "upload_net"};
|
|
48
|
+
|
|
49
|
+
static double rj_totals[RJPerfMetricCount] = {0};
|
|
50
|
+
|
|
51
|
+
static double rj_maxes[RJPerfMetricCount] = {0};
|
|
52
|
+
|
|
53
|
+
static uint64_t rj_counts[RJPerfMetricCount] = {0};
|
|
54
|
+
|
|
55
|
+
static uint64_t rj_last_dump = 0;
|
|
56
|
+
|
|
57
|
+
static const double RJ_DUMP_INTERVAL_MS = 5000.0; // 5s
|
|
58
|
+
|
|
59
|
+
static const uint64_t RJ_MIN_SAMPLES = 5;
|
|
60
|
+
|
|
61
|
+
static os_unfair_lock rj_perf_lock = OS_UNFAIR_LOCK_INIT;
|
|
62
|
+
|
|
63
|
+
uint64_t rj_perf_now(void) { return mach_absolute_time(); }
|
|
64
|
+
|
|
65
|
+
void rj_perf_record(RJPerfMetric metric, uint64_t start, uint64_t end) {
|
|
66
|
+
if (metric < 0 || metric >= RJPerfMetricCount)
|
|
67
|
+
return;
|
|
68
|
+
|
|
69
|
+
double ms = rj_ms(start, end);
|
|
70
|
+
|
|
71
|
+
// IMMEDIATE LOGGING (Request by user)
|
|
72
|
+
// Pinpoints main thread blockers
|
|
73
|
+
BOOL isMain = [NSThread isMainThread];
|
|
74
|
+
const char *threadName = isMain ? "MAIN" : "BG";
|
|
75
|
+
|
|
76
|
+
// Log critical main thread hitches (> 4ms) visibly
|
|
77
|
+
// Or just log everything as requested ("intense logging")
|
|
78
|
+
// Using specific emoji to highlight potential issues
|
|
79
|
+
if (isMain && ms > 4.0) {
|
|
80
|
+
RJLogInfo(@"[RJ-PERF] ⚠️ [%s] %s: %.2fms", threadName, rj_metric_names[metric],
|
|
81
|
+
ms);
|
|
82
|
+
} else {
|
|
83
|
+
RJLogInfo(@"[RJ-PERF] [%s] %s: %.2fms", threadName, rj_metric_names[metric],
|
|
84
|
+
ms);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
os_unfair_lock_lock(&rj_perf_lock);
|
|
88
|
+
rj_counts[metric]++;
|
|
89
|
+
rj_totals[metric] += ms;
|
|
90
|
+
if (ms > rj_maxes[metric]) {
|
|
91
|
+
rj_maxes[metric] = ms;
|
|
92
|
+
}
|
|
93
|
+
os_unfair_lock_unlock(&rj_perf_lock);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
void rj_perf_dump_if_needed(void) {
|
|
97
|
+
uint64_t now = rj_perf_now();
|
|
98
|
+
|
|
99
|
+
if (rj_last_dump != 0 && rj_ms(rj_last_dump, now) < RJ_DUMP_INTERVAL_MS) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
os_unfair_lock_lock(&rj_perf_lock);
|
|
104
|
+
|
|
105
|
+
if (rj_last_dump != 0 && rj_ms(rj_last_dump, now) < RJ_DUMP_INTERVAL_MS) {
|
|
106
|
+
os_unfair_lock_unlock(&rj_perf_lock);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
uint64_t total_samples = 0;
|
|
111
|
+
for (int i = 0; i < RJPerfMetricCount; i++) {
|
|
112
|
+
total_samples += rj_counts[i];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (total_samples < RJ_MIN_SAMPLES) {
|
|
116
|
+
os_unfair_lock_unlock(&rj_perf_lock);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
rj_last_dump = now;
|
|
121
|
+
|
|
122
|
+
NSMutableString *log =
|
|
123
|
+
[NSMutableString stringWithString:@"[Rejourney PERF SUMMARY]"];
|
|
124
|
+
|
|
125
|
+
for (int i = 0; i < RJPerfMetricCount; i++) {
|
|
126
|
+
if (rj_counts[i] > 0) {
|
|
127
|
+
double avg = rj_totals[i] / rj_counts[i];
|
|
128
|
+
[log appendFormat:@" %s=%llu/%.1f/%.1fms", rj_metric_names[i],
|
|
129
|
+
(unsigned long long)rj_counts[i], avg, rj_maxes[i]];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
os_unfair_lock_unlock(&rj_perf_lock);
|
|
134
|
+
|
|
135
|
+
RJLogInfo(@"%@", log);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
void rj_perf_dump(void) {
|
|
139
|
+
os_unfair_lock_lock(&rj_perf_lock);
|
|
140
|
+
|
|
141
|
+
uint64_t total_samples = 0;
|
|
142
|
+
for (int i = 0; i < RJPerfMetricCount; i++) {
|
|
143
|
+
total_samples += rj_counts[i];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (total_samples == 0) {
|
|
147
|
+
os_unfair_lock_unlock(&rj_perf_lock);
|
|
148
|
+
RJLogInfo(@"[Rejourney PERF] No samples collected");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
NSMutableString *log = [NSMutableString stringWithString:@"\n"];
|
|
153
|
+
[log appendString:@"╔════════════════════════════════════════════════════════"
|
|
154
|
+
@"══════╗\n"];
|
|
155
|
+
[log appendString:@"║ REJOURNEY SDK PERFORMANCE METRICS (ms) "
|
|
156
|
+
@" ║\n"];
|
|
157
|
+
[log appendString:@"╠════════════════════════════════════════════════════════"
|
|
158
|
+
@"══════╣\n"];
|
|
159
|
+
[log appendFormat:@"║ %-16s │ %8s │ %10s │ %10s ║\n", "METRIC", "COUNT",
|
|
160
|
+
"AVG (ms)", "MAX (ms)"];
|
|
161
|
+
[log appendString:@"╠════════════════════════════════════════════════════════"
|
|
162
|
+
@"══════╣\n"];
|
|
163
|
+
|
|
164
|
+
for (int i = 0; i < RJPerfMetricCount; i++) {
|
|
165
|
+
if (rj_counts[i] > 0) {
|
|
166
|
+
double avg = rj_totals[i] / rj_counts[i];
|
|
167
|
+
[log appendFormat:@"║ %-16s │ %8llu │ %10.2f │ %10.2f ║\n",
|
|
168
|
+
rj_metric_names[i], (unsigned long long)rj_counts[i],
|
|
169
|
+
avg, rj_maxes[i]];
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
[log appendString:
|
|
174
|
+
@"╚══════════════════════════════════════════════════════════════╝"];
|
|
175
|
+
|
|
176
|
+
rj_last_dump = rj_perf_now();
|
|
177
|
+
|
|
178
|
+
os_unfair_lock_unlock(&rj_perf_lock);
|
|
179
|
+
|
|
180
|
+
RJLogInfo(@"%@", log);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
void rj_perf_reset(void) {
|
|
184
|
+
os_unfair_lock_lock(&rj_perf_lock);
|
|
185
|
+
|
|
186
|
+
for (int i = 0; i < RJPerfMetricCount; i++) {
|
|
187
|
+
rj_totals[i] = 0;
|
|
188
|
+
rj_maxes[i] = 0;
|
|
189
|
+
rj_counts[i] = 0;
|
|
190
|
+
}
|
|
191
|
+
rj_last_dump = 0;
|
|
192
|
+
|
|
193
|
+
os_unfair_lock_unlock(&rj_perf_lock);
|
|
194
|
+
|
|
195
|
+
RJLogInfo(@"[Rejourney PERF] Metrics reset");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
NSDictionary<NSString *, NSDictionary<NSString *, NSNumber *> *> *
|
|
199
|
+
rj_perf_snapshot(void) {
|
|
200
|
+
NSMutableDictionary *result = [NSMutableDictionary dictionary];
|
|
201
|
+
|
|
202
|
+
os_unfair_lock_lock(&rj_perf_lock);
|
|
203
|
+
|
|
204
|
+
for (int i = 0; i < RJPerfMetricCount; i++) {
|
|
205
|
+
if (rj_counts[i] > 0) {
|
|
206
|
+
NSString *name = [NSString stringWithUTF8String:rj_metric_names[i]];
|
|
207
|
+
double avg = rj_totals[i] / rj_counts[i];
|
|
208
|
+
|
|
209
|
+
result[name] = @{
|
|
210
|
+
@"count" : @(rj_counts[i]),
|
|
211
|
+
@"avg_us" : @(avg),
|
|
212
|
+
@"max_us" : @(rj_maxes[i]),
|
|
213
|
+
@"total_us" : @(rj_totals[i])
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
os_unfair_lock_unlock(&rj_perf_lock);
|
|
219
|
+
|
|
220
|
+
return [result copy];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
#endif
|
|
224
|
+
|
|
225
|
+
@implementation RJPerfTiming
|
|
226
|
+
|
|
227
|
+
+ (BOOL)isEnabled {
|
|
228
|
+
#if RJ_PERF
|
|
229
|
+
return YES;
|
|
230
|
+
#else
|
|
231
|
+
return NO;
|
|
232
|
+
#endif
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
+ (NSDictionary<NSString *, NSDictionary<NSString *, NSNumber *> *> *)snapshot {
|
|
236
|
+
#if RJ_PERF
|
|
237
|
+
return rj_perf_snapshot();
|
|
238
|
+
#else
|
|
239
|
+
return nil;
|
|
240
|
+
#endif
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
+ (void)dump {
|
|
244
|
+
#if RJ_PERF
|
|
245
|
+
rj_perf_dump();
|
|
246
|
+
#endif
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
+ (void)reset {
|
|
250
|
+
#if RJ_PERF
|
|
251
|
+
rj_perf_reset();
|
|
252
|
+
#endif
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
+ (NSString *)nameForMetric:(RJPerfMetric)metric {
|
|
256
|
+
#if RJ_PERF
|
|
257
|
+
if (metric >= 0 && metric < RJPerfMetricCount) {
|
|
258
|
+
return [NSString stringWithUTF8String:rj_metric_names[metric]];
|
|
259
|
+
}
|
|
260
|
+
#endif
|
|
261
|
+
return @"unknown";
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJTelemetry.h
|
|
3
|
+
// Rejourney SDK Telemetry
|
|
4
|
+
//
|
|
5
|
+
// Provides observability metrics for SDK health monitoring.
|
|
6
|
+
// Tracks upload success rates, retry counts, circuit breaker events, and memory
|
|
7
|
+
// pressure.
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
#import <Foundation/Foundation.h>
|
|
11
|
+
|
|
12
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
13
|
+
|
|
14
|
+
/// Telemetry event types
|
|
15
|
+
typedef NS_ENUM(NSInteger, RJTelemetryEventType) {
|
|
16
|
+
RJTelemetryEventUploadSuccess,
|
|
17
|
+
RJTelemetryEventUploadFailure,
|
|
18
|
+
RJTelemetryEventRetryAttempt,
|
|
19
|
+
RJTelemetryEventCircuitBreakerOpen,
|
|
20
|
+
RJTelemetryEventCircuitBreakerClose,
|
|
21
|
+
RJTelemetryEventMemoryPressureEviction,
|
|
22
|
+
RJTelemetryEventOfflineQueuePersist,
|
|
23
|
+
RJTelemetryEventOfflineQueueRestore,
|
|
24
|
+
RJTelemetryEventSessionStart,
|
|
25
|
+
RJTelemetryEventSessionEnd,
|
|
26
|
+
RJTelemetryEventCrashDetected,
|
|
27
|
+
RJTelemetryEventTokenRefresh,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/// SDK health metrics snapshot
|
|
31
|
+
@interface RJTelemetryMetrics : NSObject
|
|
32
|
+
|
|
33
|
+
@property(nonatomic, assign, readonly) NSInteger uploadSuccessCount;
|
|
34
|
+
@property(nonatomic, assign, readonly) NSInteger uploadFailureCount;
|
|
35
|
+
@property(nonatomic, assign, readonly) NSInteger retryAttemptCount;
|
|
36
|
+
@property(nonatomic, assign, readonly) NSInteger circuitBreakerOpenCount;
|
|
37
|
+
@property(nonatomic, assign, readonly) NSInteger memoryEvictionCount;
|
|
38
|
+
@property(nonatomic, assign, readonly) NSInteger offlinePersistCount;
|
|
39
|
+
@property(nonatomic, assign, readonly) NSInteger sessionStartCount;
|
|
40
|
+
@property(nonatomic, assign, readonly) NSInteger crashCount;
|
|
41
|
+
@property(nonatomic, assign, readonly) NSInteger anrCount;
|
|
42
|
+
@property(nonatomic, assign, readonly) double uploadSuccessRate;
|
|
43
|
+
@property(nonatomic, assign, readonly) NSTimeInterval avgUploadDurationMs;
|
|
44
|
+
@property(nonatomic, assign, readonly) NSInteger currentQueueDepth;
|
|
45
|
+
@property(nonatomic, strong, readonly) NSDate *lastUploadTime;
|
|
46
|
+
@property(nonatomic, strong, readonly) NSDate *lastRetryTime;
|
|
47
|
+
|
|
48
|
+
@end
|
|
49
|
+
|
|
50
|
+
/// Telemetry collector for SDK observability
|
|
51
|
+
@interface RJTelemetry : NSObject
|
|
52
|
+
|
|
53
|
+
/// Shared instance
|
|
54
|
+
+ (instancetype)sharedInstance;
|
|
55
|
+
|
|
56
|
+
/// Record a telemetry event
|
|
57
|
+
- (void)recordEvent:(RJTelemetryEventType)eventType;
|
|
58
|
+
|
|
59
|
+
/// Record an event with additional context
|
|
60
|
+
- (void)recordEvent:(RJTelemetryEventType)eventType
|
|
61
|
+
metadata:(nullable NSDictionary<NSString *, id> *)metadata;
|
|
62
|
+
|
|
63
|
+
/// Record upload duration for latency tracking
|
|
64
|
+
- (void)recordUploadDuration:(NSTimeInterval)durationMs
|
|
65
|
+
success:(BOOL)success
|
|
66
|
+
byteCount:(NSUInteger)bytes;
|
|
67
|
+
|
|
68
|
+
/// Record memory pressure eviction
|
|
69
|
+
- (void)recordFrameEviction:(NSUInteger)bytesEvicted
|
|
70
|
+
frameCount:(NSInteger)count;
|
|
71
|
+
|
|
72
|
+
/// Record retry queue depth
|
|
73
|
+
- (void)recordQueueDepth:(NSInteger)depth;
|
|
74
|
+
|
|
75
|
+
/// Record an ANR event
|
|
76
|
+
- (void)recordANR;
|
|
77
|
+
|
|
78
|
+
/// Get current metrics snapshot
|
|
79
|
+
- (RJTelemetryMetrics *)currentMetrics;
|
|
80
|
+
|
|
81
|
+
/// Get metrics as dictionary for reporting
|
|
82
|
+
- (NSDictionary<NSString *, id> *)metricsAsDictionary;
|
|
83
|
+
|
|
84
|
+
/// Reset all metrics (typically on session end)
|
|
85
|
+
- (void)resetMetrics;
|
|
86
|
+
|
|
87
|
+
/// Export metrics to console for debugging (only in DEBUG builds)
|
|
88
|
+
- (void)logCurrentMetrics;
|
|
89
|
+
|
|
90
|
+
@end
|
|
91
|
+
|
|
92
|
+
NS_ASSUME_NONNULL_END
|