Skip to content

Commit

Permalink
feat: propagate app.isLaunching to NDK layer
Browse files Browse the repository at this point in the history
  • Loading branch information
fractalwrench committed Mar 9, 2021
1 parent 9087f64 commit 700f6af
Show file tree
Hide file tree
Showing 24 changed files with 419 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.bugsnag.android.BugsnagTestUtils.generateConfiguration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
Expand Down Expand Up @@ -151,6 +152,13 @@ public void testClientSetContextSendsMessage() {
assertEquals("Pod Bay", msg.getContext());
}

@Test
public void testClientMarkLaunchCompletedSendsMessage() {
client.markLaunchCompleted();
StateEvent.UpdateIsLaunching msg = findMessageInQueue(StateEvent.UpdateIsLaunching.class);
assertFalse(msg.isLaunching());
}

@Test
public void testClientSetUserId() {
client.setUser("personX", "[email protected]", "Loblaw");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,6 @@ class AppWithState(
writer.name("duration").value(duration)
writer.name("durationInForeground").value(durationInForeground)
writer.name("inForeground").value(inForeground)
writer.name("isLaunching").value(inForeground)
writer.name("isLaunching").value(isLaunching)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ void registerObserver(Observer observer) {
userState.addObserver(observer);
contextState.addObserver(observer);
deliveryDelegate.addObserver(observer);
launchCrashTracker.addObserver(observer);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import java.util.concurrent.atomic.AtomicBoolean
* configuration.launchDurationMillis, after which which the launch period is considered
* complete. If this value is zero, then the user must manually call markLaunchCompleted().
*/
internal class LaunchCrashTracker(config: ImmutableConfig) {
internal class LaunchCrashTracker(config: ImmutableConfig) : BaseObservable() {

private val launching = AtomicBoolean(true)
private val executor = ScheduledThreadPoolExecutor(1)
Expand All @@ -32,6 +32,8 @@ internal class LaunchCrashTracker(config: ImmutableConfig) {
fun markLaunchCompleted() {
executor.shutdown()
launching.set(false)
notifyObservers(StateEvent.UpdateIsLaunching(false))
logger.d("App launch period marked as complete")
}

fun isLaunching() = launching.get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ sealed class StateEvent {

class UpdateContext(val context: String?) : StateEvent()
class UpdateInForeground(val inForeground: Boolean, val contextActivity: String?) : StateEvent()
class UpdateIsLaunching(val isLaunching: Boolean) : StateEvent()
class UpdateOrientation(val orientation: String?) : StateEvent()

class UpdateUser(val user: User) : StateEvent()
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"app":{"version":"22","id":"com.bugsnag.example","type":"android","releaseStage":"prod","versionCode":55,"buildUUID":"1234-uuid","binaryArch":"x86","duration":6502,"durationInForeground":6502,"inForeground":true}}
{"app":{"version":"22","id":"com.bugsnag.example","type":"android","releaseStage":"prod","versionCode":55,"buildUUID":"1234-uuid","binaryArch":"x86","duration":6502,"durationInForeground":6502,"inForeground":true,"isLaunching":true}}
3 changes: 3 additions & 0 deletions bugsnag-plugin-android-ndk/src/main/assets/include/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ void bugsnag_app_set_id(void *event_ptr, char *value);
bool bugsnag_app_get_in_foreground(void *event_ptr);
void bugsnag_app_set_in_foreground(void *event_ptr, bool value);

bool bugsnag_app_get_is_launching(void *event_ptr);
void bugsnag_app_set_is_launching(void *event_ptr, bool value);

char *bugsnag_app_get_release_stage(void *event_ptr);
void bugsnag_app_set_release_stage(void *event_ptr, char *value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class NativeBridge : Observer {
external fun pausedSession()
external fun updateContext(context: String)
external fun updateInForeground(inForeground: Boolean, activityName: String)
external fun updateIsLaunching(isLaunching: Boolean)
external fun updateOrientation(orientation: String)
external fun updateUserId(newValue: String)
external fun updateUserEmail(newValue: String)
Expand Down Expand Up @@ -122,6 +123,7 @@ class NativeBridge : Observer {
msg.inForeground,
makeSafe(msg.contextActivity ?: "")
)
is StateEvent.UpdateIsLaunching -> updateIsLaunching(msg.isLaunching)
is UpdateOrientation -> updateOrientation(msg.orientation ?: "")
is UpdateUser -> {
updateUserId(makeSafe(msg.user.id ?: ""))
Expand Down
11 changes: 11 additions & 0 deletions bugsnag-plugin-android-ndk/src/main/jni/bugsnag_ndk.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,17 @@ Java_com_bugsnag_android_ndk_NativeBridge_updateInForeground(
}
}

JNIEXPORT void JNICALL
Java_com_bugsnag_android_ndk_NativeBridge_updateIsLaunching(
JNIEnv *env, jobject _this, jboolean new_value) {
if (bsg_global_env == NULL) {
return;
}
bsg_request_env_write_lock();
bugsnag_app_set_is_launching(&bsg_global_env->next_event, new_value);
bsg_release_env_write_lock();
}

JNIEXPORT void JNICALL
Java_com_bugsnag_android_ndk_NativeBridge_updateLowMemory(JNIEnv *env,
jobject _this,
Expand Down
10 changes: 10 additions & 0 deletions bugsnag-plugin-android-ndk/src/main/jni/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,16 @@ void bugsnag_app_set_in_foreground(void *event_ptr, bool value) {
event->app.in_foreground = value;
}

bool bugsnag_app_get_is_launching(void *event_ptr) {
bugsnag_event *event = (bugsnag_event *)event_ptr;
return event->app.in_foreground;
}

void bugsnag_app_set_is_launching(void *event_ptr, bool value) {
bugsnag_event *event = (bugsnag_event *)event_ptr;
event->app.in_foreground = value;
}

/* Accessors for event.device */

bool bugsnag_device_get_jailbroken(void *event_ptr) {
Expand Down
3 changes: 2 additions & 1 deletion bugsnag-plugin-android-ndk/src/main/jni/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
/**
* Version of the bugsnag_event struct. Serialized to report header.
*/
#define BUGSNAG_EVENT_VERSION 4
#define BUGSNAG_EVENT_VERSION 5

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -60,6 +60,7 @@ typedef struct {
*/
time_t duration_in_foreground_ms_offset;
bool in_foreground;
bool is_launching;
char binary_arch[32];
} bsg_app_info;

Expand Down
1 change: 1 addition & 0 deletions bugsnag-plugin-android-ndk/src/main/jni/metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ void bsg_populate_app_data(JNIEnv *env, bsg_jni_cache *jni_cache,
sizeof(event->app.id));
event->app.in_foreground =
bsg_get_map_value_bool(env, jni_cache, data, "inForeground");
event->app.is_launching = true;

char name[64];
bsg_copy_map_value_string(env, jni_cache, data, "name", name, sizeof(name));
Expand Down
45 changes: 44 additions & 1 deletion bugsnag-plugin-android-ndk/src/main/jni/utils/migrate.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,23 @@ typedef struct {
char binaryArch[32];
} bsg_app_info_v1;

typedef struct {
char id[64];
char release_stage[64];
char type[32];
char version[32];
char active_screen[64];
int version_code;
char build_uuid[64];
time_t duration;
time_t duration_in_foreground;
time_t duration_ms_offset;
time_t duration_in_foreground_ms_offset;
bool in_foreground;
bool is_launching;
char binary_arch[32];
} bsg_app_info_v2;

typedef struct {
int api_level;
double battery_level;
Expand Down Expand Up @@ -158,7 +175,7 @@ typedef struct {

typedef struct {
bsg_notifier notifier;
bsg_app_info app;
bsg_app_info_v2 app;
bsg_device_info device;
bugsnag_user user;
bsg_error error;
Expand All @@ -181,6 +198,32 @@ typedef struct {
bool unhandled;
} bugsnag_report_v3;

typedef struct {
bsg_notifier notifier;
bsg_app_info_v2 app;
bsg_device_info device;
bugsnag_user user;
bsg_error error;
bugsnag_metadata metadata;

int crumb_count;
// Breadcrumbs are a ring; the first index moves as the
// structure is filled and replaced.
int crumb_first_index;
bugsnag_breadcrumb breadcrumbs[BUGSNAG_CRUMBS_MAX];

char context[64];
bugsnag_severity severity;

char session_id[33];
char session_start[33];
int handled_events;
int unhandled_events;
char grouping_hash[64];
bool unhandled;
char api_key[64];
} bugsnag_report_v4;

#ifdef __cplusplus
}
#endif
Expand Down
86 changes: 80 additions & 6 deletions bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ extern "C" {
bool bsg_event_write(bsg_report_header *header, bugsnag_event *event, int fd);

bugsnag_event *bsg_event_read(int fd);
bugsnag_event *bsg_report_v4_read(int fd);
bsg_report_header *bsg_report_header_read(int fd);
bugsnag_event *bsg_map_v4_to_report(bugsnag_report_v4 *report_v4);
bugsnag_event *bsg_map_v3_to_report(bugsnag_report_v3 *report_v3);
bugsnag_event *bsg_map_v2_to_report(bugsnag_report_v2 *report_v2);
bugsnag_event *bsg_map_v1_to_report(bugsnag_report_v1 *report_v1);

void migrate_app_v1(bugsnag_report_v2 *report_v2, bugsnag_report_v3 *event);
void migrate_app_v2(bugsnag_report_v4 *report_v4, bugsnag_event *event);
void migrate_device_v1(bugsnag_report_v2 *report_v2, bugsnag_report_v3 *event);
void migrate_breadcrumb_v1(bugsnag_report_v2 *report_v2,
bugsnag_report_v3 *event);
Expand Down Expand Up @@ -87,7 +88,19 @@ bugsnag_report_v3 *bsg_report_v3_read(int fd) {
return event;
}

bugsnag_event *bsg_report_v4_read(int fd) {
bugsnag_report_v4 *bsg_report_v4_read(int fd) {
size_t event_size = sizeof(bugsnag_report_v4);
bugsnag_report_v4 *event = malloc(event_size);

ssize_t len = read(fd, event, event_size);
if (len != event_size) {
free(event);
return NULL;
}
return event;
}

bugsnag_event *bsg_report_v5_read(int fd) {
size_t event_size = sizeof(bugsnag_event);
bugsnag_event *event = malloc(event_size);

Expand Down Expand Up @@ -118,8 +131,42 @@ bugsnag_event *bsg_event_read(int fd) {
} else if (event_version == 3) {
bugsnag_report_v3 *report_v3 = bsg_report_v3_read(fd);
event = bsg_map_v3_to_report(report_v3);
} else {
event = bsg_report_v4_read(fd);
} else if (event_version == 4) {
bugsnag_report_v4 *report_v4 = bsg_report_v4_read(fd);
event = bsg_map_v4_to_report(report_v4);
} else if (event_version == 5) {
event = bsg_report_v5_read(fd);
}
return event;
}

bugsnag_event *bsg_map_v4_to_report(bugsnag_report_v4 *report_v4) {
if (report_v4 == NULL) {
return NULL;
}
bugsnag_event *event = malloc(sizeof(bugsnag_event));

if (event != NULL) {
event->notifier = report_v4->notifier;
event->device = report_v4->device;
event->user = report_v4->user;
event->error = report_v4->error;
event->metadata = report_v4->metadata;
event->crumb_count = report_v4->crumb_count;
event->crumb_first_index = report_v4->crumb_first_index;
memcpy(event->breadcrumbs, report_v4->breadcrumbs,
sizeof(event->breadcrumbs));
event->severity = report_v4->severity;
strcpy(event->session_id, report_v4->session_id);
strcpy(event->session_start, report_v4->session_start);
event->handled_events = report_v4->handled_events;
event->unhandled_events = report_v4->unhandled_events;
strcpy(event->grouping_hash, report_v4->grouping_hash);
event->unhandled = report_v4->unhandled;
bsg_strncpy_safe(event->api_key, report_v4->api_key,
sizeof(event->api_key));
migrate_app_v2(report_v4, event);
free(report_v4);
}
return event;
}
Expand All @@ -128,7 +175,7 @@ bugsnag_event *bsg_map_v3_to_report(bugsnag_report_v3 *report_v3) {
if (report_v3 == NULL) {
return NULL;
}
bugsnag_event *event = malloc(sizeof(bugsnag_event));
bugsnag_report_v4 *event = malloc(sizeof(bugsnag_event));

if (event != NULL) {
event->notifier = report_v3->notifier;
Expand All @@ -153,7 +200,7 @@ bugsnag_event *bsg_map_v3_to_report(bugsnag_report_v3 *report_v3) {
strcpy(event->api_key, "");
free(report_v3);
}
return event;
return bsg_map_v4_to_report(event);
}

bugsnag_event *bsg_map_v2_to_report(bugsnag_report_v2 *report_v2) {
Expand Down Expand Up @@ -294,6 +341,32 @@ void migrate_app_v1(bugsnag_report_v2 *report_v2, bugsnag_report_v3 *event) {
bugsnag_event_add_metadata_string(event, "app", "name", report_v2->app.name);
}

void migrate_app_v2(bugsnag_report_v4 *report_v4, bugsnag_event *event) {
bsg_strncpy_safe(event->app.id, report_v4->app.id, sizeof(event->app.id));
bsg_strncpy_safe(event->app.release_stage, report_v4->app.release_stage,
sizeof(event->app.release_stage));
bsg_strncpy_safe(event->app.type, report_v4->app.type,
sizeof(event->app.type));
bsg_strncpy_safe(event->app.version, report_v4->app.version,
sizeof(event->app.version));
bsg_strncpy_safe(event->app.active_screen, report_v4->app.active_screen,
sizeof(event->app.active_screen));
bsg_strncpy_safe(event->app.build_uuid, report_v4->app.build_uuid,
sizeof(event->app.build_uuid));
bsg_strncpy_safe(event->app.binary_arch, report_v4->app.binary_arch,
sizeof(event->app.binary_arch));
event->app.version_code = report_v4->app.version_code;
event->app.duration = report_v4->app.duration;
event->app.duration_in_foreground = report_v4->app.duration_in_foreground;
event->app.duration_ms_offset = report_v4->app.duration_ms_offset;
event->app.duration_in_foreground_ms_offset =
report_v4->app.duration_in_foreground_ms_offset;
event->app.in_foreground = report_v4->app.in_foreground;

// no info available, set to sensible default
event->app.is_launching = false;
}

void migrate_device_v1(bugsnag_report_v2 *report_v2, bugsnag_report_v3 *event) {
bsg_strncpy_safe(
event->device.os_name, bsg_os_name(),
Expand Down Expand Up @@ -487,6 +560,7 @@ void bsg_serialize_app(const bsg_app_info app, JSON_Object *event_obj) {
json_object_dotset_number(event_obj, "app.durationInForeground",
app.duration_in_foreground);
json_object_dotset_boolean(event_obj, "app.inForeground", app.in_foreground);
json_object_dotset_boolean(event_obj, "app.isLaunching", app.is_launching);
}

void bsg_serialize_app_metadata(const bsg_app_info app,
Expand Down
10 changes: 10 additions & 0 deletions bugsnag-plugin-android-ndk/src/test/cpp/test_bsg_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ bugsnag_event *init_event() {
event->app.duration = 9019;
event->app.duration_in_foreground = 7017;
event->app.in_foreground = true;
event->app.is_launching = true;
bsg_strncpy_safe(event->grouping_hash, "Bar", sizeof(event->grouping_hash));

event->device.jailbroken = true;
Expand Down Expand Up @@ -188,6 +189,14 @@ TEST test_app_in_foreground(void) {
PASS();
}

TEST test_app_is_launching(void) {
bugsnag_event *event = init_event();
ASSERT(bugsnag_app_get_is_launching(event));
bugsnag_app_set_is_launching(event, false);
ASSERT_FALSE(bugsnag_app_get_is_launching(event));
free(event);
PASS();
}

TEST test_device_jailbroken(void) {
bugsnag_event *event = init_event();
Expand Down Expand Up @@ -394,6 +403,7 @@ SUITE(event_mutators) {
RUN_TEST(test_app_duration);
RUN_TEST(test_app_duration_in_foreground);
RUN_TEST(test_app_in_foreground);
RUN_TEST(test_app_is_launching);
RUN_TEST(test_device_jailbroken);
RUN_TEST(test_device_id);
RUN_TEST(test_device_locale);
Expand Down
Loading

0 comments on commit 700f6af

Please sign in to comment.