Skip to content

Commit

Permalink
Crashlytics add new Record Exception Model API (#5055)
Browse files Browse the repository at this point in the history
  • Loading branch information
samedson authored Mar 16, 2020
1 parent 956fb1b commit 31e054a
Show file tree
Hide file tree
Showing 32 changed files with 699 additions and 188 deletions.
19 changes: 17 additions & 2 deletions Crashlytics/Crashlytics/Components/FIRCLSContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@

__BEGIN_DECLS

#ifdef __OBJC__
@class FIRCLSInternalReport;
@class FIRCLSSettings;
@class FIRCLSInstallIdentifierModel;
@class FIRCLSFileManager;
#endif

typedef struct {
volatile bool initialized;
volatile bool debuggerAttached;
Expand Down Expand Up @@ -90,10 +97,18 @@ typedef struct {
uint32_t maxKeyValues;
} FIRCLSContextInitData;

bool FIRCLSContextInitialize(const FIRCLSContextInitData* initData);
#ifdef __OBJC__
bool FIRCLSContextInitialize(FIRCLSInternalReport* report,
FIRCLSSettings* settings,
FIRCLSInstallIdentifierModel* installIDModel,
FIRCLSFileManager* fileManager);

// Re-writes the metadata file on the current thread
void FIRCLSContextUpdateMetadata(const FIRCLSContextInitData* initData);
void FIRCLSContextUpdateMetadata(FIRCLSInternalReport* report,
FIRCLSSettings* settings,
FIRCLSInstallIdentifierModel* installIDModel,
FIRCLSFileManager* fileManager);
#endif

void FIRCLSContextBaseInit(void);
void FIRCLSContextBaseDeinit(void);
Expand Down
71 changes: 68 additions & 3 deletions Crashlytics/Crashlytics/Components/FIRCLSContext.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
#include <stdlib.h>
#include <string.h>

#import "FIRCLSFileManager.h"
#import "FIRCLSInstallIdentifierModel.h"
#import "FIRCLSInternalReport.h"
#import "FIRCLSSettings.h"

#include "FIRCLSApplication.h"
#include "FIRCLSCrashedMarkerFile.h"
#include "FIRCLSDefines.h"
#include "FIRCLSFeatures.h"
#include "FIRCLSGlobals.h"
#include "FIRCLSInternalReport.h"
#include "FIRCLSProcess.h"
#include "FIRCLSUtility.h"

Expand All @@ -45,7 +49,61 @@
static const char* FIRCLSContextAppendToRoot(NSString* root, NSString* component);
static void FIRCLSContextAllocate(FIRCLSContext* context);

bool FIRCLSContextInitialize(const FIRCLSContextInitData* initData) {
FIRCLSContextInitData FIRCLSContextBuildInitData(FIRCLSInternalReport* report,
FIRCLSSettings* settings,
FIRCLSInstallIdentifierModel* installIDModel,
FIRCLSFileManager* fileManager) {
// Because we need to start the crash reporter right away,
// it starts up either with default settings, or cached settings
// from the last time they were fetched

FIRCLSContextInitData initData;

memset(&initData, 0, sizeof(FIRCLSContextInitData));

initData.customBundleId = nil;
initData.installId = [installIDModel.installID UTF8String];
initData.sessionId = [[report identifier] UTF8String];
initData.rootPath = [[report path] UTF8String];
initData.previouslyCrashedFileRootPath = [[fileManager rootPath] UTF8String];
initData.errorsEnabled = [settings errorReportingEnabled];
initData.customExceptionsEnabled = [settings customExceptionsEnabled];
initData.maxCustomExceptions = [settings maxCustomExceptions];
initData.maxErrorLogSize = [settings errorLogBufferSize];
initData.maxLogSize = [settings logBufferSize];
initData.maxKeyValues = [settings maxCustomKeys];

// If this is set, then we could attempt to do a synchronous submission for certain kinds of
// events (exceptions). This is a very cool feature, but adds complexity to the backend. For now,
// we're going to leave this disabled. It does work in the exception case, but will ultimtely
// result in the following crash to be discared. Usually that crash isn't interesting. But, if it
// was, we'd never have a chance to see it.
initData.delegate = nil;

#if CLS_MACH_EXCEPTION_SUPPORTED
__block exception_mask_t mask = 0;

// TODO(b/141241224) This if statement was hardcoded to no, so this block was never run
// FIRCLSSignalEnumerateHandledSignals(^(int idx, int signal) {
// if ([self.delegate ensureDeliveryOfUnixSignal:signal]) {
// mask |= FIRCLSMachExceptionMaskForSignal(signal);
// }
// });

initData.machExceptionMask = mask;
#endif

return initData;
}

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

if (!initData) {
return false;
}
Expand Down Expand Up @@ -197,7 +255,14 @@ bool FIRCLSContextInitialize(const FIRCLSContextInitData* initData) {
return true;
}

void FIRCLSContextUpdateMetadata(const FIRCLSContextInitData* initData) {
void FIRCLSContextUpdateMetadata(FIRCLSInternalReport* report,
FIRCLSSettings* settings,
FIRCLSInstallIdentifierModel* installIDModel,
FIRCLSFileManager* fileManager) {
FIRCLSContextInitData initDataObj =
FIRCLSContextBuildInitData(report, settings, installIDModel, fileManager);
FIRCLSContextInitData* initData = &initDataObj;

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

const char* metaDataPath =
Expand Down
70 changes: 4 additions & 66 deletions Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,7 @@ - (void)checkAndRotateInstallUUIDIfNeededWithReport:(FIRCLSInternalReport *)repo
return;
}

FIRCLSContextInitData initData = [self initializeContextInitData:report];

FIRCLSContextUpdateMetadata(&initData);
FIRCLSContextUpdateMetadata(report, self.settings, self.installIDModel, self->_fileManager);
}];
}

Expand All @@ -473,53 +471,18 @@ - (void)startNetworkRequestsWithToken:(FIRCLSDataCollectionToken *)token
[self handleContentsInOtherReportingDirectoriesWithToken:token];
}

- (FIRCLSContextInitData)initializeContextInitData:(FIRCLSInternalReport *)report {
FIRCLSContextInitData initData;

memset(&initData, 0, sizeof(FIRCLSContextInitData));

// Because we need to start the crash reporter right away,
// it starts up either with default settings, or cached settings
// from the last time they were fetched
FIRCLSSettings *settings = self.settings;

initData.customBundleId = NULL;
initData.installId = [self.installIDModel.installID UTF8String];
initData.sessionId = [[report identifier] UTF8String];
initData.rootPath = [[report path] UTF8String];
initData.previouslyCrashedFileRootPath = [[_fileManager rootPath] UTF8String];
#if CLS_MACH_EXCEPTION_SUPPORTED
initData.machExceptionMask = [self machExceptionMask];
#endif
initData.errorsEnabled = [settings errorReportingEnabled];
initData.customExceptionsEnabled = [settings customExceptionsEnabled];
initData.maxCustomExceptions = [settings maxCustomExceptions];
initData.maxErrorLogSize = [settings errorLogBufferSize];
initData.maxLogSize = [settings logBufferSize];
initData.maxKeyValues = [settings maxCustomKeys];

return initData;
}

- (BOOL)startCrashReporterWithProfilingMark:(FIRCLSProfileMark)mark
report:(FIRCLSInternalReport *)report {
if (!report) {
return NO;
}

FIRCLSContextInitData initData = [self initializeContextInitData:report];

// If this is set, then we could attempt to do a synchronous submission for certain kinds of
// events (exceptions). This is a very cool feature, but adds complexity to the backend. For now,
// we're going to leave this disabled. It does work in the exception case, but will ultimtely
// result in the following crash to be discared. Usually that crash isn't interesting. But, if it
// was, we'd never have a chance to see it.
initData.delegate = NULL;

if (![self installCrashReportingHandlers:&initData]) {
if (!FIRCLSContextInitialize(report, self.settings, self.installIDModel, _fileManager)) {
return NO;
}

[self setupStateNotifications];

[self registerAnalyticsEventListener];

[self crashReportingSetupCompleted:mark];
Expand Down Expand Up @@ -569,33 +532,8 @@ - (FIRCLSReportUploader *)uploader {
return _uploader;
}

#if CLS_MACH_EXCEPTION_SUPPORTED
- (exception_mask_t)machExceptionMask {
__block exception_mask_t mask = 0;

// TODO(b/141241224) This if statement was hardcoded to no, so this block was never run
// FIRCLSSignalEnumerateHandledSignals(^(int idx, int signal) {
// if ([self.delegate ensureDeliveryOfUnixSignal:signal]) {
// mask |= FIRCLSMachExceptionMaskForSignal(signal);
// }
// });

return mask;
}
#endif

#pragma mark - Reporting Lifecycle

- (BOOL)installCrashReportingHandlers:(FIRCLSContextInitData *)initData {
if (!FIRCLSContextInitialize(initData)) {
return NO;
}

[self setupStateNotifications];

return YES;
}

- (FIRCLSInternalReport *)setupCurrentReport:(NSString *)executionIdentifier {
[self createLaunchFailureMarker];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#import "FIRCLSReportManager.h"
#import "FIRCLSReportUploader.h"

@class FIRCLSInstallIdentifierModel;

@interface FIRCLSReportManager () <FIRCLSReportUploaderDelegate, FIRCLSReportUploaderDataSource>

@property(nonatomic, strong) NSOperationQueue *operationQueue;
Expand Down
7 changes: 2 additions & 5 deletions Crashlytics/Crashlytics/FIRCrashlytics.m
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,8 @@ - (void)recordError:(NSError *)error {
FIRCLSUserLoggingRecordError(error, nil);
}

- (void)recordCustomExceptionName:(NSString *)name
reason:(NSString *)reason
frameArray:(NSArray<FIRCLSStackFrame *> *)frameArray {
FIRCLSExceptionRecord(FIRCLSExceptionTypeCustom, [[name copy] UTF8String],
[[reason copy] UTF8String], [frameArray copy], NO);
- (void)recordExceptionModel:(FIRExceptionModel *)exceptionModel {
FIRCLSExceptionRecordModel(exceptionModel);
}

@end
42 changes: 42 additions & 0 deletions Crashlytics/Crashlytics/FIRExceptionModel.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2020 Google
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "FIRExceptionModel.h"

@interface FIRExceptionModel ()

@property(nonatomic, copy) NSString *name;
@property(nonatomic, copy) NSString *reason;

@end

@implementation FIRExceptionModel

- (instancetype)initWithName:(NSString *)name reason:(NSString *)reason {
self = [super init];
if (!self) {
return nil;
}

_name = [name copy];
_reason = [reason copy];

return self;
}

+ (instancetype)exceptionModelWithName:(NSString *)name reason:(NSString *)reason {
return [[FIRExceptionModel alloc] initWithName:name reason:reason];
}

@end
94 changes: 94 additions & 0 deletions Crashlytics/Crashlytics/FIRStackFrame.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright 2020 Google
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "FIRStackFrame_Private.h"

@interface FIRStackFrame ()

@property(nonatomic, copy, nullable) NSString *symbol;
@property(nonatomic, copy, nullable) NSString *rawSymbol;
@property(nonatomic, copy, nullable) NSString *library;
@property(nonatomic, copy, nullable) NSString *fileName;
@property(nonatomic, assign) uint32_t lineNumber;
@property(nonatomic, assign) uint64_t offset;
@property(nonatomic, assign) uint64_t address;

@property(nonatomic, assign) BOOL isSymbolicated;

@end

@implementation FIRStackFrame

#pragma mark - Public Methods

- (instancetype)initWithSymbol:(NSString *)symbol file:(NSString *)file line:(NSInteger)line {
self = [super init];
if (!self) {
return nil;
}

_symbol = [symbol copy];
_fileName = [file copy];
_lineNumber = (uint32_t)line;

_isSymbolicated = true;

return self;
}

+ (instancetype)stackFrameWithSymbol:(NSString *)symbol file:(NSString *)file line:(NSInteger)line {
return [[FIRStackFrame alloc] initWithSymbol:symbol file:file line:line];
}

#pragma mark - Internal Methods

+ (instancetype)stackFrame {
return [[self alloc] init];
}

+ (instancetype)stackFrameWithAddress:(NSUInteger)address {
FIRStackFrame *frame = [self stackFrame];

[frame setAddress:address];

return frame;
}

+ (instancetype)stackFrameWithSymbol:(NSString *)symbol {
FIRStackFrame *frame = [self stackFrame];

frame.symbol = symbol;
frame.rawSymbol = symbol;

return frame;
}

#pragma mark - Overrides

- (NSString *)description {
if (self.isSymbolicated) {
return [NSString
stringWithFormat:@"{%@ - %@:%u}", [self fileName], [self symbol], [self lineNumber]];
}

if (self.fileName) {
return [NSString stringWithFormat:@"{[0x%llx] %@ - %@:%u}", [self address], [self fileName],
[self symbol], [self lineNumber]];
}

return [NSString
stringWithFormat:@"{[0x%llx + %u] %@}", [self address], [self lineNumber], [self symbol]];
}

@end
Loading

0 comments on commit 31e054a

Please sign in to comment.