Skip to content

Commit

Permalink
Merge pull request #1180 from bugsnag/PLAT-5979/ndk-is-launching
Browse files Browse the repository at this point in the history
Propagate changes in app.isLaunching to the NDK layer
  • Loading branch information
fractalwrench authored Mar 12, 2021
2 parents 153b505 + 65ed888 commit 7a4f8e8
Show file tree
Hide file tree
Showing 25 changed files with 454 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
[#1184](https://github.com/bugsnag/bugsnag-android/pull/1184)
[#1185](https://github.com/bugsnag/bugsnag-android/pull/1185)
[#1186](https://github.com/bugsnag/bugsnag-android/pull/1186)
[#1180](https://github.com/bugsnag/bugsnag-android/pull/1180)

## 5.7.1 (2021-03-03)

Expand Down
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 @@ -365,6 +365,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 @@ -408,6 +408,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.is_launching;
}

void bugsnag_app_set_is_launching(void *event_ptr, bool value) {
bugsnag_event *event = (bugsnag_event *)event_ptr;
event->app.is_launching = 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
99 changes: 93 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 All @@ -99,6 +112,16 @@ bugsnag_event *bsg_report_v4_read(int fd) {
return event;
}

/**
* Reads persisted structs into memory from disk. The report version is
* serialized in the file header, and old structs are maintained in migrate.h
* for backwards compatibility. These are then migrated to the current
* bugsnag_event struct.
*
* Note that calling the individual bsg_map_v functions will free the parameter
* - this is to conserve memory when migrating particularly old payload
* versions.
*/
bugsnag_event *bsg_event_read(int fd) {
bsg_report_header *header = bsg_report_header_read(fd);
if (header == NULL) {
Expand All @@ -118,8 +141,45 @@ 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;
bsg_strncpy_safe(event->session_id, report_v4->session_id,
sizeof(event->session_id));
bsg_strncpy_safe(event->session_start, report_v4->session_start,
sizeof(event->session_id));
event->handled_events = report_v4->handled_events;
event->unhandled_events = report_v4->unhandled_events;
bsg_strncpy_safe(event->grouping_hash, report_v4->grouping_hash,
sizeof(event->session_id));
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 +188,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 +213,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 @@ -288,6 +348,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_strcpy(event->device.os_name,
bsg_os_name()); // os_name was not a field in v2
Expand Down Expand Up @@ -472,6 +558,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
Loading

0 comments on commit 7a4f8e8

Please sign in to comment.