Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2019 Google
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 "Interop/Analytics/Public/FIRAnalyticsInterop.h"
16
 
17
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
18
#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h"
19
#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"
20
#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader_Private.h"
21
#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"
22
#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
23
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
24
#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h"
25
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
26
#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"
27
#import "Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h"
28
#import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h"
29
#import "Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h"
30
 
31
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
32
 
33
#import "Crashlytics/Shared/FIRCLSConstants.h"
34
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSMultipartMimeStreamEncoder.h"
35
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h"
36
 
37
#import <GoogleDataTransport/GoogleDataTransport.h>
38
 
39
@interface FIRCLSReportUploader () {
40
  id<FIRAnalyticsInterop> _analytics;
41
}
42
 
43
@property(nonatomic, strong) GDTCORTransport *googleTransport;
44
@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel;
45
 
46
@property(nonatomic, readonly) NSString *googleAppID;
47
 
48
@end
49
 
50
@implementation FIRCLSReportUploader
51
 
52
- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData {
53
  self = [super init];
54
  if (!self) {
55
    return nil;
56
  }
57
 
58
  _operationQueue = managerData.operationQueue;
59
  _googleAppID = managerData.googleAppID;
60
  _googleTransport = managerData.googleTransport;
61
  _installIDModel = managerData.installIDModel;
62
  _fileManager = managerData.fileManager;
63
  _analytics = managerData.analytics;
64
 
65
  return self;
66
}
67
 
68
#pragma mark - Packaging and Submission
69
 
70
/*
71
 * For a crash report, this is the initial code path for uploading. A report
72
 * will not repeat this code path after it's happened because this code path
73
 * will move the report from the "active" folder into "processing" and then
74
 * "prepared". Once in prepared, the report can be re-uploaded any number of times
75
 * with uploadPackagedReportAtPath in the case of an upload failure.
76
 */
77
- (void)prepareAndSubmitReport:(FIRCLSInternalReport *)report
78
           dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
79
                      asUrgent:(BOOL)urgent
80
                withProcessing:(BOOL)shouldProcess {
81
  if (![dataCollectionToken isValid]) {
82
    FIRCLSErrorLog(@"Data collection disabled and report will not be submitted");
83
    return;
84
  }
85
 
86
  // This activity is still relevant using GoogleDataTransport because the on-device
87
  // symbolication operation may be computationally intensive.
88
  FIRCLSApplicationActivity(
89
      FIRCLSApplicationActivityDefault, @"Crashlytics Crash Report Processing", ^{
90
        // Run this only once because it can be run multiple times in succession,
91
        // and if it's slow it could delay crash upload too much without providing
92
        // user benefit.
93
        static dispatch_once_t regenerateOnceToken;
94
        dispatch_once(&regenerateOnceToken, ^{
95
          // Check to see if the FID has rotated before we construct the payload
96
          // so that the payload has an updated value.
97
          [self.installIDModel regenerateInstallIDIfNeeded];
98
        });
99
 
100
        // Run on-device symbolication before packaging if we should process
101
        if (shouldProcess) {
102
          if (![self.fileManager moveItemAtPath:report.path
103
                                    toDirectory:self.fileManager.processingPath]) {
104
            FIRCLSErrorLog(@"Unable to move report for processing");
105
            return;
106
          }
107
 
108
          // adjust the report's path, and process it
109
          [report setPath:[self.fileManager.processingPath
110
                              stringByAppendingPathComponent:report.directoryName]];
111
 
112
          FIRCLSSymbolResolver *resolver = [[FIRCLSSymbolResolver alloc] init];
113
 
114
          FIRCLSProcessReportOperation *processOperation =
115
              [[FIRCLSProcessReportOperation alloc] initWithReport:report resolver:resolver];
116
 
117
          [processOperation start];
118
        }
119
 
120
        // With the new report endpoint, the report is deleted once it is written to GDT
121
        // Check if the report has a crash file before the report is moved or deleted
122
        BOOL isCrash = report.isCrash;
123
 
124
        // For the new endpoint, just move the .clsrecords from "processing" -> "prepared".
125
        // In the old endpoint this was for packaging the report as a multipartmime file,
126
        // so this can probably be removed for GoogleDataTransport.
127
        if (![self.fileManager moveItemAtPath:report.path
128
                                  toDirectory:self.fileManager.preparedPath]) {
129
          FIRCLSErrorLog(@"Unable to move report to prepared");
130
          return;
131
        }
132
 
133
        NSString *packagedPath = [self.fileManager.preparedPath
134
            stringByAppendingPathComponent:report.path.lastPathComponent];
135
 
136
        FIRCLSInfoLog(@"[Firebase/Crashlytics] Packaged report with id '%@' for submission",
137
                      report.identifier);
138
 
139
        [self uploadPackagedReportAtPath:packagedPath
140
                     dataCollectionToken:dataCollectionToken
141
                                asUrgent:urgent];
142
 
143
        // We don't check for success here for 2 reasons:
144
        //   1) If we can't upload a crash for whatever reason, but we can upload analytics
145
        //      it's better for the customer to get accurate Crash Free Users.
146
        //   2) In the past we did try to check for success, but it was a useless check because
147
        //      sendDataEvent is async (unless we're sending urgently).
148
        if (isCrash) {
149
          [FIRCLSAnalyticsManager logCrashWithTimeStamp:report.crashedOnDate.timeIntervalSince1970
150
                                            toAnalytics:self->_analytics];
151
        }
152
      });
153
 
154
  return;
155
}
156
 
157
/*
158
 * This code path can be repeated any number of times for a prepared crash report if
159
 * the report is failing to upload.
160
 *
161
 * Therefore, side effects (like logging to Analytics) should not go in this method or
162
 * else they will re-trigger when failures happen.
163
 *
164
 * When a crash report fails to upload, it will stay in the "prepared" folder. Upon next
165
 * run of the app, the ReportManager will attempt to re-upload prepared reports using this
166
 * method.
167
 */
168
- (void)uploadPackagedReportAtPath:(NSString *)path
169
               dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken
170
                          asUrgent:(BOOL)urgent {
171
  FIRCLSDebugLog(@"Submitting report %@", urgent ? @"urgently" : @"async");
172
 
173
  if (![dataCollectionToken isValid]) {
174
    FIRCLSErrorLog(@"A report upload was requested with an invalid data collection token.");
175
    return;
176
  }
177
 
178
  FIRCLSReportAdapter *adapter = [[FIRCLSReportAdapter alloc] initWithPath:path
179
                                                               googleAppId:self.googleAppID
180
                                                            installIDModel:self.installIDModel];
181
 
182
  GDTCOREvent *event = [self.googleTransport eventForTransport];
183
  event.dataObject = adapter;
184
  event.qosTier = GDTCOREventQoSFast;  // Bypass batching, send immediately
185
 
186
  dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
187
 
188
  [self.googleTransport
189
      sendDataEvent:event
190
         onComplete:^(BOOL wasWritten, NSError *error) {
191
           if (!wasWritten) {
192
             FIRCLSErrorLog(
193
                 @"Failed to send crash report due to failure writing GoogleDataTransport event");
194
             return;
195
           }
196
 
197
           if (error) {
198
             FIRCLSErrorLog(@"Failed to send crash report due to GoogleDataTransport error: %@",
199
                            error.localizedDescription);
200
             return;
201
           }
202
 
203
           FIRCLSInfoLog(@"Completed report submission with id: %@", path.lastPathComponent);
204
 
205
           if (urgent) {
206
             dispatch_semaphore_signal(semaphore);
207
           }
208
 
209
           [self cleanUpSubmittedReportAtPath:path];
210
         }];
211
 
212
  if (urgent) {
213
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
214
  }
215
}
216
 
217
- (BOOL)cleanUpSubmittedReportAtPath:(NSString *)path {
218
  if (![[self fileManager] removeItemAtPath:path]) {
219
    FIRCLSErrorLog(@"Unable to remove packaged submission");
220
    return NO;
221
  }
222
 
223
  return YES;
224
}
225
 
226
@end