Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/*
2
 * Copyright 2020 Google LLC
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
#import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h"
18
#import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter_Private.h"
19
 
20
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
21
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
22
 
23
#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
24
 
25
#import <nanopb/pb.h>
26
#import <nanopb/pb_decode.h>
27
#import <nanopb/pb_encode.h>
28
 
29
@interface FIRCLSReportAdapter ()
30
 
31
@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel;
32
 
33
@end
34
 
35
@implementation FIRCLSReportAdapter
36
 
37
- (instancetype)initWithPath:(NSString *)folderPath
38
                 googleAppId:(NSString *)googleAppID
39
              installIDModel:(FIRCLSInstallIdentifierModel *)installIDModel {
40
  self = [super init];
41
  if (self) {
42
    _folderPath = folderPath;
43
    _googleAppID = googleAppID;
44
    _installIDModel = installIDModel;
45
 
46
    [self loadMetaDataFile];
47
 
48
    _report = [self protoReport];
49
  }
50
  return self;
51
}
52
 
53
- (void)dealloc {
54
  pb_release(google_crashlytics_Report_fields, &_report);
55
}
56
 
57
//
58
// MARK: Load from persisted crash files
59
//
60
 
61
/// Reads from metadata.clsrecord
62
- (void)loadMetaDataFile {
63
  NSString *path = [self.folderPath stringByAppendingPathComponent:FIRCLSReportMetadataFile];
64
  NSDictionary *dict = [FIRCLSReportAdapter combinedDictionariesFromFilePath:path];
65
 
66
  self.identity = [[FIRCLSRecordIdentity alloc] initWithDict:dict[@"identity"]];
67
  self.host = [[FIRCLSRecordHost alloc] initWithDict:dict[@"host"]];
68
  self.application = [[FIRCLSRecordApplication alloc] initWithDict:dict[@"application"]];
69
}
70
 
71
/// Return the persisted crash file as a combined dictionary that way lookups can occur with a key
72
/// (to avoid ordering dependency)
73
/// @param filePath Persisted crash file path
74
+ (NSDictionary *)combinedDictionariesFromFilePath:(NSString *)filePath {
75
  NSMutableDictionary *joinedDict = [[NSMutableDictionary alloc] init];
76
  for (NSDictionary *dict in [self dictionariesFromEachLineOfFile:filePath]) {
77
    [joinedDict addEntriesFromDictionary:dict];
78
  }
79
  return joinedDict;
80
}
81
 
82
/// The persisted crash files contains JSON on separate lines. Read each line and return the JSON
83
/// data as a dictionary.
84
/// @param filePath Persisted crash file path
85
+ (NSArray<NSDictionary *> *)dictionariesFromEachLineOfFile:(NSString *)filePath {
86
  NSString *content = [[NSString alloc] initWithContentsOfFile:filePath
87
                                                      encoding:NSUTF8StringEncoding
88
                                                         error:nil];
89
  NSArray *lines =
90
      [content componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet];
91
 
92
  NSMutableArray<NSDictionary *> *array = [[NSMutableArray<NSDictionary *> alloc] init];
93
 
94
  int lineNum = 0;
95
  for (NSString *line in lines) {
96
    lineNum++;
97
 
98
    if (line.length == 0) {
99
      // Likely newline at the end of the file
100
      continue;
101
    }
102
 
103
    NSError *error;
104
    NSDictionary *dict =
105
        [NSJSONSerialization JSONObjectWithData:[line dataUsingEncoding:NSUTF8StringEncoding]
106
                                        options:0
107
                                          error:&error];
108
 
109
    if (error) {
110
      FIRCLSErrorLog(@"Failed to read JSON from file (%@) line (%d) with error: %@", filePath,
111
                     lineNum, error);
112
    } else {
113
      [array addObject:dict];
114
    }
115
  }
116
 
117
  return array;
118
}
119
 
120
//
121
// MARK: GDTCOREventDataObject
122
//
123
 
124
- (NSData *)transportBytes {
125
  pb_ostream_t sizestream = PB_OSTREAM_SIZING;
126
 
127
  // Encode 1 time to determine the size.
128
  if (!pb_encode(&sizestream, google_crashlytics_Report_fields, &_report)) {
129
    FIRCLSErrorLog(@"Error in nanopb encoding for size: %s", PB_GET_ERROR(&sizestream));
130
  }
131
 
132
  // Encode a 2nd time to actually get the bytes from it.
133
  size_t bufferSize = sizestream.bytes_written;
134
  CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize);
135
  CFDataSetLength(dataRef, bufferSize);
136
  pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize);
137
  if (!pb_encode(&ostream, google_crashlytics_Report_fields, &_report)) {
138
    FIRCLSErrorLog(@"Error in nanopb encoding for bytes: %s", PB_GET_ERROR(&ostream));
139
  }
140
 
141
  return CFBridgingRelease(dataRef);
142
}
143
 
144
//
145
// MARK: NanoPB conversions
146
//
147
 
148
- (google_crashlytics_Report)protoReport {
149
  google_crashlytics_Report report = google_crashlytics_Report_init_default;
150
  report.sdk_version = FIRCLSEncodeString(self.identity.build_version);
151
  report.gmp_app_id = FIRCLSEncodeString(self.googleAppID);
152
  report.platform = [self protoPlatformFromString:self.host.platform];
153
  report.installation_uuid = FIRCLSEncodeString(self.installIDModel.installID);
154
  report.build_version = FIRCLSEncodeString(self.application.build_version);
155
  report.display_version = FIRCLSEncodeString(self.application.display_version);
156
  report.apple_payload = [self protoFilesPayload];
157
  return report;
158
}
159
 
160
- (google_crashlytics_FilesPayload)protoFilesPayload {
161
  google_crashlytics_FilesPayload apple_payload = google_crashlytics_FilesPayload_init_default;
162
 
163
  NSArray<NSString *> *clsRecords = [self clsRecordFilePaths];
164
  google_crashlytics_FilesPayload_File *files =
165
      malloc(sizeof(google_crashlytics_FilesPayload_File) * clsRecords.count);
166
 
167
  if (files == NULL) {
168
    // files and files_count are initialized to NULL and 0 by default.
169
    return apple_payload;
170
  }
171
  for (NSUInteger i = 0; i < clsRecords.count; i++) {
172
    google_crashlytics_FilesPayload_File file = google_crashlytics_FilesPayload_File_init_default;
173
    file.filename = FIRCLSEncodeString(clsRecords[i].lastPathComponent);
174
 
175
    NSError *error;
176
    file.contents = FIRCLSEncodeData([NSData dataWithContentsOfFile:clsRecords[i]
177
                                                            options:0
178
                                                              error:&error]);
179
    if (error) {
180
      FIRCLSErrorLog(@"Failed to read from %@ with error: %@", clsRecords[i], error);
181
    }
182
 
183
    files[i] = file;
184
  }
185
 
186
  apple_payload.files = files;
187
  apple_payload.files_count = (pb_size_t)clsRecords.count;
188
 
189
  return apple_payload;
190
}
191
 
192
- (NSArray<NSString *> *)clsRecordFilePaths {
193
  NSMutableArray<NSString *> *clsRecords = [[NSMutableArray<NSString *> alloc] init];
194
 
195
  NSError *error;
196
  NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.folderPath
197
                                                                       error:&error];
198
 
199
  if (error) {
200
    FIRCLSErrorLog(@"Failed to find .clsrecords from %@ with error: %@", self.folderPath, error);
201
    return clsRecords;
202
  }
203
 
204
  [files enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
205
    NSString *filename = (NSString *)obj;
206
    NSString *lowerExtension = filename.pathExtension.lowercaseString;
207
    if ([lowerExtension isEqualToString:@"clsrecord"] ||
208
        [lowerExtension isEqualToString:@"symbolicated"]) {
209
      [clsRecords addObject:[self.folderPath stringByAppendingPathComponent:filename]];
210
    }
211
  }];
212
 
213
  return [clsRecords sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
214
}
215
 
216
- (google_crashlytics_Platforms)protoPlatformFromString:(NSString *)str {
217
  NSString *platform = str.lowercaseString;
218
 
219
  if ([platform isEqualToString:@"ios"]) {
220
    return google_crashlytics_Platforms_IOS;
221
  } else if ([platform isEqualToString:@"mac"]) {
222
    return google_crashlytics_Platforms_MAC_OS_X;
223
  } else if ([platform isEqualToString:@"tvos"]) {
224
    return google_crashlytics_Platforms_TVOS;
225
  } else {
226
    return google_crashlytics_Platforms_UNKNOWN_PLATFORM;
227
  }
228
}
229
 
230
/** Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array.
231
 * @note Memory needs to be freed manually, through pb_free or pb_release.
232
 * @param string The string to encode as pb_bytes.
233
 */
234
pb_bytes_array_t *FIRCLSEncodeString(NSString *string) {
235
  if ([string isMemberOfClass:[NSNull class]]) {
236
    FIRCLSErrorLog(@"Expected encodable string, but found NSNull instead. "
237
                   @"Set a symbolic breakpoint at FIRCLSEncodeString to debug.");
238
    string = nil;
239
  }
240
  NSString *stringToEncode = string ? string : @"";
241
  NSData *stringBytes = [stringToEncode dataUsingEncoding:NSUTF8StringEncoding];
242
  return FIRCLSEncodeData(stringBytes);
243
}
244
 
245
/** Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array.
246
 * @note Memory needs to be free manually, through pb_free or pb_release.
247
 * @param data The data to copy into the new bytes array.
248
 */
249
pb_bytes_array_t *FIRCLSEncodeData(NSData *data) {
250
  pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length));
251
  if (pbBytes == NULL) {
252
    return NULL;
253
  }
254
  memcpy(pbBytes->bytes, [data bytes], data.length);
255
  pbBytes->size = (pb_size_t)data.length;
256
  return pbBytes;
257
}
258
 
259
@end