Skip to content

Commit

Permalink
Merge pull request #98 from rust-mobile/rib/pr/fix-game-activity-dead…
Browse files Browse the repository at this point in the history
…lock

GameActivity PATH: fix deadlocks in java callbacks after app destroyed
  • Loading branch information
rib authored Jul 30, 2023
2 parents a84a7b5 + c10a2fb commit 8a21219
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 5 deletions.
11 changes: 11 additions & 0 deletions android-activity/build.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
#![allow(dead_code)]

fn build_glue_for_game_activity() {
for f in ["GameActivity.h", "GameActivity.cpp"] {
println!("cargo:rerun-if-changed=game-activity-csrc/game-activity/{f}");
}
cc::Build::new()
.cpp(true)
.include("game-activity-csrc")
.file("game-activity-csrc/game-activity/GameActivity.cpp")
.extra_warnings(false)
.cpp_link_stdlib("c++_static")
.compile("libgame_activity.a");

for f in ["gamecommon.h", "gametextinput.h", "gametextinput.cpp"] {
println!("cargo:rerun-if-changed=game-activity-csrc/game-text-input/{f}");
}
cc::Build::new()
.cpp(true)
.include("game-activity-csrc")
.file("game-activity-csrc/game-text-input/gametextinput.cpp")
.cpp_link_stdlib("c++_static")
.compile("libgame_text_input.a");

for f in ["android_native_app_glue.h", "android_native_app_glue.c"] {
println!("cargo:rerun-if-changed=game-activity-csrc/native_app_glue/{f}");
}
cc::Build::new()
.include("game-activity-csrc")
.include("game-activity-csrc/game-activity/native_app_glue")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,15 @@ static void android_app_set_window(struct android_app* android_app,
ANativeWindow* window) {
LOGV("android_app_set_window called");
pthread_mutex_lock(&android_app->mutex);

// NB: we have to consider that the native thread could have already
// (gracefully) exit (setting android_app->destroyed) and so we need
// to be careful to avoid a deadlock waiting for a thread that's
// already exit.
if (android_app->destroyed) {
pthread_mutex_unlock(&android_app->mutex);
return;
}
if (android_app->pendingWindow != NULL) {
android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
}
Expand All @@ -324,15 +333,30 @@ static void android_app_set_window(struct android_app* android_app,
static void android_app_set_activity_state(struct android_app* android_app,
int8_t cmd) {
pthread_mutex_lock(&android_app->mutex);
android_app_write_cmd(android_app, cmd);
while (android_app->activityState != cmd) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);

// NB: we have to consider that the native thread could have already
// (gracefully) exit (setting android_app->destroyed) and so we need
// to be careful to avoid a deadlock waiting for a thread that's
// already exit.
if (!android_app->destroyed) {
android_app_write_cmd(android_app, cmd);
while (android_app->activityState != cmd) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
}
}
pthread_mutex_unlock(&android_app->mutex);
}

static void android_app_free(struct android_app* android_app) {
pthread_mutex_lock(&android_app->mutex);

// It's possible that onDestroy is called after we have already 'destroyed'
// the app (via `android_app_destroy` due to `android_main` returning.
//
// In this case `->destroyed` will already be set (so we won't deadlock in
// the loop below) but we still need to close the messaging fds and finish
// freeing the android_app

android_app_write_cmd(android_app, APP_CMD_DESTROY);
while (!android_app->destroyed) {
pthread_cond_wait(&android_app->cond, &android_app->mutex);
Expand Down Expand Up @@ -372,6 +396,16 @@ static void onSaveInstanceState(GameActivity* activity,

struct android_app* android_app = ToApp(activity);
pthread_mutex_lock(&android_app->mutex);

// NB: we have to consider that the native thread could have already
// (gracefully) exit (setting android_app->destroyed) and so we need
// to be careful to avoid a deadlock waiting for a thread that's
// already exit.
if (android_app->destroyed) {
pthread_mutex_unlock(&android_app->mutex);
return;
}

android_app->stateSaved = 0;
android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
while (!android_app->stateSaved) {
Expand Down Expand Up @@ -481,6 +515,15 @@ static bool onTouchEvent(GameActivity* activity,
struct android_app* android_app = ToApp(activity);
pthread_mutex_lock(&android_app->mutex);

// NB: we have to consider that the native thread could have already
// (gracefully) exit (setting android_app->destroyed) and so we need
// to be careful to avoid a deadlock waiting for a thread that's
// already exit.
if (android_app->destroyed) {
pthread_mutex_unlock(&android_app->mutex);
return false;
}

if (android_app->motionEventFilter != NULL &&
!android_app->motionEventFilter(event)) {
pthread_mutex_unlock(&android_app->mutex);
Expand Down Expand Up @@ -563,6 +606,15 @@ static bool onKey(GameActivity* activity, const GameActivityKeyEvent* event) {
struct android_app* android_app = ToApp(activity);
pthread_mutex_lock(&android_app->mutex);

// NB: we have to consider that the native thread could have already
// (gracefully) exit (setting android_app->destroyed) and so we need
// to be careful to avoid a deadlock waiting for a thread that's
// already exit.
if (android_app->destroyed) {
pthread_mutex_unlock(&android_app->mutex);
return false;
}

if (android_app->keyEventFilter != NULL &&
!android_app->keyEventFilter(event)) {
pthread_mutex_unlock(&android_app->mutex);
Expand Down Expand Up @@ -599,8 +651,9 @@ static void onTextInputEvent(GameActivity* activity,
const GameTextInputState* state) {
struct android_app* android_app = ToApp(activity);
pthread_mutex_lock(&android_app->mutex);

android_app->textInputState = 1;
if (!android_app->destroyed) {
android_app->textInputState = 1;
}
pthread_mutex_unlock(&android_app->mutex);
}

Expand Down

0 comments on commit 8a21219

Please sign in to comment.