Skip to content

Commit

Permalink
Merge e07c7fa into d031a9c
Browse files Browse the repository at this point in the history
  • Loading branch information
fractalwrench committed Feb 15, 2019
2 parents d031a9c + e07c7fa commit 6e60b21
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 28 deletions.
20 changes: 20 additions & 0 deletions features/fixtures/mazerunner/src/main/cpp/bugsnags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,26 @@ Java_com_bugsnag_android_mazerunner_scenarios_CXXAutoContextScenario_activate(JN
(char *)"This is a new world", BSG_SEVERITY_INFO);
}

JNIEXPORT int JNICALL
Java_com_bugsnag_android_mazerunner_scenarios_CXXStartSessionScenario_crash(JNIEnv *env,
jobject instance,
jint value) {
int x = 22;
if (x > 0)
__builtin_trap();
return 338;
}

JNIEXPORT int JNICALL
Java_com_bugsnag_android_mazerunner_scenarios_CXXStopSessionScenario_crash(JNIEnv *env,
jobject instance,
jint value) {
int x = 22552;
if (x > 0)
__builtin_trap();
return 555;
}

JNIEXPORT int JNICALL
Java_com_bugsnag_android_mazerunner_scenarios_CXXUpdateContextCrashScenario_crash(JNIEnv *env,
jobject instance,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.bugsnag.android.mazerunner.scenarios;

import android.content.Context;

import com.bugsnag.android.Bugsnag;
import com.bugsnag.android.Configuration;

import android.support.annotation.NonNull;

public class CXXStartSessionScenario extends Scenario {
static {
System.loadLibrary("bugsnag-ndk");
System.loadLibrary("monochrome");
System.loadLibrary("entrypoint");
}

public native int crash(int counter);

public CXXStartSessionScenario(@NonNull Configuration config, @NonNull Context context) {
super(config, context);
config.setAutoCaptureSessions(false);
}

@Override
public void run() {
super.run();
String metadata = getEventMetaData();

if (metadata == null || !metadata.equals("non-crashy")) {
Bugsnag.getClient().startSession();
crash(0);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.bugsnag.android.mazerunner.scenarios;

import android.content.Context;

import com.bugsnag.android.Bugsnag;
import com.bugsnag.android.Configuration;

import android.support.annotation.NonNull;

public class CXXStopSessionScenario extends Scenario {
static {
System.loadLibrary("bugsnag-ndk");
System.loadLibrary("monochrome");
System.loadLibrary("entrypoint");
}

public native int crash(int counter);

public CXXStopSessionScenario(@NonNull Configuration config, @NonNull Context context) {
super(config, context);
config.setAutoCaptureSessions(false);
}

@Override
public void run() {
super.run();
String metadata = getEventMetaData();

if (metadata == null || !metadata.equals("non-crashy")) {
Bugsnag.getClient().startSession();
Bugsnag.getClient().stopSession();
crash(0);
}
}
}
19 changes: 19 additions & 0 deletions features/native_session_tracking.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Feature: NDK Session Tracking

Scenario: Started session is in payload of unhandled NDK error
When I run "CXXStartSessionScenario"
And I configure the app to run in the "non-crashy" state
And I relaunch the app
Then I should receive 2 requests
And the request 0 is a valid for the session tracking API
And the request 1 is a valid for the error reporting API
And the payload field "events.0.session.events.unhandled" equals 1 for request 1

Scenario: Stopped session is not in payload of unhandled NDK error
When I run "CXXStopSessionScenario"
And I configure the app to run in the "non-crashy" state
And I relaunch the app
Then I should receive 2 requests
And the request 0 is a valid for the session tracking API
And the request 1 is a valid for the error reporting API
And the payload field "events.0.session" is null for request 1
20 changes: 16 additions & 4 deletions ndk/src/main/java/com/bugsnag/android/ndk/NativeBridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ public static native void addBreadcrumb(String name, String type, String timesta

public static native void removeMetadata(String tab, String key);

public static native void startedSession(String sessionID, String key);
public static native void startedSession(String sessionID, String key, int handledCount);

public static native void stoppedSession();

public static native void updateAppVersion(String appVersion);

Expand Down Expand Up @@ -131,6 +133,9 @@ public void update(Observable observable, Object rawMessage) {
case START_SESSION:
handleStartSession(arg);
break;
case STOP_SESSION:
handleStopSession();
break;
case UPDATE_APP_VERSION:
handleAppVersionChange(arg);
break;
Expand Down Expand Up @@ -313,11 +318,14 @@ private void handleStartSession(Object arg) {
if (arg instanceof List) {
@SuppressWarnings("unchecked")
List<Object> metadata = (List<Object>)arg;
if (metadata.size() == 2) {
if (metadata.size() == 3) {
Object id = metadata.get(0);
Object startTime = metadata.get(1);
if (id instanceof String && startTime instanceof String) {
startedSession((String)id, (String)startTime);
Object handledCount = metadata.get(2);

if (id instanceof String && startTime instanceof String
&& handledCount instanceof Integer) {
startedSession((String)id, (String)startTime, (Integer) handledCount);
return;
}
}
Expand All @@ -326,6 +334,10 @@ private void handleStartSession(Object arg) {
warn("START_SESSION object is invalid: " + arg);
}

private void handleStopSession() {
stoppedSession();
}

private void handleReleaseStageChange(Object arg) {
if (arg instanceof String) {
updateReleaseStage((String)arg);
Expand Down
21 changes: 18 additions & 3 deletions ndk/src/main/jni/bugsnag_ndk.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,24 +121,39 @@ Java_com_bugsnag_android_ndk_NativeBridge_addHandledEvent(JNIEnv *env,
if (bsg_global_env == NULL)
return;
bsg_request_env_write_lock();
bsg_global_env->next_report.handled_events++;
bugsnag_report *report = &bsg_global_env->next_report;

if (report->stoppedSession) {
report->handled_events++;
}
bsg_release_env_write_lock();
}

JNIEXPORT void JNICALL Java_com_bugsnag_android_ndk_NativeBridge_startedSession(
JNIEnv *env, jobject _this, jstring session_id_, jstring start_date_) {
JNIEnv *env, jobject _this, jstring session_id_, jstring start_date_, jint handled_count) {
if (bsg_global_env == NULL || session_id_ == NULL)
return;
char *session_id = (char *)(*env)->GetStringUTFChars(env, session_id_, 0);
char *started_at = (char *)(*env)->GetStringUTFChars(env, start_date_, 0);
bsg_request_env_write_lock();
bugsnag_report_start_session(&bsg_global_env->next_report, session_id,
started_at);
started_at, (int) handled_count);
bsg_release_env_write_lock();
(*env)->ReleaseStringUTFChars(env, session_id_, session_id);
(*env)->ReleaseStringUTFChars(env, start_date_, started_at);
}

JNIEXPORT void JNICALL Java_com_bugsnag_android_ndk_NativeBridge_stoppedSession(
JNIEnv *env, jobject _this) {
if (bsg_global_env == NULL) {
return;
}
bsg_request_env_write_lock();
bugsnag_report *report = &bsg_global_env->next_report;
report->stoppedSession = true;
bsg_release_env_write_lock();
}

JNIEXPORT void JNICALL
Java_com_bugsnag_android_ndk_NativeBridge_clearBreadcrumbs(JNIEnv *env,
jobject _this) {
Expand Down
1 change: 1 addition & 0 deletions ndk/src/main/jni/metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ void bsg_populate_report(JNIEnv *env, bugsnag_report *report) {
bsg_populate_app_data(env, jni_cache, report);
bsg_populate_device_data(env, jni_cache, report);
bsg_populate_user_data(env, jni_cache, report);
report->stoppedSession = false;
}
void bsg_populate_metadata(JNIEnv *env, bugsnag_report *report,
jobject metadata) {
Expand Down
5 changes: 3 additions & 2 deletions ndk/src/main/jni/report.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,12 @@ void bugsnag_report_remove_metadata_tab(bugsnag_report *report, char *section) {
}

void bugsnag_report_start_session(bugsnag_report *report, char *session_id,
char *started_at) {
char *started_at, int handled_count) {
bsg_strncpy_safe(report->session_id, session_id, sizeof(report->session_id));
bsg_strncpy_safe(report->session_start, started_at,
sizeof(report->session_start));
report->handled_events = 0;
report->handled_events = handled_count;
report->stoppedSession = false;
}

void bugsnag_report_set_context(bugsnag_report *report, char *value) {
Expand Down
3 changes: 2 additions & 1 deletion ndk/src/main/jni/report.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ typedef struct {
char session_id[33];
char session_start[33];
int handled_events;
bool stoppedSession;
} bugsnag_report;

void bugsnag_report_add_metadata_double(bugsnag_report *report, char *section,
Expand All @@ -315,7 +316,7 @@ void bugsnag_report_set_user_email(bugsnag_report *report, char *value);
void bugsnag_report_set_user_id(bugsnag_report *report, char *value);
void bugsnag_report_set_user_name(bugsnag_report *report, char *value);
void bugsnag_report_start_session(bugsnag_report *report, char *session_id,
char *started_at);
char *started_at, int handled_count);
#ifdef __cplusplus
}
#endif
Expand Down
17 changes: 10 additions & 7 deletions ndk/src/main/jni/utils/serializer.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,16 @@ char *bsg_serialize_report_to_json_string(bugsnag_report *report) {
json_object_dotset_string(event, "user.email", report->user.email);
if (strlen(report->user.id) > 0)
json_object_dotset_string(event, "user.id", report->user.id);
if (strlen(report->session_id) > 0) {
json_object_dotset_string(event, "session.startedAt",
report->session_start);
json_object_dotset_string(event, "session.id", report->session_id);
json_object_dotset_number(event, "session.events.handled",
report->handled_events);
json_object_dotset_number(event, "session.events.unhandled", 1);

if (!report->stoppedSession) {
if (strlen(report->session_id) > 0) {
json_object_dotset_string(event, "session.startedAt",
report->session_start);
json_object_dotset_string(event, "session.id", report->session_id);
json_object_dotset_number(event, "session.events.handled",
report->handled_events);
json_object_dotset_number(event, "session.events.unhandled", 1);
}
}

json_object_set_string(exception, "errorClass", report->exception.name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ public void testStartSessionSendsMessage() throws InterruptedException {
client.startSession();
List<Object> sessionInfo = (List<Object>)findMessageInQueue(
NativeInterface.MessageType.START_SESSION, List.class);
assertEquals(2, sessionInfo.size());
assertEquals(3, sessionInfo.size());
assertTrue(sessionInfo.get(0) instanceof String);
assertTrue(sessionInfo.get(1) instanceof String);
assertTrue(sessionInfo.get(2) instanceof Integer);
}

@Test
Expand Down
6 changes: 6 additions & 0 deletions sdk/src/main/java/com/bugsnag/android/NativeInterface.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ public enum MessageType {
* containing [id, startDateIsoString]
*/
START_SESSION,

/**
* A session was stopped.
*/
STOP_SESSION,

/**
* Set a new app version. The Message object should be the new app
* version
Expand Down
31 changes: 21 additions & 10 deletions sdk/src/main/java/com/bugsnag/android/SessionTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,27 +81,42 @@ Session startNewSession(@NonNull Date date, @Nullable User user,
return session;
}

void startSession(boolean autoCaptured) {
startNewSession(new Date(), client.getUser(), autoCaptured);
Session startSession(boolean autoCaptured) {
return startNewSession(new Date(), client.getUser(), autoCaptured);
}

void stopSession() {
Session session = currentSession.get();

if (session != null) {
session.isStopped.set(true);
setChanged();
notifyObservers(new NativeInterface.Message(
NativeInterface.MessageType.STOP_SESSION, null));
}
}

boolean resumeSession() {
Session session = currentSession.get();
boolean resumed;

if (session == null) {
startSession(false);
return false;
session = startSession(false);
resumed = false;
} else {
return session.isStopped.compareAndSet(true, false);
resumed = session.isStopped.compareAndSet(true, false);
}

notifySessionStartObserver(session);
return resumed;
}

private void notifySessionStartObserver(Session session) {
setChanged();
String startedAt = DateUtils.toIso8601(session.getStartedAt());
notifyObservers(new NativeInterface.Message(
NativeInterface.MessageType.START_SESSION,
Arrays.asList(session.getId(), startedAt, session.getHandledCount())));
}

/**
Expand Down Expand Up @@ -142,11 +157,7 @@ public void run() {
// This is on the current thread but there isn't much else we can do
sessionStore.write(session);
}
setChanged();
String startedAt = DateUtils.toIso8601(session.getStartedAt());
notifyObservers(new NativeInterface.Message(
NativeInterface.MessageType.START_SESSION,
Arrays.asList(session.getId(), startedAt)));
notifySessionStartObserver(session);
}
}

Expand Down

0 comments on commit 6e60b21

Please sign in to comment.