Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2021 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 "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h"
16
 
17
#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"
18
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h"
19
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h"
20
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
21
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
22
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
23
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
24
#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"
25
#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h"
26
#import "Crashlytics/Crashlytics/Private/FIRCrashlyticsReport_Private.h"
27
#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h"
28
 
29
// This value should stay in sync with the Android SDK
30
NSUInteger const FIRCLSMaxUnsentReports = 4;
31
 
32
@interface FIRCLSExistingReportManager ()
33
 
34
@property(nonatomic, strong) FIRCLSFileManager *fileManager;
35
@property(nonatomic, strong) FIRCLSReportUploader *reportUploader;
36
@property(nonatomic, strong) NSOperationQueue *operationQueue;
37
@property(nonatomic, strong) FIRCLSSettings *settings;
38
@property(nonatomic, strong) FIRCLSDataCollectionArbiter *dataArbiter;
39
@property(nonatomic, strong) FIRCLSOnDemandModel *onDemandModel;
40
 
41
// This list of active reports excludes the brand new active report that will be created this run of
42
// the app.
43
@property(nonatomic, strong) NSArray *existingUnemptyActiveReportPaths;
44
@property(nonatomic, strong) NSArray *processingReportPaths;
45
@property(nonatomic, strong) NSArray *preparedReportPaths;
46
 
47
@property(nonatomic, strong) FIRCLSInternalReport *newestInternalReport;
48
 
49
@end
50
 
51
@implementation FIRCLSExistingReportManager
52
 
53
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData
54
                     reportUploader:(FIRCLSReportUploader *)reportUploader {
55
  self = [super init];
56
  if (!self) {
57
    return nil;
58
  }
59
 
60
  _fileManager = managerData.fileManager;
61
  _settings = managerData.settings;
62
  _operationQueue = managerData.operationQueue;
63
  _dataArbiter = managerData.dataArbiter;
64
  _reportUploader = reportUploader;
65
  _onDemandModel = managerData.onDemandModel;
66
 
67
  return self;
68
}
69
 
70
NSInteger compareNewer(FIRCLSInternalReport *reportA,
71
                       FIRCLSInternalReport *reportB,
72
                       void *context) {
73
  // Compare naturally sorts with oldest first, so swap A and B
74
  return [reportB.dateCreated compare:reportA.dateCreated];
75
}
76
 
77
- (void)collectExistingReports {
78
  self.existingUnemptyActiveReportPaths =
79
      [self getUnsentActiveReportsAndDeleteEmptyOrOld:self.fileManager.activePathContents];
80
  self.processingReportPaths = self.fileManager.processingPathContents;
81
  self.preparedReportPaths = self.fileManager.preparedPathContents;
82
}
83
 
84
- (FIRCrashlyticsReport *)newestUnsentReport {
85
  if (self.unsentReportsCount <= 0) {
86
    return nil;
87
  }
88
 
89
  return [[FIRCrashlyticsReport alloc] initWithInternalReport:self.newestInternalReport];
90
}
91
 
92
- (NSUInteger)unsentReportsCount {
93
  // There are nuances about why we only count active reports.
94
  // See the header comment for more information.
95
  return self.existingUnemptyActiveReportPaths.count;
96
}
97
 
98
/*
99
 * This has the side effect of deleting any reports over the max, starting with oldest reports.
100
 */
101
- (NSArray<NSString *> *)getUnsentActiveReportsAndDeleteEmptyOrOld:(NSArray *)reportPaths {
102
  NSMutableArray<FIRCLSInternalReport *> *validReports = [NSMutableArray array];
103
  NSMutableArray<FIRCLSInternalReport *> *reports = [NSMutableArray array];
104
 
105
  for (NSString *path in reportPaths) {
106
    FIRCLSInternalReport *_Nullable report = [FIRCLSInternalReport reportWithPath:path];
107
    if (!report) {
108
      continue;
109
    }
110
 
111
    [reports addObject:report];
112
  }
113
 
114
  if (reports.count == 0) {
115
    return @[];
116
  }
117
 
118
  [reports sortUsingFunction:compareNewer context:nil];
119
  NSString *newestReportPath = [reports firstObject].path;
120
 
121
  // If there was a MetricKit event recorded on the last run of the app, add it to the newest
122
  // report.
123
  if (self.settings.metricKitCollectionEnabled &&
124
      [self.fileManager metricKitDiagnosticFileExists]) {
125
    [self.fileManager createEmptyMetricKitFile:newestReportPath];
126
  }
127
 
128
  for (FIRCLSInternalReport *report in reports) {
129
    // Delete reports without any crashes or non-fatals
130
    if (![report hasAnyEvents]) {
131
      [self.operationQueue addOperationWithBlock:^{
132
        [self.fileManager removeItemAtPath:report.path];
133
      }];
134
      continue;
135
    }
136
 
137
    [validReports addObject:report];
138
  }
139
 
140
  if (validReports.count == 0) {
141
    return @[];
142
  }
143
 
144
  // Sort with the newest at the end
145
  [validReports sortUsingFunction:compareNewer context:nil];
146
 
147
  // Set our report for updating in checkAndUpdateUnsentReports
148
  self.newestInternalReport = [validReports firstObject];
149
 
150
  // Delete any reports above the limit, starting with the oldest
151
  // which should be at the start of the array.
152
  if (validReports.count > FIRCLSMaxUnsentReports) {
153
    NSUInteger deletingCount = validReports.count - FIRCLSMaxUnsentReports;
154
    FIRCLSInfoLog(@"Deleting %lu unsent reports over the limit of %lu to prevent disk space from "
155
                  @"filling up. To prevent this make sure to call send/deleteUnsentReports.",
156
                  deletingCount, FIRCLSMaxUnsentReports);
157
  }
158
 
159
  // Not that validReports is sorted, delete any reports at indices > MAX_UNSENT_REPORTS, and
160
  // collect the rest of the reports to return.
161
  NSMutableArray<NSString *> *validReportPaths = [NSMutableArray array];
162
  for (int i = 0; i < validReports.count; i++) {
163
    if (i >= FIRCLSMaxUnsentReports) {
164
      [self.operationQueue addOperationWithBlock:^{
165
        NSString *path = [[validReports objectAtIndex:i] path];
166
        [self.fileManager removeItemAtPath:path];
167
      }];
168
    } else {
169
      [validReportPaths addObject:[[validReports objectAtIndex:i] path]];
170
    }
171
  }
172
 
173
  return validReportPaths;
174
}
175
 
176
- (void)sendUnsentReportsWithToken:(FIRCLSDataCollectionToken *)dataCollectionToken
177
                          asUrgent:(BOOL)urgent {
178
  for (NSString *path in self.existingUnemptyActiveReportPaths) {
179
    [self processExistingActiveReportPath:path
180
                      dataCollectionToken:dataCollectionToken
181
                                 asUrgent:urgent];
182
  }
183
 
184
  for (NSString *path in self.onDemandModel.storedActiveReportPaths) {
185
    [self processExistingActiveReportPath:path
186
                      dataCollectionToken:dataCollectionToken
187
                                 asUrgent:urgent];
188
  }
189
  [self.onDemandModel.storedActiveReportPaths removeAllObjects];
190
 
191
  // deal with stuff in processing more carefully - do not process again
192
  [self.operationQueue addOperationWithBlock:^{
193
    for (NSString *path in self.processingReportPaths) {
194
      FIRCLSInternalReport *report = [FIRCLSInternalReport reportWithPath:path];
195
      [self.reportUploader prepareAndSubmitReport:report
196
                              dataCollectionToken:dataCollectionToken
197
                                         asUrgent:NO
198
                                   withProcessing:NO];
199
    }
200
  }];
201
 
202
  // Because this could happen quite a bit after the initial set of files was
203
  // captured, some could be completed (deleted). So, just double-check to make sure
204
  // the file still exists.
205
  [self.operationQueue addOperationWithBlock:^{
206
    for (NSString *path in self.preparedReportPaths) {
207
      if (![[self.fileManager underlyingFileManager] fileExistsAtPath:path]) {
208
        continue;
209
      }
210
      [self.reportUploader uploadPackagedReportAtPath:path
211
                                  dataCollectionToken:dataCollectionToken
212
                                             asUrgent:NO];
213
    }
214
  }];
215
}
216
 
217
- (void)processExistingActiveReportPath:(NSString *)path
218
                    dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
219
                               asUrgent:(BOOL)urgent {
220
  FIRCLSInternalReport *report = [FIRCLSInternalReport reportWithPath:path];
221
 
222
  // TODO: hasAnyEvents should really be called on the background queue.
223
  if (![report hasAnyEvents]) {
224
    [self.operationQueue addOperationWithBlock:^{
225
      [self.fileManager removeItemAtPath:path];
226
    }];
227
 
228
    return;
229
  }
230
 
231
  if (urgent && [dataCollectionToken isValid]) {
232
    // We can proceed without the delegate.
233
    [self.reportUploader prepareAndSubmitReport:report
234
                            dataCollectionToken:dataCollectionToken
235
                                       asUrgent:urgent
236
                                 withProcessing:YES];
237
    return;
238
  }
239
 
240
  [self.operationQueue addOperationWithBlock:^{
241
    [self.reportUploader prepareAndSubmitReport:report
242
                            dataCollectionToken:dataCollectionToken
243
                                       asUrgent:NO
244
                                 withProcessing:YES];
245
  }];
246
}
247
 
248
- (void)deleteUnsentReports {
249
  NSArray<NSString *> *reportPaths = @[];
250
  reportPaths = [reportPaths arrayByAddingObjectsFromArray:self.existingUnemptyActiveReportPaths];
251
  reportPaths = [reportPaths arrayByAddingObjectsFromArray:self.processingReportPaths];
252
  reportPaths = [reportPaths arrayByAddingObjectsFromArray:self.preparedReportPaths];
253
 
254
  [self.operationQueue addOperationWithBlock:^{
255
    for (NSString *path in reportPaths) {
256
      [self.fileManager removeItemAtPath:path];
257
    }
258
  }];
259
}
260
 
261
- (void)handleOnDemandReportUpload:(NSString *)path
262
               dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
263
                          asUrgent:(BOOL)urgent {
264
  dispatch_async(self.operationQueue.underlyingQueue, ^{
265
    [self processExistingActiveReportPath:path
266
                      dataCollectionToken:dataCollectionToken
267
                                 asUrgent:YES];
268
  });
269
}
270
 
271
@end