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
#include "Crashlytics/Crashlytics/Components/FIRCLSContext.h"
16
 
17
#include <stdlib.h>
18
#include <string.h>
19
 
20
#import "Crashlytics/Shared/FIRCLSConstants.h"
21
 
22
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
23
#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h"
24
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
25
#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"
26
 
27
#include "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
28
#include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h"
29
#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
30
#include "Crashlytics/Crashlytics/Components/FIRCLSProcess.h"
31
#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
32
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
33
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
34
 
35
// The writable size is our handler stack plus whatever scratch we need.  We have to use this space
36
// extremely carefully, however, because thread stacks always needs to be page-aligned.  Only the
37
// first allocation is gauranteed to be page-aligned.
38
//
39
// CLS_SIGNAL_HANDLER_STACK_SIZE and CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE are platform dependant,
40
// defined as 0 for tv/watch.
41
#define CLS_MINIMUM_READWRITE_SIZE                                         \
42
  (CLS_SIGNAL_HANDLER_STACK_SIZE + CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE + \
43
   sizeof(FIRCLSReadWriteContext))
44
 
45
// We need enough space here for the context, plus storage for strings.
46
#define CLS_MINIMUM_READABLE_SIZE (sizeof(FIRCLSReadOnlyContext) + 4096 * 4)
47
 
48
static const int64_t FIRCLSContextInitWaitTime = 5LL * NSEC_PER_SEC;
49
 
50
static bool FIRCLSContextRecordMetadata(const char* path, const FIRCLSContextInitData* initData);
51
static const char* FIRCLSContextAppendToRoot(NSString* root, NSString* component);
52
static void FIRCLSContextAllocate(FIRCLSContext* context);
53
 
54
FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
55
                                                 FIRCLSSettings* settings,
56
                                                 FIRCLSFileManager* fileManager) {
57
  // Because we need to start the crash reporter right away,
58
  // it starts up either with default settings, or cached settings
59
  // from the last time they were fetched
60
 
61
  FIRCLSContextInitData initData;
62
 
63
  memset(&initData, 0, sizeof(FIRCLSContextInitData));
64
 
65
  initData.customBundleId = nil;
66
  initData.sessionId = [[report identifier] UTF8String];
67
  initData.rootPath = [[report path] UTF8String];
68
  initData.previouslyCrashedFileRootPath = [[fileManager rootPath] UTF8String];
69
  initData.errorsEnabled = [settings errorReportingEnabled];
70
  initData.customExceptionsEnabled = [settings customExceptionsEnabled];
71
  initData.maxCustomExceptions = [settings maxCustomExceptions];
72
  initData.maxErrorLogSize = [settings errorLogBufferSize];
73
  initData.maxLogSize = [settings logBufferSize];
74
  initData.maxKeyValues = [settings maxCustomKeys];
75
  initData.betaToken = "";
76
 
77
  return initData;
78
}
79
 
80
bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
81
                             FIRCLSSettings* settings,
82
                             FIRCLSFileManager* fileManager) {
83
  FIRCLSContextInitData initDataObj = FIRCLSContextBuildInitData(report, settings, fileManager);
84
  FIRCLSContextInitData* initData = &initDataObj;
85
 
86
  if (!initData) {
87
    return false;
88
  }
89
 
90
  FIRCLSContextBaseInit();
91
 
92
  dispatch_group_t group = dispatch_group_create();
93
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
94
 
95
  if (!FIRCLSIsValidPointer(initData->rootPath)) {
96
    return false;
97
  }
98
 
99
  NSString* rootPath = [NSString stringWithUTF8String:initData->rootPath];
100
 
101
  // setup our SDK log file synchronously, because other calls may depend on it
102
  _firclsContext.readonly->logPath = FIRCLSContextAppendToRoot(rootPath, @"sdk.log");
103
  _firclsContext.readonly->initialReportPath = FIRCLSDupString([report.path UTF8String]);
104
  if (!FIRCLSUnlinkIfExists(_firclsContext.readonly->logPath)) {
105
    FIRCLSErrorLog(@"Unable to write initialize SDK write paths %s", strerror(errno));
106
  }
107
 
108
  // some values that aren't tied to particular subsystem
109
  _firclsContext.readonly->debuggerAttached = FIRCLSProcessDebuggerAttached();
110
 
111
  dispatch_group_async(group, queue, ^{
112
    FIRCLSHostInitialize(&_firclsContext.readonly->host);
113
  });
114
 
115
  dispatch_group_async(group, queue, ^{
116
    _firclsContext.readonly->logging.errorStorage.maxSize = 0;
117
    _firclsContext.readonly->logging.errorStorage.maxEntries =
118
        initData->errorsEnabled ? initData->maxCustomExceptions : 0;
119
    _firclsContext.readonly->logging.errorStorage.restrictBySize = false;
120
    _firclsContext.readonly->logging.errorStorage.entryCount =
121
        &_firclsContext.writable->logging.errorsCount;
122
    _firclsContext.readonly->logging.errorStorage.aPath =
123
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportErrorAFile);
124
    _firclsContext.readonly->logging.errorStorage.bPath =
125
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportErrorBFile);
126
 
127
    _firclsContext.readonly->logging.logStorage.maxSize = initData->maxLogSize;
128
    _firclsContext.readonly->logging.logStorage.maxEntries = 0;
129
    _firclsContext.readonly->logging.logStorage.restrictBySize = true;
130
    _firclsContext.readonly->logging.logStorage.entryCount = NULL;
131
    _firclsContext.readonly->logging.logStorage.aPath =
132
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportLogAFile);
133
    _firclsContext.readonly->logging.logStorage.bPath =
134
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportLogBFile);
135
    _firclsContext.readonly->logging.customExceptionStorage.aPath =
136
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportCustomExceptionAFile);
137
    _firclsContext.readonly->logging.customExceptionStorage.bPath =
138
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportCustomExceptionBFile);
139
    _firclsContext.readonly->logging.customExceptionStorage.maxSize = 0;
140
    _firclsContext.readonly->logging.customExceptionStorage.restrictBySize = false;
141
    _firclsContext.readonly->logging.customExceptionStorage.maxEntries =
142
        initData->maxCustomExceptions;
143
    _firclsContext.readonly->logging.customExceptionStorage.entryCount =
144
        &_firclsContext.writable->exception.customExceptionCount;
145
 
146
    _firclsContext.readonly->logging.userKVStorage.maxCount = initData->maxKeyValues;
147
    _firclsContext.readonly->logging.userKVStorage.incrementalPath =
148
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportUserIncrementalKVFile);
149
    _firclsContext.readonly->logging.userKVStorage.compactedPath =
150
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportUserCompactedKVFile);
151
 
152
    _firclsContext.readonly->logging.internalKVStorage.maxCount = 32;  // Hardcode = bad
153
    _firclsContext.readonly->logging.internalKVStorage.incrementalPath =
154
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportInternalIncrementalKVFile);
155
    _firclsContext.readonly->logging.internalKVStorage.compactedPath =
156
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportInternalCompactedKVFile);
157
 
158
    FIRCLSUserLoggingInit(&_firclsContext.readonly->logging, &_firclsContext.writable->logging);
159
  });
160
 
161
  dispatch_group_async(group, queue, ^{
162
    _firclsContext.readonly->binaryimage.path =
163
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportBinaryImageFile);
164
 
165
    FIRCLSBinaryImageInit(&_firclsContext.readonly->binaryimage,
166
                          &_firclsContext.writable->binaryImage);
167
  });
168
 
169
  dispatch_group_async(group, queue, ^{
170
    NSString* rootPath = [NSString stringWithUTF8String:initData->previouslyCrashedFileRootPath];
171
    NSString* fileName = [NSString stringWithUTF8String:FIRCLSCrashedMarkerFileName];
172
    _firclsContext.readonly->previouslyCrashedFileFullPath =
173
        FIRCLSContextAppendToRoot(rootPath, fileName);
174
  });
175
 
176
  // To initialize Crashlytics handlers even if the Xcode debugger is attached, replace this check
177
  // with YES. Note that this is only possible to do on an actual device as it will cause the
178
  // simulator to crash.
179
  if (!_firclsContext.readonly->debuggerAttached) {
180
#if CLS_SIGNAL_SUPPORTED
181
    dispatch_group_async(group, queue, ^{
182
      _firclsContext.readonly->signal.path =
183
          FIRCLSContextAppendToRoot(rootPath, FIRCLSReportSignalFile);
184
 
185
      FIRCLSSignalInitialize(&_firclsContext.readonly->signal);
186
    });
187
#endif
188
 
189
#if CLS_MACH_EXCEPTION_SUPPORTED
190
    dispatch_group_async(group, queue, ^{
191
      _firclsContext.readonly->machException.path =
192
          FIRCLSContextAppendToRoot(rootPath, FIRCLSReportMachExceptionFile);
193
 
194
      FIRCLSMachExceptionInit(&_firclsContext.readonly->machException);
195
    });
196
#endif
197
 
198
    dispatch_group_async(group, queue, ^{
199
      _firclsContext.readonly->exception.path =
200
          FIRCLSContextAppendToRoot(rootPath, FIRCLSReportExceptionFile);
201
      _firclsContext.readonly->exception.maxCustomExceptions =
202
          initData->customExceptionsEnabled ? initData->maxCustomExceptions : 0;
203
 
204
      FIRCLSExceptionInitialize(&_firclsContext.readonly->exception,
205
                                &_firclsContext.writable->exception);
206
    });
207
  } else {
208
    FIRCLSSDKLog("Debugger present - not installing handlers\n");
209
  }
210
 
211
  dispatch_group_async(group, queue, ^{
212
    const char* metaDataPath = [[rootPath stringByAppendingPathComponent:FIRCLSReportMetadataFile]
213
        fileSystemRepresentation];
214
    if (!FIRCLSContextRecordMetadata(metaDataPath, initData)) {
215
      FIRCLSSDKLog("Unable to record context metadata\n");
216
    }
217
  });
218
 
219
  // At this point we need to do two things. First, we need to do our memory protection *only* after
220
  // all of these initialization steps are really done. But, we also want to wait as long as
221
  // possible for these to be complete. If we do not, there's a chance that we will not be able to
222
  // correctly report a crash shortly after start.
223
 
224
  // Note at this will retain the group, so its totally fine to release the group here.
225
  dispatch_group_notify(group, queue, ^{
226
    _firclsContext.readonly->initialized = true;
227
    __sync_synchronize();
228
 
229
    if (!FIRCLSAllocatorProtect(_firclsContext.allocator)) {
230
      FIRCLSSDKLog("Error: Memory protection failed\n");
231
    }
232
  });
233
 
234
  if (dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, FIRCLSContextInitWaitTime)) !=
235
      0) {
236
    FIRCLSSDKLog("Error: Delayed initialization\n");
237
  }
238
 
239
  return true;
240
}
241
 
242
void FIRCLSContextBaseInit(void) {
243
  NSString* sdkBundleID = FIRCLSApplicationGetSDKBundleID();
244
 
245
  NSString* loggingQueueName = [sdkBundleID stringByAppendingString:@".logging"];
246
  NSString* binaryImagesQueueName = [sdkBundleID stringByAppendingString:@".binary-images"];
247
  NSString* exceptionQueueName = [sdkBundleID stringByAppendingString:@".exception"];
248
 
249
  _firclsLoggingQueue = dispatch_queue_create([loggingQueueName UTF8String], DISPATCH_QUEUE_SERIAL);
250
  _firclsBinaryImageQueue =
251
      dispatch_queue_create([binaryImagesQueueName UTF8String], DISPATCH_QUEUE_SERIAL);
252
  _firclsExceptionQueue =
253
      dispatch_queue_create([exceptionQueueName UTF8String], DISPATCH_QUEUE_SERIAL);
254
 
255
  FIRCLSContextAllocate(&_firclsContext);
256
 
257
  _firclsContext.writable->internalLogging.logFd = -1;
258
  _firclsContext.writable->internalLogging.logLevel = FIRCLSInternalLogLevelDebug;
259
  _firclsContext.writable->crashOccurred = false;
260
 
261
  _firclsContext.readonly->initialized = false;
262
 
263
  __sync_synchronize();
264
}
265
 
266
static void FIRCLSContextAllocate(FIRCLSContext* context) {
267
  // create the allocator, and the contexts
268
  // The ordering here is really important, because the "stack" variable must be
269
  // page-aligned.  There's no mechanism to ask the allocator to do alignment, but we
270
  // do know the very first allocation in a region is aligned to a page boundary.
271
 
272
  context->allocator = FIRCLSAllocatorCreate(CLS_MINIMUM_READWRITE_SIZE, CLS_MINIMUM_READABLE_SIZE);
273
 
274
  context->readonly =
275
      FIRCLSAllocatorSafeAllocate(context->allocator, sizeof(FIRCLSReadOnlyContext), CLS_READONLY);
276
  memset(context->readonly, 0, sizeof(FIRCLSReadOnlyContext));
277
 
278
#if CLS_MEMORY_PROTECTION_ENABLED
279
#if CLS_MACH_EXCEPTION_SUPPORTED
280
  context->readonly->machStack = FIRCLSAllocatorSafeAllocate(
281
      context->allocator, CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE, CLS_READWRITE);
282
#endif
283
#if CLS_USE_SIGALTSTACK
284
  context->readonly->signalStack =
285
      FIRCLSAllocatorSafeAllocate(context->allocator, CLS_SIGNAL_HANDLER_STACK_SIZE, CLS_READWRITE);
286
#endif
287
#else
288
#if CLS_MACH_EXCEPTION_SUPPORTED
289
  context->readonly->machStack = valloc(CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE);
290
#endif
291
#if CLS_USE_SIGALTSTACK
292
  context->readonly->signalStack = valloc(CLS_SIGNAL_HANDLER_STACK_SIZE);
293
#endif
294
#endif
295
 
296
#if CLS_MACH_EXCEPTION_SUPPORTED
297
  memset(_firclsContext.readonly->machStack, 0, CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE);
298
#endif
299
#if CLS_USE_SIGALTSTACK
300
  memset(_firclsContext.readonly->signalStack, 0, CLS_SIGNAL_HANDLER_STACK_SIZE);
301
#endif
302
 
303
  context->writable = FIRCLSAllocatorSafeAllocate(context->allocator,
304
                                                  sizeof(FIRCLSReadWriteContext), CLS_READWRITE);
305
  memset(context->writable, 0, sizeof(FIRCLSReadWriteContext));
306
}
307
 
308
void FIRCLSContextBaseDeinit(void) {
309
  _firclsContext.readonly->initialized = false;
310
 
311
  FIRCLSAllocatorDestroy(_firclsContext.allocator);
312
}
313
 
314
bool FIRCLSContextIsInitialized(void) {
315
  __sync_synchronize();
316
  if (!FIRCLSIsValidPointer(_firclsContext.readonly)) {
317
    return false;
318
  }
319
 
320
  return _firclsContext.readonly->initialized;
321
}
322
 
323
bool FIRCLSContextHasCrashed(void) {
324
  if (!FIRCLSContextIsInitialized()) {
325
    return false;
326
  }
327
 
328
  // we've already run a full barrier above, so this read is ok
329
  return _firclsContext.writable->crashOccurred;
330
}
331
 
332
void FIRCLSContextMarkHasCrashed(void) {
333
  if (!FIRCLSContextIsInitialized()) {
334
    return;
335
  }
336
 
337
  _firclsContext.writable->crashOccurred = true;
338
  __sync_synchronize();
339
}
340
 
341
bool FIRCLSContextMarkAndCheckIfCrashed(void) {
342
  if (!FIRCLSContextIsInitialized()) {
343
    return false;
344
  }
345
 
346
  if (_firclsContext.writable->crashOccurred) {
347
    return true;
348
  }
349
 
350
  _firclsContext.writable->crashOccurred = true;
351
  __sync_synchronize();
352
 
353
  return false;
354
}
355
 
356
static const char* FIRCLSContextAppendToRoot(NSString* root, NSString* component) {
357
  return FIRCLSDupString(
358
      [[root stringByAppendingPathComponent:component] fileSystemRepresentation]);
359
}
360
 
361
static bool FIRCLSContextRecordIdentity(FIRCLSFile* file, const FIRCLSContextInitData* initData) {
362
  FIRCLSFileWriteSectionStart(file, "identity");
363
 
364
  FIRCLSFileWriteHashStart(file);
365
 
366
  FIRCLSFileWriteHashEntryString(file, "generator", FIRCLSSDKGeneratorName().UTF8String);
367
  FIRCLSFileWriteHashEntryString(file, "display_version", FIRCLSSDKVersion().UTF8String);
368
  FIRCLSFileWriteHashEntryString(file, "build_version", FIRCLSSDKVersion().UTF8String);
369
  FIRCLSFileWriteHashEntryUint64(file, "started_at", time(NULL));
370
 
371
  FIRCLSFileWriteHashEntryString(file, "session_id", initData->sessionId);
372
  // install_id is written into the proto directly. This is only left here to
373
  // support Apple Report Converter.
374
  FIRCLSFileWriteHashEntryString(file, "install_id", "");
375
  FIRCLSFileWriteHashEntryString(file, "beta_token", initData->betaToken);
376
  FIRCLSFileWriteHashEntryBoolean(file, "absolute_log_timestamps", true);
377
 
378
  FIRCLSFileWriteHashEnd(file);
379
  FIRCLSFileWriteSectionEnd(file);
380
 
381
  return true;
382
}
383
 
384
static bool FIRCLSContextRecordApplication(FIRCLSFile* file, const char* customBundleId) {
385
  FIRCLSFileWriteSectionStart(file, "application");
386
 
387
  FIRCLSFileWriteHashStart(file);
388
 
389
  FIRCLSFileWriteHashEntryString(file, "bundle_id",
390
                                 [FIRCLSApplicationGetBundleIdentifier() UTF8String]);
391
  FIRCLSFileWriteHashEntryString(file, "custom_bundle_id", customBundleId);
392
  FIRCLSFileWriteHashEntryString(file, "build_version",
393
                                 [FIRCLSApplicationGetBundleVersion() UTF8String]);
394
  FIRCLSFileWriteHashEntryString(file, "display_version",
395
                                 [FIRCLSApplicationGetShortBundleVersion() UTF8String]);
396
  FIRCLSFileWriteHashEntryString(file, "extension_id",
397
                                 [FIRCLSApplicationExtensionPointIdentifier() UTF8String]);
398
 
399
  FIRCLSFileWriteHashEnd(file);
400
  FIRCLSFileWriteSectionEnd(file);
401
 
402
  return true;
403
}
404
 
405
static bool FIRCLSContextRecordMetadata(const char* path, const FIRCLSContextInitData* initData) {
406
  if (!FIRCLSUnlinkIfExists(path)) {
407
    FIRCLSSDKLog("Unable to unlink existing metadata file %s\n", strerror(errno));
408
  }
409
 
410
  FIRCLSFile file;
411
 
412
  if (!FIRCLSFileInitWithPath(&file, path, false)) {
413
    FIRCLSSDKLog("Unable to open metadata file %s\n", strerror(errno));
414
    return false;
415
  }
416
 
417
  if (!FIRCLSContextRecordIdentity(&file, initData)) {
418
    FIRCLSSDKLog("Unable to write out identity metadata\n");
419
  }
420
 
421
  if (!FIRCLSHostRecord(&file)) {
422
    FIRCLSSDKLog("Unable to write out host metadata\n");
423
  }
424
 
425
  if (!FIRCLSContextRecordApplication(&file, initData->customBundleId)) {
426
    FIRCLSSDKLog("Unable to write out application metadata\n");
427
  }
428
 
429
  if (!FIRCLSBinaryImageRecordMainExecutable(&file)) {
430
    FIRCLSSDKLog("Unable to write out executable metadata\n");
431
  }
432
 
433
  FIRCLSFileClose(&file);
434
 
435
  return true;
436
}