@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,183 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJMotionEvent.m
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// Motion event implementation.
|
|
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 "RJMotionEvent.h"
|
|
23
|
+
#import <math.h>
|
|
24
|
+
|
|
25
|
+
@implementation RJMotionEvent
|
|
26
|
+
|
|
27
|
+
#pragma mark - Computed Properties
|
|
28
|
+
|
|
29
|
+
- (NSTimeInterval)duration {
|
|
30
|
+
return self.t1 - self.t0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
- (CGFloat)distance {
|
|
34
|
+
return sqrt(self.dx * self.dx + self.dy * self.dy);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
- (CGFloat)averageVelocity {
|
|
38
|
+
NSTimeInterval dur = self.duration;
|
|
39
|
+
if (dur <= 0)
|
|
40
|
+
return 0;
|
|
41
|
+
return self.distance / (dur / 1000.0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
- (CGFloat)direction {
|
|
45
|
+
return atan2(self.dy, self.dx);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#pragma mark - Serialization
|
|
49
|
+
|
|
50
|
+
- (NSDictionary *)toDictionary {
|
|
51
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
52
|
+
|
|
53
|
+
dict[@"type"] = [RJMotionEvent motionTypeName:self.type];
|
|
54
|
+
dict[@"t0"] = @(self.t0);
|
|
55
|
+
dict[@"t1"] = @(self.t1);
|
|
56
|
+
dict[@"dx"] = @(self.dx);
|
|
57
|
+
dict[@"dy"] = @(self.dy);
|
|
58
|
+
dict[@"v0"] = @(self.v0);
|
|
59
|
+
dict[@"v1"] = @(self.v1);
|
|
60
|
+
dict[@"curve"] = [RJMotionEvent curveNameForType:self.curve];
|
|
61
|
+
dict[@"duration"] = @(self.duration);
|
|
62
|
+
dict[@"distance"] = @(self.distance);
|
|
63
|
+
|
|
64
|
+
if (self.targetId) {
|
|
65
|
+
dict[@"targetId"] = self.targetId;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return [dict copy];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
+ (instancetype)eventFromDictionary:(NSDictionary *)dict {
|
|
72
|
+
if (!dict || ![dict isKindOfClass:[NSDictionary class]]) {
|
|
73
|
+
return nil;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
RJMotionEvent *event = [[RJMotionEvent alloc] init];
|
|
77
|
+
|
|
78
|
+
NSString *typeName = dict[@"type"];
|
|
79
|
+
if (typeName) {
|
|
80
|
+
event.type = [RJMotionEvent motionTypeFromName:typeName];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
NSNumber *t0 = dict[@"t0"];
|
|
84
|
+
if (t0)
|
|
85
|
+
event.t0 = t0.doubleValue;
|
|
86
|
+
|
|
87
|
+
NSNumber *t1 = dict[@"t1"];
|
|
88
|
+
if (t1)
|
|
89
|
+
event.t1 = t1.doubleValue;
|
|
90
|
+
|
|
91
|
+
NSNumber *dx = dict[@"dx"];
|
|
92
|
+
if (dx)
|
|
93
|
+
event.dx = dx.doubleValue;
|
|
94
|
+
|
|
95
|
+
NSNumber *dy = dict[@"dy"];
|
|
96
|
+
if (dy)
|
|
97
|
+
event.dy = dy.doubleValue;
|
|
98
|
+
|
|
99
|
+
NSNumber *v0 = dict[@"v0"];
|
|
100
|
+
if (v0)
|
|
101
|
+
event.v0 = v0.doubleValue;
|
|
102
|
+
|
|
103
|
+
NSNumber *v1 = dict[@"v1"];
|
|
104
|
+
if (v1)
|
|
105
|
+
event.v1 = v1.doubleValue;
|
|
106
|
+
|
|
107
|
+
NSString *curveName = dict[@"curve"];
|
|
108
|
+
if (curveName) {
|
|
109
|
+
event.curve = [RJMotionEvent curveTypeFromName:curveName];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
event.targetId = dict[@"targetId"];
|
|
113
|
+
|
|
114
|
+
return event;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#pragma mark - Curve Helpers
|
|
118
|
+
|
|
119
|
+
+ (NSString *)curveNameForType:(RJMotionCurve)curve {
|
|
120
|
+
switch (curve) {
|
|
121
|
+
case RJMotionCurveLinear:
|
|
122
|
+
return @"linear";
|
|
123
|
+
case RJMotionCurveExponentialDecay:
|
|
124
|
+
return @"exponential_decay";
|
|
125
|
+
case RJMotionCurveEaseOut:
|
|
126
|
+
return @"ease_out";
|
|
127
|
+
case RJMotionCurveBounce:
|
|
128
|
+
return @"bounce";
|
|
129
|
+
case RJMotionCurveSpring:
|
|
130
|
+
return @"spring";
|
|
131
|
+
}
|
|
132
|
+
return @"linear";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
+ (RJMotionCurve)curveTypeFromName:(NSString *)name {
|
|
136
|
+
if ([name isEqualToString:@"exponential_decay"]) {
|
|
137
|
+
return RJMotionCurveExponentialDecay;
|
|
138
|
+
} else if ([name isEqualToString:@"ease_out"]) {
|
|
139
|
+
return RJMotionCurveEaseOut;
|
|
140
|
+
} else if ([name isEqualToString:@"bounce"]) {
|
|
141
|
+
return RJMotionCurveBounce;
|
|
142
|
+
} else if ([name isEqualToString:@"spring"]) {
|
|
143
|
+
return RJMotionCurveSpring;
|
|
144
|
+
}
|
|
145
|
+
return RJMotionCurveLinear;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
+ (NSString *)motionTypeName:(RJMotionType)type {
|
|
149
|
+
switch (type) {
|
|
150
|
+
case RJMotionTypeScroll:
|
|
151
|
+
return @"scroll";
|
|
152
|
+
case RJMotionTypePan:
|
|
153
|
+
return @"pan";
|
|
154
|
+
case RJMotionTypeSwipe:
|
|
155
|
+
return @"swipe";
|
|
156
|
+
case RJMotionTypeFling:
|
|
157
|
+
return @"fling";
|
|
158
|
+
}
|
|
159
|
+
return @"scroll";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
+ (RJMotionType)motionTypeFromName:(NSString *)name {
|
|
163
|
+
if ([name isEqualToString:@"pan"]) {
|
|
164
|
+
return RJMotionTypePan;
|
|
165
|
+
} else if ([name isEqualToString:@"swipe"]) {
|
|
166
|
+
return RJMotionTypeSwipe;
|
|
167
|
+
} else if ([name isEqualToString:@"fling"]) {
|
|
168
|
+
return RJMotionTypeFling;
|
|
169
|
+
}
|
|
170
|
+
return RJMotionTypeScroll;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#pragma mark - Instance Convenience Methods
|
|
174
|
+
|
|
175
|
+
- (NSString *)typeName {
|
|
176
|
+
return [RJMotionEvent motionTypeName:self.type];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
- (NSString *)curveName {
|
|
180
|
+
return [RJMotionEvent curveNameForType:self.curve];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJPerformanceManager.h
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// System performance monitoring and adaptive throttling.
|
|
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 "../Core/RJTypes.h"
|
|
23
|
+
#import <Foundation/Foundation.h>
|
|
24
|
+
|
|
25
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
26
|
+
|
|
27
|
+
// RJPerformanceLevel is defined in RJTypes.h
|
|
28
|
+
|
|
29
|
+
/// Delegate for performance level changes
|
|
30
|
+
@protocol RJPerformanceManagerDelegate <NSObject>
|
|
31
|
+
@optional
|
|
32
|
+
- (void)performanceManagerDidChangeLevel:(RJPerformanceLevel)level;
|
|
33
|
+
- (void)performanceManagerDidReceiveMemoryWarning;
|
|
34
|
+
@end
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Manages system performance monitoring including thermal state,
|
|
38
|
+
* battery level, and memory pressure.
|
|
39
|
+
*/
|
|
40
|
+
@interface RJPerformanceManager : NSObject
|
|
41
|
+
|
|
42
|
+
/// Current performance level based on system conditions
|
|
43
|
+
@property(nonatomic, readonly) RJPerformanceLevel currentLevel;
|
|
44
|
+
|
|
45
|
+
/// Delegate for performance events
|
|
46
|
+
@property(nonatomic, weak, nullable) id<RJPerformanceManagerDelegate> delegate;
|
|
47
|
+
|
|
48
|
+
/// Whether thermal throttling is enabled
|
|
49
|
+
@property(nonatomic, assign) BOOL thermalThrottleEnabled;
|
|
50
|
+
|
|
51
|
+
/// Whether battery-aware throttling is enabled
|
|
52
|
+
@property(nonatomic, assign) BOOL batteryAwareEnabled;
|
|
53
|
+
|
|
54
|
+
/// Shared instance
|
|
55
|
+
+ (instancetype)sharedManager;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Start monitoring system performance.
|
|
59
|
+
*/
|
|
60
|
+
- (void)startMonitoring;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Stop monitoring system performance.
|
|
64
|
+
*/
|
|
65
|
+
- (void)stopMonitoring;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Force a performance level update check.
|
|
69
|
+
*/
|
|
70
|
+
- (void)updatePerformanceLevel;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get current memory usage in bytes.
|
|
74
|
+
*/
|
|
75
|
+
- (NSUInteger)currentMemoryUsage;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Handle memory warning - clears caches and notifies delegate.
|
|
79
|
+
*/
|
|
80
|
+
- (void)handleMemoryWarning;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get current CPU usage as percentage (0.0-100.0).
|
|
84
|
+
* Returns -1 if unavailable.
|
|
85
|
+
*/
|
|
86
|
+
/**
|
|
87
|
+
* Get current CPU usage as percentage (0.0-100.0).
|
|
88
|
+
* Returns -1 if unavailable.
|
|
89
|
+
*/
|
|
90
|
+
- (float)currentCPUUsage;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Returns YES if CPU usage is considered high enough to skip expensive
|
|
94
|
+
* operations.
|
|
95
|
+
*/
|
|
96
|
+
@property(nonatomic, readonly) BOOL isCPUHigh;
|
|
97
|
+
|
|
98
|
+
@end
|
|
99
|
+
|
|
100
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJPerformanceManager.m
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// System performance monitoring and adaptive throttling implementation.
|
|
6
|
+
//
|
|
7
|
+
// Copyright (c) 2026 Rejourney
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
#import "RJPerformanceManager.h"
|
|
11
|
+
#import "../Core/RJConstants.h"
|
|
12
|
+
#import "../Core/RJLogger.h"
|
|
13
|
+
#import <UIKit/UIKit.h>
|
|
14
|
+
#import <mach/mach.h>
|
|
15
|
+
|
|
16
|
+
#pragma mark - Private Interface
|
|
17
|
+
|
|
18
|
+
@interface RJPerformanceManager ()
|
|
19
|
+
|
|
20
|
+
@property(nonatomic, assign) RJPerformanceLevel currentLevel;
|
|
21
|
+
|
|
22
|
+
@property(nonatomic, strong, nullable) dispatch_source_t memoryPressureSource;
|
|
23
|
+
|
|
24
|
+
@property(nonatomic, strong, nullable) NSTimer *cpuMonitorTimer;
|
|
25
|
+
|
|
26
|
+
@property(nonatomic, assign) float rollingCPUAverage;
|
|
27
|
+
|
|
28
|
+
@property(nonatomic, assign) NSInteger highCPUSampleCount;
|
|
29
|
+
|
|
30
|
+
@property(nonatomic, assign) BOOL isMonitoring;
|
|
31
|
+
|
|
32
|
+
@end
|
|
33
|
+
|
|
34
|
+
#pragma mark - Implementation
|
|
35
|
+
|
|
36
|
+
@implementation RJPerformanceManager
|
|
37
|
+
|
|
38
|
+
#pragma mark - Singleton
|
|
39
|
+
|
|
40
|
+
+ (instancetype)sharedManager {
|
|
41
|
+
static RJPerformanceManager *sharedInstance = nil;
|
|
42
|
+
static dispatch_once_t onceToken;
|
|
43
|
+
dispatch_once(&onceToken, ^{
|
|
44
|
+
sharedInstance = [[self alloc] init];
|
|
45
|
+
});
|
|
46
|
+
return sharedInstance;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#pragma mark - Initialization
|
|
50
|
+
|
|
51
|
+
- (instancetype)init {
|
|
52
|
+
self = [super init];
|
|
53
|
+
if (self) {
|
|
54
|
+
_currentLevel = RJPerformanceLevelNormal;
|
|
55
|
+
_thermalThrottleEnabled = YES;
|
|
56
|
+
_batteryAwareEnabled = YES;
|
|
57
|
+
_isMonitoring = NO;
|
|
58
|
+
_rollingCPUAverage = 0.0;
|
|
59
|
+
_highCPUSampleCount = 0;
|
|
60
|
+
}
|
|
61
|
+
return self;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
- (void)dealloc {
|
|
65
|
+
[self stopMonitoring];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
#pragma mark - Monitoring Lifecycle
|
|
69
|
+
|
|
70
|
+
- (void)startMonitoring {
|
|
71
|
+
if (self.isMonitoring)
|
|
72
|
+
return;
|
|
73
|
+
|
|
74
|
+
self.isMonitoring = YES;
|
|
75
|
+
|
|
76
|
+
[self setupMemoryPressureMonitoring];
|
|
77
|
+
|
|
78
|
+
[[NSNotificationCenter defaultCenter]
|
|
79
|
+
addObserver:self
|
|
80
|
+
selector:@selector(handleMemoryWarningNotification:)
|
|
81
|
+
name:UIApplicationDidReceiveMemoryWarningNotification
|
|
82
|
+
object:nil];
|
|
83
|
+
|
|
84
|
+
if (@available(iOS 11.0, *)) {
|
|
85
|
+
[[NSNotificationCenter defaultCenter]
|
|
86
|
+
addObserver:self
|
|
87
|
+
selector:@selector(handleThermalStateChange:)
|
|
88
|
+
name:NSProcessInfoThermalStateDidChangeNotification
|
|
89
|
+
object:nil];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
|
|
93
|
+
[[NSNotificationCenter defaultCenter]
|
|
94
|
+
addObserver:self
|
|
95
|
+
selector:@selector(handleBatteryStateChange:)
|
|
96
|
+
name:UIDeviceBatteryLevelDidChangeNotification
|
|
97
|
+
object:nil];
|
|
98
|
+
|
|
99
|
+
__weak typeof(self) weakSelf = self;
|
|
100
|
+
self.cpuMonitorTimer =
|
|
101
|
+
[NSTimer scheduledTimerWithTimeInterval:2.0
|
|
102
|
+
repeats:YES
|
|
103
|
+
block:^(NSTimer *timer) {
|
|
104
|
+
[weakSelf checkCPUUsage];
|
|
105
|
+
}];
|
|
106
|
+
[[NSRunLoop currentRunLoop] addTimer:self.cpuMonitorTimer
|
|
107
|
+
forMode:NSRunLoopCommonModes];
|
|
108
|
+
|
|
109
|
+
RJLogDebug(@"Performance monitoring started");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
- (void)stopMonitoring {
|
|
113
|
+
if (!self.isMonitoring)
|
|
114
|
+
return;
|
|
115
|
+
|
|
116
|
+
self.isMonitoring = NO;
|
|
117
|
+
|
|
118
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
119
|
+
|
|
120
|
+
if (self.cpuMonitorTimer) {
|
|
121
|
+
[self.cpuMonitorTimer invalidate];
|
|
122
|
+
self.cpuMonitorTimer = nil;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (self.memoryPressureSource) {
|
|
126
|
+
@try {
|
|
127
|
+
dispatch_source_cancel(self.memoryPressureSource);
|
|
128
|
+
} @catch (NSException *e) {
|
|
129
|
+
}
|
|
130
|
+
self.memoryPressureSource = nil;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
RJLogDebug(@"Performance monitoring stopped");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
#pragma mark - Memory Pressure Monitoring
|
|
137
|
+
|
|
138
|
+
- (void)setupMemoryPressureMonitoring {
|
|
139
|
+
dispatch_source_t source = dispatch_source_create(
|
|
140
|
+
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0,
|
|
141
|
+
DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL,
|
|
142
|
+
dispatch_get_main_queue());
|
|
143
|
+
|
|
144
|
+
if (!source) {
|
|
145
|
+
RJLogWarning(@"Failed to create memory pressure source");
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
__weak typeof(self) weakSelf = self;
|
|
150
|
+
dispatch_source_set_event_handler(source, ^{
|
|
151
|
+
__strong typeof(weakSelf) strongSelf = weakSelf;
|
|
152
|
+
if (!strongSelf)
|
|
153
|
+
return;
|
|
154
|
+
|
|
155
|
+
dispatch_source_memorypressure_flags_t flags =
|
|
156
|
+
dispatch_source_get_data(source);
|
|
157
|
+
|
|
158
|
+
if (flags & DISPATCH_MEMORYPRESSURE_CRITICAL) {
|
|
159
|
+
RJLogWarning(@"CRITICAL memory pressure - pausing captures");
|
|
160
|
+
[strongSelf setLevel:RJPerformanceLevelPaused];
|
|
161
|
+
[strongSelf handleMemoryWarning];
|
|
162
|
+
} else if (flags & DISPATCH_MEMORYPRESSURE_WARN) {
|
|
163
|
+
RJLogWarning(@"Memory pressure warning - reducing captures");
|
|
164
|
+
[strongSelf setLevel:RJPerformanceLevelMinimal];
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
dispatch_resume(source);
|
|
169
|
+
self.memoryPressureSource = source;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
#pragma mark - Level Management
|
|
173
|
+
|
|
174
|
+
- (void)setLevel:(RJPerformanceLevel)level {
|
|
175
|
+
if (self.currentLevel != level) {
|
|
176
|
+
self.currentLevel = level;
|
|
177
|
+
if ([self.delegate
|
|
178
|
+
respondsToSelector:@selector(performanceManagerDidChangeLevel:)]) {
|
|
179
|
+
[self.delegate performanceManagerDidChangeLevel:level];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
- (void)updatePerformanceLevel {
|
|
185
|
+
if (!self.thermalThrottleEnabled && !self.batteryAwareEnabled) {
|
|
186
|
+
[self setLevel:RJPerformanceLevelNormal];
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
RJPerformanceLevel newLevel = RJPerformanceLevelNormal;
|
|
191
|
+
|
|
192
|
+
if (@available(iOS 11.0, *)) {
|
|
193
|
+
if (self.thermalThrottleEnabled) {
|
|
194
|
+
NSProcessInfoThermalState thermalState =
|
|
195
|
+
[[NSProcessInfo processInfo] thermalState];
|
|
196
|
+
|
|
197
|
+
switch (thermalState) {
|
|
198
|
+
case NSProcessInfoThermalStateCritical:
|
|
199
|
+
[self setLevel:RJPerformanceLevelPaused];
|
|
200
|
+
return;
|
|
201
|
+
case NSProcessInfoThermalStateSerious:
|
|
202
|
+
[self setLevel:RJPerformanceLevelMinimal];
|
|
203
|
+
return;
|
|
204
|
+
case NSProcessInfoThermalStateFair:
|
|
205
|
+
newLevel = RJPerformanceLevelReduced;
|
|
206
|
+
break;
|
|
207
|
+
case NSProcessInfoThermalStateNominal:
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (self.batteryAwareEnabled) {
|
|
214
|
+
float batteryLevel = [[UIDevice currentDevice] batteryLevel];
|
|
215
|
+
UIDeviceBatteryState batteryState = [[UIDevice currentDevice] batteryState];
|
|
216
|
+
|
|
217
|
+
BOOL isCharging = (batteryState == UIDeviceBatteryStateCharging ||
|
|
218
|
+
batteryState == UIDeviceBatteryStateFull);
|
|
219
|
+
|
|
220
|
+
if (!isCharging && batteryLevel >= 0 &&
|
|
221
|
+
batteryLevel < RJLowBatteryThreshold) {
|
|
222
|
+
newLevel = MAX(newLevel, RJPerformanceLevelReduced);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
NSUInteger usedMemory = [self currentMemoryUsage];
|
|
227
|
+
if (usedMemory > RJMemoryWarningThresholdBytes) {
|
|
228
|
+
newLevel = MAX(newLevel, RJPerformanceLevelReduced);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
[self setLevel:newLevel];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
#pragma mark - Notification Handlers
|
|
235
|
+
|
|
236
|
+
- (void)handleThermalStateChange:(NSNotification *)notification {
|
|
237
|
+
[self updatePerformanceLevel];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
- (void)handleBatteryStateChange:(NSNotification *)notification {
|
|
241
|
+
[self updatePerformanceLevel];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
- (void)handleMemoryWarningNotification:(NSNotification *)notification {
|
|
245
|
+
[self handleMemoryWarning];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#pragma mark - Memory Management
|
|
249
|
+
|
|
250
|
+
- (void)handleMemoryWarning {
|
|
251
|
+
RJLogWarning(@"Memory warning received");
|
|
252
|
+
|
|
253
|
+
[self setLevel:RJPerformanceLevelMinimal];
|
|
254
|
+
|
|
255
|
+
if ([self.delegate respondsToSelector:@selector
|
|
256
|
+
(performanceManagerDidReceiveMemoryWarning)]) {
|
|
257
|
+
[self.delegate performanceManagerDidReceiveMemoryWarning];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
- (NSUInteger)currentMemoryUsage {
|
|
262
|
+
struct task_basic_info info;
|
|
263
|
+
mach_msg_type_number_t size = TASK_BASIC_INFO_COUNT;
|
|
264
|
+
|
|
265
|
+
kern_return_t result =
|
|
266
|
+
task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
|
|
267
|
+
|
|
268
|
+
return (result == KERN_SUCCESS) ? info.resident_size : 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
#pragma mark - CPU Monitoring
|
|
272
|
+
|
|
273
|
+
- (float)currentCPUUsage {
|
|
274
|
+
thread_array_t threadList;
|
|
275
|
+
mach_msg_type_number_t threadCount;
|
|
276
|
+
|
|
277
|
+
kern_return_t kr = task_threads(mach_task_self(), &threadList, &threadCount);
|
|
278
|
+
if (kr != KERN_SUCCESS) {
|
|
279
|
+
return -1.0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
float totalUsage = 0.0;
|
|
283
|
+
|
|
284
|
+
for (mach_msg_type_number_t i = 0; i < threadCount; i++) {
|
|
285
|
+
thread_info_data_t threadInfo;
|
|
286
|
+
mach_msg_type_number_t threadInfoCount = THREAD_INFO_MAX;
|
|
287
|
+
|
|
288
|
+
kr = thread_info(threadList[i], THREAD_BASIC_INFO,
|
|
289
|
+
(thread_info_t)threadInfo, &threadInfoCount);
|
|
290
|
+
|
|
291
|
+
if (kr == KERN_SUCCESS) {
|
|
292
|
+
thread_basic_info_t basicInfo = (thread_basic_info_t)threadInfo;
|
|
293
|
+
|
|
294
|
+
if (!(basicInfo->flags & TH_FLAGS_IDLE)) {
|
|
295
|
+
totalUsage += basicInfo->cpu_usage / (float)TH_USAGE_SCALE * 100.0;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
mach_port_deallocate(mach_task_self(), threadList[i]);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
vm_deallocate(mach_task_self(), (vm_address_t)threadList,
|
|
303
|
+
threadCount * sizeof(thread_t));
|
|
304
|
+
|
|
305
|
+
return totalUsage;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
- (BOOL)isCPUHigh {
|
|
309
|
+
return self.rollingCPUAverage >= 60.0;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
- (void)checkCPUUsage {
|
|
313
|
+
float currentCPU = [self currentCPUUsage];
|
|
314
|
+
if (currentCPU < 0)
|
|
315
|
+
return;
|
|
316
|
+
|
|
317
|
+
if (self.rollingCPUAverage == 0) {
|
|
318
|
+
self.rollingCPUAverage = currentCPU;
|
|
319
|
+
} else {
|
|
320
|
+
self.rollingCPUAverage = 0.3 * currentCPU + 0.7 * self.rollingCPUAverage;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/*
|
|
324
|
+
* Updated CPU Thresholds:
|
|
325
|
+
* CRITICAL: > 90%
|
|
326
|
+
* HIGH: > 60%
|
|
327
|
+
* NORMAL: < 40%
|
|
328
|
+
*/
|
|
329
|
+
const float CPU_CRITICAL_THRESHOLD = 90.0; // was 80
|
|
330
|
+
const float CPU_HIGH_THRESHOLD = 60.0; // was 60
|
|
331
|
+
const float CPU_NORMAL_THRESHOLD = 40.0;
|
|
332
|
+
const NSInteger HYSTERESIS_SAMPLES = 3;
|
|
333
|
+
|
|
334
|
+
RJPerformanceLevel suggestedLevel = RJPerformanceLevelNormal;
|
|
335
|
+
|
|
336
|
+
if (self.rollingCPUAverage >= CPU_CRITICAL_THRESHOLD) {
|
|
337
|
+
suggestedLevel = RJPerformanceLevelMinimal;
|
|
338
|
+
self.highCPUSampleCount++;
|
|
339
|
+
} else if (self.rollingCPUAverage >= CPU_HIGH_THRESHOLD) {
|
|
340
|
+
// Force Reduced level (scales down to 0.4) when CPU is high
|
|
341
|
+
suggestedLevel = RJPerformanceLevelReduced;
|
|
342
|
+
self.highCPUSampleCount++;
|
|
343
|
+
} else if (self.rollingCPUAverage < CPU_NORMAL_THRESHOLD) {
|
|
344
|
+
self.highCPUSampleCount = 0;
|
|
345
|
+
suggestedLevel = RJPerformanceLevelNormal;
|
|
346
|
+
} else {
|
|
347
|
+
// In hysteresis zone, maintain current level if it's already
|
|
348
|
+
// reduced/minimal
|
|
349
|
+
if (self.currentLevel >= RJPerformanceLevelReduced) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
// Otherwise keep monitoring
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Apply with hysteresis
|
|
357
|
+
if (suggestedLevel > self.currentLevel) {
|
|
358
|
+
if (self.highCPUSampleCount >= HYSTERESIS_SAMPLES) {
|
|
359
|
+
RJLogInfo(@"CPU usage high (%.1f%%), throttling to level %ld",
|
|
360
|
+
self.rollingCPUAverage, (long)suggestedLevel);
|
|
361
|
+
[self setLevel:suggestedLevel];
|
|
362
|
+
}
|
|
363
|
+
} else if (suggestedLevel < self.currentLevel) {
|
|
364
|
+
// Immediate recovery if CPU drops comfortably
|
|
365
|
+
if (self.highCPUSampleCount == 0) {
|
|
366
|
+
RJLogInfo(@"CPU usage normalized (%.1f%%), restoring level %ld",
|
|
367
|
+
self.rollingCPUAverage, (long)suggestedLevel);
|
|
368
|
+
[self setLevel:suggestedLevel];
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
@end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
|
|
2
|
+
#import <CoreVideo/CoreVideo.h>
|
|
3
|
+
#import <Foundation/Foundation.h>
|
|
4
|
+
|
|
5
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Utility for high-performance pixel buffer downscaling using vImage
|
|
9
|
+
* (Accelerate). Moves scaling work off the main thread to avoid blocking UI.
|
|
10
|
+
*/
|
|
11
|
+
typedef NS_ENUM(NSInteger, RJDownscaleQuality) {
|
|
12
|
+
RJDownscaleQualityBalanced = 0,
|
|
13
|
+
RJDownscaleQualityHigh = 1,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
@interface RJPixelBufferDownscaler : NSObject
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Downscales a source pixel buffer to target dimensions using vImage.
|
|
20
|
+
*
|
|
21
|
+
* @param src The source CVPixelBuffer (typically at native screen scale).
|
|
22
|
+
* @param dstW The target width.
|
|
23
|
+
* @param dstH The target height.
|
|
24
|
+
* @param pool A pixel buffer pool configured for the target dimensions
|
|
25
|
+
* (optional but recommended for perf).
|
|
26
|
+
* @return A new CVPixelBuffer containing the scaled image, or NULL if failed.
|
|
27
|
+
* Caller must release.
|
|
28
|
+
*/
|
|
29
|
+
+ (CVPixelBufferRef _Nullable)downscale:(CVPixelBufferRef)src
|
|
30
|
+
toW:(size_t)dstW
|
|
31
|
+
toH:(size_t)dstH
|
|
32
|
+
usingPool:(CVPixelBufferPoolRef _Nullable)pool;
|
|
33
|
+
|
|
34
|
+
+ (CVPixelBufferRef _Nullable)downscale:(CVPixelBufferRef)src
|
|
35
|
+
toW:(size_t)dstW
|
|
36
|
+
toH:(size_t)dstH
|
|
37
|
+
usingPool:(CVPixelBufferPoolRef _Nullable)pool
|
|
38
|
+
quality:(RJDownscaleQuality)quality;
|
|
39
|
+
|
|
40
|
+
@end
|
|
41
|
+
|
|
42
|
+
NS_ASSUME_NONNULL_END
|