/** Load the persistent state portion of a crash context.
 *
 * @param path The path to the file to read.
 *
 * @return true if the operation was successful.
 */
static bool loadState(const char* const path)
{
    // Stop if the file doesn't exist.
    // This is expected on the first run of the app.
    const int fd = open(path, O_RDONLY);
    if(fd < 0)
    {
        return false;
    }
    close(fd);

    char* data;
    int length;
    if(!ksfu_readEntireFile(path, &data, &length, 50000))
    {
        KSLOG_ERROR("%s: Could not load file", path);
        return false;
    }

    KSJSONDecodeCallbacks callbacks;
    callbacks.onBeginArray = onBeginArray;
    callbacks.onBeginObject = onBeginObject;
    callbacks.onBooleanElement = onBooleanElement;
    callbacks.onEndContainer = onEndContainer;
    callbacks.onEndData = onEndData;
    callbacks.onFloatingPointElement = onFloatingPointElement;
    callbacks.onIntegerElement = onIntegerElement;
    callbacks.onNullElement = onNullElement;
    callbacks.onStringElement = onStringElement;

    int errorOffset = 0;

    char stringBuffer[1000];
    const int result = ksjson_decode(data,
                                     (int)length,
                                     stringBuffer,
                                     sizeof(stringBuffer),
                                     &callbacks,
                                     &g_state,
                                     &errorOffset);
    free(data);
    if(result != KSJSON_OK)
    {
        KSLOG_ERROR("%s, offset %d: %s",
                    path, errorOffset, ksjson_stringForError(result));
        return false;
    }
    return true;
}
Example #2
0
char* kscrf_fixupCrashReport(const char* crashReport)
{
    if(crashReport == NULL)
    {
        return NULL;
    }

    KSJSONDecodeCallbacks callbacks =
    {
        .onBeginArray = onBeginArray,
        .onBeginObject = onBeginObject,
        .onBooleanElement = onBooleanElement,
        .onEndContainer = onEndContainer,
        .onEndData = onEndData,
        .onFloatingPointElement = onFloatingPointElement,
        .onIntegerElement = onIntegerElement,
        .onNullElement = onNullElement,
        .onStringElement = onStringElement,
    };
    int stringBufferLength = 10000;
    char* stringBuffer = malloc((unsigned)stringBufferLength);
    int crashReportLength = (int)strlen(crashReport);
    int fixedReportLength = (int)(crashReportLength * 1.5);
    char* fixedReport = malloc((unsigned)fixedReportLength);
    KSJSONEncodeContext encodeContext;
    FixupContext fixupContext =
    {
        .encodeContext = &encodeContext,
        .currentDepth = 0,
        .outputPtr = fixedReport,
        .outputBytesLeft = fixedReportLength,
    };
    
    ksjson_beginEncode(&encodeContext, true, addJSONData, &fixupContext);
    
    int errorOffset = 0;
    int result = ksjson_decode(crashReport, (int)strlen(crashReport), stringBuffer, stringBufferLength, &callbacks, &fixupContext, &errorOffset);
    *fixupContext.outputPtr = '\0';
    free(stringBuffer);
    if(result != KSJSON_OK)
    {
        KSLOG_ERROR("Could not decode report: %s", ksjson_stringForError(result));
        free(fixedReport);
        return NULL;
    }
    return fixedReport;
}
/** Save the persistent state portion of a crash context.
 *
 * @param path The path to the file to create.
 *
 * @return true if the operation was successful.
 */
static bool saveState(const char* const path)
{
    int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if(fd < 0)
    {
        KSLOG_ERROR("Could not open file %s for writing: %s",
                    path,
                    strerror(errno));
        return false;
    }

    KSJSONEncodeContext JSONContext;
    ksjson_beginEncode(&JSONContext,
                       true,
                       addJSONData,
                       &fd);

    int result;
    if((result = ksjson_beginObject(&JSONContext, NULL)) != KSJSON_OK)
    {
        goto done;
    }
    if((result = ksjson_addIntegerElement(&JSONContext,
                                          kKeyFormatVersion,
                                          kFormatVersion)) != KSJSON_OK)
    {
        goto done;
    }
    // Record this launch crashed state into "crashed last launch" field.
    if((result = ksjson_addBooleanElement(&JSONContext,
                                          kKeyCrashedLastLaunch,
                                          g_state.crashedThisLaunch)) != KSJSON_OK)
    {
        goto done;
    }
    if((result = ksjson_addFloatingPointElement(&JSONContext,
                                                kKeyActiveDurationSinceLastCrash,
                                                g_state.activeDurationSinceLastCrash)) != KSJSON_OK)
    {
        goto done;
    }
    if((result = ksjson_addFloatingPointElement(&JSONContext,
                                                kKeyBackgroundDurationSinceLastCrash,
                                                g_state.backgroundDurationSinceLastCrash)) != KSJSON_OK)
    {
        goto done;
    }
    if((result = ksjson_addIntegerElement(&JSONContext,
                                          kKeyLaunchesSinceLastCrash,
                                          g_state.launchesSinceLastCrash)) != KSJSON_OK)
    {
        goto done;
    }
    if((result = ksjson_addIntegerElement(&JSONContext,
                                          kKeySessionsSinceLastCrash,
                                          g_state.sessionsSinceLastCrash)) != KSJSON_OK)
    {
        goto done;
    }
    result = ksjson_endEncode(&JSONContext);

done:
    close(fd);
    if(result != KSJSON_OK)
    {
        KSLOG_ERROR("%s: %s",
                    path, ksjson_stringForError(result));
        return false;
    }
    return true;
}