bool FIRCLSContextInitialize()

in Crashlytics/Crashlytics/Components/FIRCLSContext.m [80:239]


bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
                             FIRCLSSettings* settings,
                             FIRCLSFileManager* fileManager) {
  FIRCLSContextInitData initDataObj = FIRCLSContextBuildInitData(report, settings, fileManager);
  FIRCLSContextInitData* initData = &initDataObj;

  if (!initData) {
    return false;
  }

  FIRCLSContextBaseInit();

  dispatch_group_t group = dispatch_group_create();
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

  if (!FIRCLSIsValidPointer(initData->rootPath)) {
    return false;
  }

  NSString* rootPath = [NSString stringWithUTF8String:initData->rootPath];

  // setup our SDK log file synchronously, because other calls may depend on it
  _firclsContext.readonly->logPath = FIRCLSContextAppendToRoot(rootPath, @"sdk.log");
  if (!FIRCLSUnlinkIfExists(_firclsContext.readonly->logPath)) {
    FIRCLSErrorLog(@"Unable to write initialize SDK write paths %s", strerror(errno));
  }

  // some values that aren't tied to particular subsystem
  _firclsContext.readonly->debuggerAttached = FIRCLSProcessDebuggerAttached();

  dispatch_group_async(group, queue, ^{
    FIRCLSHostInitialize(&_firclsContext.readonly->host);
  });

  dispatch_group_async(group, queue, ^{
    _firclsContext.readonly->logging.errorStorage.maxSize = 0;
    _firclsContext.readonly->logging.errorStorage.maxEntries =
        initData->errorsEnabled ? initData->maxCustomExceptions : 0;
    _firclsContext.readonly->logging.errorStorage.restrictBySize = false;
    _firclsContext.readonly->logging.errorStorage.entryCount =
        &_firclsContext.writable->logging.errorsCount;
    _firclsContext.readonly->logging.errorStorage.aPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportErrorAFile);
    _firclsContext.readonly->logging.errorStorage.bPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportErrorBFile);

    _firclsContext.readonly->logging.logStorage.maxSize = initData->maxLogSize;
    _firclsContext.readonly->logging.logStorage.maxEntries = 0;
    _firclsContext.readonly->logging.logStorage.restrictBySize = true;
    _firclsContext.readonly->logging.logStorage.entryCount = NULL;
    _firclsContext.readonly->logging.logStorage.aPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportLogAFile);
    _firclsContext.readonly->logging.logStorage.bPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportLogBFile);
    _firclsContext.readonly->logging.customExceptionStorage.aPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportCustomExceptionAFile);
    _firclsContext.readonly->logging.customExceptionStorage.bPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportCustomExceptionBFile);
    _firclsContext.readonly->logging.customExceptionStorage.maxSize = 0;
    _firclsContext.readonly->logging.customExceptionStorage.restrictBySize = false;
    _firclsContext.readonly->logging.customExceptionStorage.maxEntries =
        initData->maxCustomExceptions;
    _firclsContext.readonly->logging.customExceptionStorage.entryCount =
        &_firclsContext.writable->exception.customExceptionCount;

    _firclsContext.readonly->logging.userKVStorage.maxCount = initData->maxKeyValues;
    _firclsContext.readonly->logging.userKVStorage.incrementalPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportUserIncrementalKVFile);
    _firclsContext.readonly->logging.userKVStorage.compactedPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportUserCompactedKVFile);

    _firclsContext.readonly->logging.internalKVStorage.maxCount = 32;  // Hardcode = bad
    _firclsContext.readonly->logging.internalKVStorage.incrementalPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportInternalIncrementalKVFile);
    _firclsContext.readonly->logging.internalKVStorage.compactedPath =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportInternalCompactedKVFile);

    FIRCLSUserLoggingInit(&_firclsContext.readonly->logging, &_firclsContext.writable->logging);
  });

  dispatch_group_async(group, queue, ^{
    _firclsContext.readonly->binaryimage.path =
        FIRCLSContextAppendToRoot(rootPath, FIRCLSReportBinaryImageFile);

    FIRCLSBinaryImageInit(&_firclsContext.readonly->binaryimage,
                          &_firclsContext.writable->binaryImage);
  });

  dispatch_group_async(group, queue, ^{
    NSString* rootPath = [NSString stringWithUTF8String:initData->previouslyCrashedFileRootPath];
    NSString* fileName = [NSString stringWithUTF8String:FIRCLSCrashedMarkerFileName];
    _firclsContext.readonly->previouslyCrashedFileFullPath =
        FIRCLSContextAppendToRoot(rootPath, fileName);
  });

  // To initialize Crashlytics handlers even if the Xcode debugger is attached, replace this check
  // with YES. Note that this is only possible to do on an actual device as it will cause the
  // simulator to crash.
  if (!_firclsContext.readonly->debuggerAttached) {
#if CLS_SIGNAL_SUPPORTED
    dispatch_group_async(group, queue, ^{
      _firclsContext.readonly->signal.path =
          FIRCLSContextAppendToRoot(rootPath, FIRCLSReportSignalFile);

      FIRCLSSignalInitialize(&_firclsContext.readonly->signal);
    });
#endif

#if CLS_MACH_EXCEPTION_SUPPORTED
    dispatch_group_async(group, queue, ^{
      _firclsContext.readonly->machException.path =
          FIRCLSContextAppendToRoot(rootPath, FIRCLSReportMachExceptionFile);

      FIRCLSMachExceptionInit(&_firclsContext.readonly->machException);
    });
#endif

    dispatch_group_async(group, queue, ^{
      _firclsContext.readonly->exception.path =
          FIRCLSContextAppendToRoot(rootPath, FIRCLSReportExceptionFile);
      _firclsContext.readonly->exception.maxCustomExceptions =
          initData->customExceptionsEnabled ? initData->maxCustomExceptions : 0;

      FIRCLSExceptionInitialize(&_firclsContext.readonly->exception,
                                &_firclsContext.writable->exception);
    });
  } else {
    FIRCLSSDKLog("Debugger present - not installing handlers\n");
  }

  dispatch_group_async(group, queue, ^{
    const char* metaDataPath = [[rootPath stringByAppendingPathComponent:FIRCLSReportMetadataFile]
        fileSystemRepresentation];
    if (!FIRCLSContextRecordMetadata(metaDataPath, initData)) {
      FIRCLSSDKLog("Unable to record context metadata\n");
    }
  });

  // At this point we need to do two things. First, we need to do our memory protection *only* after
  // all of these initialization steps are really done. But, we also want to wait as long as
  // possible for these to be complete. If we do not, there's a chance that we will not be able to
  // correctly report a crash shortly after start.

  // Note at this will retain the group, so its totally fine to release the group here.
  dispatch_group_notify(group, queue, ^{
    _firclsContext.readonly->initialized = true;
    __sync_synchronize();

    if (!FIRCLSAllocatorProtect(_firclsContext.allocator)) {
      FIRCLSSDKLog("Error: Memory protection failed\n");
    }
  });

  if (dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, FIRCLSContextInitWaitTime)) !=
      0) {
    FIRCLSSDKLog("Error: Delayed initialization\n");
  }

  return true;
}