Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2022 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import <Foundation/Foundation.h>
16
 
17
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
18
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h"
19
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
20
#import "Crashlytics/Crashlytics/Handlers/FIRCLSException.h"
21
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
22
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
23
#import "Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.h"
24
#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h"
25
 
26
#include <math.h>
27
 
28
@interface FIRCLSOnDemandModel ()
29
 
30
@property(nonatomic, readonly) int recordedOnDemandExceptionCount;
31
@property(nonatomic, readonly) int droppedOnDemandExceptionCount;
32
@property(nonatomic, readonly) int queuedOperationsCount;
33
 
34
@property(nonatomic, strong) FIRCLSSettings *settings;
35
@property(nonatomic, strong) NSOperationQueue *operationQueue;
36
@property(nonatomic, strong) dispatch_queue_t dispatchQueue;
37
 
38
@property(nonatomic) double lastUpdated;
39
@property(nonatomic) double currentStep;
40
 
41
@property(nonatomic, strong) NSFileManager *fileManager;
42
@property(nonatomic, strong) NSMutableArray *storedActiveReportPaths;
43
 
44
@end
45
 
46
@implementation FIRCLSOnDemandModel
47
 
48
@synthesize recordedOnDemandExceptionCount = _recordedOnDemandExceptionCount;
49
@synthesize droppedOnDemandExceptionCount = _droppedOnDemandExceptionCount;
50
@synthesize queuedOperationsCount = _queuedOperationsCount;
51
 
52
static const double MAX_DELAY_SEC = 3600;
53
static const double SEC_PER_MINUTE = 60;
54
 
55
- (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings {
56
  self = [super init];
57
  if (!self) {
58
    return nil;
59
  }
60
 
61
  _settings = settings;
62
 
63
  NSString *sdkBundleID = FIRCLSApplicationGetSDKBundleID();
64
  _operationQueue = [NSOperationQueue new];
65
  [_operationQueue setMaxConcurrentOperationCount:1];
66
  [_operationQueue setName:[sdkBundleID stringByAppendingString:@".on-demand-queue"]];
67
  _dispatchQueue = dispatch_queue_create("com.google.firebase.crashlytics.on.demand", 0);
68
  _operationQueue.underlyingQueue = _dispatchQueue;
69
 
70
  _queuedOperationsCount = 0;
71
 
72
  _recordedOnDemandExceptionCount = 0;
73
  _droppedOnDemandExceptionCount = 0;
74
 
75
  _lastUpdated = [NSDate timeIntervalSinceReferenceDate];
76
  _currentStep = -1;
77
  _fileManager = [[NSFileManager alloc] init];
78
 
79
  self.storedActiveReportPaths = [NSMutableArray array];
80
 
81
  return self;
82
}
83
 
84
/*
85
 * Called from FIRCrashlytics whenever the on-demand record exception method is called. Handles
86
 * rate limiting and exponential backoff.
87
 */
88
- (BOOL)recordOnDemandExceptionIfQuota:(FIRExceptionModel *)exceptionModel
89
             withDataCollectionEnabled:(BOOL)dataCollectionEnabled
90
            usingExistingReportManager:(FIRCLSExistingReportManager *)existingReportManager {
91
  // Record the exception model into a new report if there is unused on-demand quota. Otherwise,
92
  // log the occurence but drop the event.
93
  @synchronized(self) {
94
    if ([self isQueueFull]) {
95
      FIRCLSDebugLog(@"No available on-demand quota, dropping report");
96
      [self incrementDroppedExceptionCount];
97
      [self incrementRecordedExceptionCount];
98
      return NO;  // Didn't record or submit the exception because no quota was available.
99
    }
100
 
101
    FIRCLSDataCollectionToken *dataCollectionToken = [FIRCLSDataCollectionToken validToken];
102
    NSString *activeReportPath = FIRCLSExceptionRecordOnDemandModel(
103
        exceptionModel, self.recordedOnDemandExceptionCount, self.droppedOnDemandExceptionCount);
104
 
105
    if (!activeReportPath) {
106
      FIRCLSErrorLog(@"Error recording on-demand exception");
107
      return NO;  // Something went wrong when recording the exception, so we don't have a valid
108
                  // path.
109
    }
110
 
111
    // Only submit an exception report if data collection is enabled. Otherwise, the report
112
    // is stored until send or delete unsent reports is called.
113
    [self incrementQueuedOperationCount];
114
    [self incrementRecordedExceptionCount];
115
    [self resetDroppedExceptionCount];
116
 
117
    [self.operationQueue addOperationWithBlock:^{
118
      double uploadDelay = [self calculateUploadDelay];
119
 
120
      if (dataCollectionEnabled) {
121
        [existingReportManager handleOnDemandReportUpload:activeReportPath
122
                                      dataCollectionToken:dataCollectionToken
123
                                                 asUrgent:YES];
124
        FIRCLSDebugLog(@"Submitted an on-demand exception, starting delay %.20f", uploadDelay);
125
      } else {
126
        [self.storedActiveReportPaths insertObject:activeReportPath atIndex:0];
127
        if ([self.storedActiveReportPaths count] > FIRCLSMaxUnsentReports) {
128
          [self.fileManager removeItemAtPath:[self.storedActiveReportPaths lastObject] error:nil];
129
          [self.storedActiveReportPaths removeLastObject];
130
          [self decrementRecordedExceptionCount];
131
          [self incrementDroppedExceptionCount];
132
        }
133
        FIRCLSDebugLog(@"Stored an on-demand exception, starting delay %.20f", uploadDelay);
134
      }
135
      [self implementOnDemandUploadDelay:uploadDelay];
136
      [self decrementQueuedOperationCount];
137
    }];
138
    return YES;  // Recorded and submitted the exception.
139
  }
140
}
141
 
142
- (double)calculateUploadDelay {
143
  double calculatedStepDuration = [self calculateStepDuration];
144
  double power = pow(self.settings.onDemandBackoffBase, calculatedStepDuration);
145
  NSNumber *calculatedUploadDelay =
146
      [NSNumber numberWithDouble:(SEC_PER_MINUTE / self.settings.onDemandUploadRate) * power];
147
  NSComparisonResult result =
148
      [[NSNumber numberWithDouble:MAX_DELAY_SEC] compare:calculatedUploadDelay];
149
  return (result == NSOrderedAscending) ? MAX_DELAY_SEC : [calculatedUploadDelay doubleValue];
150
}
151
 
152
- (double)calculateStepDuration {
153
  double currentTime = [NSDate timeIntervalSinceReferenceDate];
154
  BOOL queueIsFull = [self isQueueFull];
155
 
156
  if (self.currentStep == -1) {
157
    self.currentStep = 0;
158
    self.lastUpdated = currentTime;
159
  }
160
 
161
  double delta =
162
      (currentTime - self.lastUpdated) / (double)self.settings.onDemandBackoffStepDuration;
163
  double queueFullDuration = (self.currentStep + delta) > 100 ? 100 : (self.currentStep + delta);
164
  double queueNotFullDuration = (self.currentStep - delta) < 0 ? 0 : (self.currentStep - delta);
165
  double calculatedDuration = queueIsFull ? queueFullDuration : queueNotFullDuration;
166
 
167
  if (self.currentStep != calculatedDuration) {
168
    self.currentStep = calculatedDuration;
169
    self.lastUpdated = currentTime;
170
  }
171
 
172
  return calculatedDuration;
173
}
174
 
175
- (void)implementOnDemandUploadDelay:(int)delay {
176
  sleep(delay);
177
}
178
 
179
- (int)droppedOnDemandExceptionCount {
180
  @synchronized(self) {
181
    return _droppedOnDemandExceptionCount;
182
  }
183
}
184
 
185
- (void)setDroppedOnDemandExceptionCount:(int)count {
186
  @synchronized(self) {
187
    _droppedOnDemandExceptionCount = count;
188
  }
189
}
190
 
191
- (void)incrementDroppedExceptionCount {
192
  @synchronized(self) {
193
    [self setDroppedOnDemandExceptionCount:[self droppedOnDemandExceptionCount] + 1];
194
  }
195
}
196
 
197
- (void)decrementDroppedExceptionCount {
198
  @synchronized(self) {
199
    [self setDroppedOnDemandExceptionCount:[self droppedOnDemandExceptionCount] - 1];
200
  }
201
}
202
 
203
- (void)resetDroppedExceptionCount {
204
  @synchronized(self) {
205
    [self setDroppedOnDemandExceptionCount:0];
206
  }
207
}
208
 
209
- (int)recordedOnDemandExceptionCount {
210
  @synchronized(self) {
211
    return _recordedOnDemandExceptionCount;
212
  }
213
}
214
 
215
- (void)setRecordedOnDemandExceptionCount:(int)count {
216
  @synchronized(self) {
217
    _recordedOnDemandExceptionCount = count;
218
  }
219
}
220
 
221
- (void)incrementRecordedExceptionCount {
222
  @synchronized(self) {
223
    [self setRecordedOnDemandExceptionCount:[self recordedOnDemandExceptionCount] + 1];
224
  }
225
}
226
 
227
- (void)decrementRecordedExceptionCount {
228
  @synchronized(self) {
229
    [self setRecordedOnDemandExceptionCount:[self recordedOnDemandExceptionCount] - 1];
230
  }
231
}
232
 
233
- (int)getQueuedOperationsCount {
234
  @synchronized(self) {
235
    return _queuedOperationsCount;
236
  }
237
}
238
 
239
- (void)setQueuedOperationsCount:(int)count {
240
  @synchronized(self) {
241
    _queuedOperationsCount = count;
242
  }
243
}
244
 
245
- (void)incrementQueuedOperationCount {
246
  @synchronized(self) {
247
    [self setQueuedOperationsCount:[self getQueuedOperationsCount] + 1];
248
  }
249
}
250
 
251
- (void)decrementQueuedOperationCount {
252
  @synchronized(self) {
253
    [self setQueuedOperationsCount:[self getQueuedOperationsCount] - 1];
254
  }
255
}
256
 
257
- (BOOL)isQueueFull {
258
  return ([self getQueuedOperationsCount] >= self.settings.onDemandUploadRate);
259
}
260
 
261
@end