Merge branch 'feature/metrics/events-crash-callback' into feature/metrics/develop

# Conflicts:
#	Classes/BITChannel.h
#	Classes/BITChannel.m
This commit is contained in:
Lukas Spieß
2016-03-17 19:25:01 +01:00
5 changed files with 95 additions and 48 deletions

View File

@@ -40,6 +40,7 @@ FOUNDATION_EXPORT char *BITSafeJsonEventsString;
- (BOOL)enqueueTelemetryItem:(BITTelemetryData *)item;
@end
NS_ASSUME_NONNULL_END
#endif /* HOCKEYSDK_FEATURE_METRICS */

View File

@@ -162,27 +162,26 @@ NS_ASSUME_NONNULL_BEGIN
// Since we can't persist every event right away, we write it to a simple C string.
// This can then be written to disk by a signal handler in case of a crash.
bit_appendStringToSafeJsonStream(string, &(BITSafeJsonEventsString));
BITSafeJsonEventsString = bit_jsonStreamByAppendingJsonString(BITSafeJsonEventsString, string);
_dataItemCount += 1;
}
}
void bit_appendStringToSafeJsonStream(NSString *string, char **jsonString) {
if (jsonString == NULL) { return; }
char * bit_jsonStreamByAppendingJsonString(char *json_stream, NSString *jsonString) {
if ((json_stream == NULL) || !json_stream) {
if (!string) { return; }
if (*jsonString == NULL || strlen(*jsonString) == 0) {
bit_resetSafeJsonStream(jsonString);
return strdup("");
}
if (string.length == 0) { return; }
if (!jsonString || (jsonString.length == 0)) {
return json_stream;
}
char *new_string = NULL;
// Concatenate old string with new JSON string and add a comma.
asprintf(&new_string, "%s%.*s\n", *jsonString, (int)MIN(string.length, (NSUInteger)INT_MAX), string.UTF8String);
free(*jsonString);
*jsonString = new_string;
char *concatenated_string = NULL;
// Concatenate old string with new JSON string and add a new line.
asprintf(&concatenated_string, "%s%.*s\n", json_stream, (int)MIN(jsonString.length, (NSUInteger)INT_MAX), jsonString.UTF8String);
return concatenated_string;
}
void bit_resetSafeJsonStream(char **string) {

View File

@@ -73,16 +73,16 @@ NS_ASSUME_NONNULL_BEGIN
/**
* A C function that serializes a given dictionary to JSON and appends it to a char string
*
* @param dictionary A dictionary which will be serialized to JSON and then appended to the string.
* @param string The C string which the dictionary's JSON representation will be appended to.
* @param existing_json_stream A C string containing JSON items in the JSON Stream format.
* @param jsonString A NSString object containing a valid JSON item.
*/
void bit_appendStringToSafeJsonStream(NSString *string, char *__nonnull*__nonnull jsonStream);
char * bit_jsonStreamByAppendingJsonString(char *existing_json_stream, NSString *jsonString);
/**
* Reset BITSafeJsonEventsString so we can start appending JSON dictionaries.
*
* @param string The string that will be reset.
*/
* Reset BITSafeJsonEventsString so we can start appending JSON dictionaries.
*
* @param string The string that will be reset.
*/
void bit_resetSafeJsonStream(char *__nonnull*__nonnull jsonStream);
/**

View File

@@ -28,7 +28,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#import "HockeySDK.h"
#import "HockeySDKFeatureConfig.h"
#if HOCKEYSDK_FEATURE_CRASH_REPORTER
@@ -39,13 +39,20 @@
#import "BITHockeyHelper.h"
#import "BITHockeyAppClient.h"
#import "BITCrashManager.h"
#import "BITCrashManagerPrivate.h"
#import "BITCrashAttachment.h"
#import "BITHockeyBaseManagerPrivate.h"
#import "BITCrashManagerPrivate.h"
#import "BITCrashReportTextFormatter.h"
#import "BITCrashDetailsPrivate.h"
#import "BITCrashCXXExceptionHandler.h"
#if HOCKEYSDK_FEATURE_METRICS
#import "BITMetricsManagerPrivate.h"
#import "BITChannel.h"
#import "BITPersistencePrivate.h"
#endif
#include <sys/sysctl.h>
// stores the set of crashreports that have been approved but aren't sent yet
@@ -81,16 +88,40 @@ static NSString *const kBITFakeCrashDeviceModel = @"BITFakeCrashDeviceModel";
static NSString *const kBITFakeCrashAppBinaryUUID = @"BITFakeCrashAppBinaryUUID";
static NSString *const kBITFakeCrashReport = @"BITFakeCrashAppString";
#if HOCKEYSDK_FEATURE_METRICS
static char const *BITSaveEventsFilePath;
#endif
static BITCrashManagerCallbacks bitCrashCallbacks = {
.context = NULL,
.handleSignal = NULL
};
// proxy implementation for PLCrashReporter to keep our interface stable while this can change
#if HOCKEYSDK_FEATURE_METRICS
static void bit_save_events_callback(siginfo_t *info, ucontext_t *uap, void *context) {
// Try to get a file descriptor with our pre-filled path
int fd = open(BITSaveEventsFilePath, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
return;
}
size_t len = strlen(BITSafeJsonEventsString);
if (len > 0) {
// Simply write the whole string to disk
write(fd, BITSafeJsonEventsString, len);
}
close(fd);
}
#endif
// Proxy implementation for PLCrashReporter to keep our interface stable while this can change
static void plcr_post_crash_callback (siginfo_t *info, ucontext_t *uap, void *context) {
if (bitCrashCallbacks.handleSignal != NULL)
#if HOCKEYSDK_FEATURE_METRICS
bit_save_events_callback(info, uap, context);
#endif
if (bitCrashCallbacks.handleSignal != NULL) {
bitCrashCallbacks.handleSignal(context);
}
}
static PLCrashReporterCallbacks plCrashCallbacks = {
@@ -99,7 +130,6 @@ static PLCrashReporterCallbacks plCrashCallbacks = {
.handleSignal = plcr_post_crash_callback
};
// Temporary class until PLCR catches up
// We trick PLCR with an Objective-C exception.
//
@@ -154,8 +184,6 @@ static void uncaught_cxx_exception_handler(const BITCrashUncaughtCXXExceptionInf
NSString *_settingsFile;
NSString *_analyzerInProgressFile;
NSFileManager *_fileManager;
PLCrashReporterCallbacks *_crashCallBacks;
BOOL _crashIdenticalCurrentVersion;
@@ -183,7 +211,6 @@ static void uncaught_cxx_exception_handler(const BITCrashUncaughtCXXExceptionInf
_plCrashReporter = nil;
_exceptionHandler = nil;
_crashCallBacks = nil;
_crashIdenticalCurrentVersion = YES;
@@ -657,17 +684,18 @@ static void uncaught_cxx_exception_handler(const BITCrashUncaughtCXXExceptionInf
return useremail;
}
#pragma mark - Public
#pragma mark - CrashCallbacks
/**
* Set the callback for PLCrashReporter
*
* @param callbacks BITCrashManagerCallbacks instance
*/
- (void)setCrashCallbacks: (BITCrashManagerCallbacks *) callbacks {
- (void)setCrashCallbacks:(BITCrashManagerCallbacks *)callbacks {
if (!callbacks) return;
if (_isSetup) {
BITHockeyLog(@"CrashCallbacks need to be configured before calling startManager!");
}
// set our proxy callback struct
bitCrashCallbacks.context = callbacks->context;
@@ -675,10 +703,17 @@ static void uncaught_cxx_exception_handler(const BITCrashUncaughtCXXExceptionInf
// set the PLCrashReporterCallbacks struct
plCrashCallbacks.context = callbacks->context;
_crashCallBacks = &plCrashCallbacks;
}
#if HOCKEYSDK_FEATURE_METRICS
- (void)configDefaultCrashCallback {
BITMetricsManager *metricsManager = [BITHockeyManager sharedHockeyManager].metricsManager;
BITPersistence *persistence = metricsManager.persistence;
BITSaveEventsFilePath = strdup([persistence fileURLForType:BITPersistenceTypeTelemetry].UTF8String);
}
#endif
#pragma mark - Public
- (void)setAlertViewHandler:(BITCustomAlertViewHandler)alertViewHandler{
_alertViewHandler = alertViewHandler;
@@ -1146,10 +1181,11 @@ static void uncaught_cxx_exception_handler(const BITCrashUncaughtCXXExceptionInf
// can't break this
NSError *error = NULL;
// set any user defined callbacks, hopefully the users knows what they do
if (_crashCallBacks) {
[self.plCrashReporter setCrashCallbacks:_crashCallBacks];
}
#if HOCKEYSDK_FEATURE_METRICS
[self configDefaultCrashCallback];
#endif
// Set plCrashReporter callback which contains our default callback and potentially user defined callbacks
[self.plCrashReporter setCrashCallbacks:&plCrashCallbacks];
// Enable the Crash Reporter
if (![self.plCrashReporter enableCrashReporterAndReturnError: &error])

View File

@@ -31,7 +31,6 @@
BITTelemetryContext *mockContext = mock(BITTelemetryContext.class);
_sut = [[BITChannel alloc]initWithTelemetryContext:mockContext persistence:_mockPersistence];
BITSafeJsonEventsString = NULL;
}
#pragma mark - Setup Tests
@@ -88,34 +87,46 @@
- (void)testAppendStringToSafeJsonStream {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
bit_appendStringToSafeJsonStream(nil, 0);
BITSafeJsonEventsString = bit_jsonStreamByAppendingJsonString(0, nil);
#pragma clang diagnostic pop
XCTAssertTrue(BITSafeJsonEventsString == NULL);
XCTAssertEqual(strcmp(BITSafeJsonEventsString, ""), 0);
BITSafeJsonEventsString = NULL;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
bit_appendStringToSafeJsonStream(nil, &BITSafeJsonEventsString);
BITSafeJsonEventsString = bit_jsonStreamByAppendingJsonString(NULL, nil);
#pragma clang diagnostic pop
XCTAssertTrue(BITSafeJsonEventsString == NULL);
XCTAssertEqual(strcmp(BITSafeJsonEventsString, ""), 0);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
BITSafeJsonEventsString = bit_jsonStreamByAppendingJsonString(nil, nil);
#pragma clang diagnostic pop
XCTAssertEqual(strcmp(BITSafeJsonEventsString, ""), 0);
bit_appendStringToSafeJsonStream(@"", &BITSafeJsonEventsString);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
BITSafeJsonEventsString = bit_jsonStreamByAppendingJsonString(NULL, @"");
#pragma clang diagnostic pop
XCTAssertEqual(strcmp(BITSafeJsonEventsString,""), 0);
bit_appendStringToSafeJsonStream(@"{\"Key1\":\"Value1\"}", &BITSafeJsonEventsString);
BITSafeJsonEventsString = bit_jsonStreamByAppendingJsonString("", @"{\"Key1\":\"Value1\"}");
XCTAssertEqual(strcmp(BITSafeJsonEventsString,"{\"Key1\":\"Value1\"}\n"), 0);
}
- (void)testResetSafeJsonStream {
BITSafeJsonEventsString = NULL;
bit_resetSafeJsonStream(&BITSafeJsonEventsString);
XCTAssertEqual(strcmp(BITSafeJsonEventsString,""), 0);
BITSafeJsonEventsString = NULL;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
bit_resetSafeJsonStream(NULL);
#pragma clang diagnostic pop
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
bit_resetSafeJsonStream(nil);
#pragma clang diagnostic pop
XCTAssertEqual(BITSafeJsonEventsString, NULL);
BITSafeJsonEventsString = strdup("test string");
bit_resetSafeJsonStream(&BITSafeJsonEventsString);