Skip to content

Commit 8a21219

Browse files
authored
Merge pull request #98 from rust-mobile/rib/pr/fix-game-activity-deadlock
GameActivity PATH: fix deadlocks in java callbacks after app destroyed
2 parents a84a7b5 + c10a2fb commit 8a21219

File tree

2 files changed

+69
-5
lines changed

2 files changed

+69
-5
lines changed

android-activity/build.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
#![allow(dead_code)]
22

33
fn build_glue_for_game_activity() {
4+
for f in ["GameActivity.h", "GameActivity.cpp"] {
5+
println!("cargo:rerun-if-changed=game-activity-csrc/game-activity/{f}");
6+
}
47
cc::Build::new()
58
.cpp(true)
69
.include("game-activity-csrc")
710
.file("game-activity-csrc/game-activity/GameActivity.cpp")
811
.extra_warnings(false)
912
.cpp_link_stdlib("c++_static")
1013
.compile("libgame_activity.a");
14+
15+
for f in ["gamecommon.h", "gametextinput.h", "gametextinput.cpp"] {
16+
println!("cargo:rerun-if-changed=game-activity-csrc/game-text-input/{f}");
17+
}
1118
cc::Build::new()
1219
.cpp(true)
1320
.include("game-activity-csrc")
1421
.file("game-activity-csrc/game-text-input/gametextinput.cpp")
1522
.cpp_link_stdlib("c++_static")
1623
.compile("libgame_text_input.a");
24+
25+
for f in ["android_native_app_glue.h", "android_native_app_glue.c"] {
26+
println!("cargo:rerun-if-changed=game-activity-csrc/native_app_glue/{f}");
27+
}
1728
cc::Build::new()
1829
.include("game-activity-csrc")
1930
.include("game-activity-csrc/game-activity/native_app_glue")

android-activity/game-activity-csrc/game-activity/native_app_glue/android_native_app_glue.c

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,15 @@ static void android_app_set_window(struct android_app* android_app,
308308
ANativeWindow* window) {
309309
LOGV("android_app_set_window called");
310310
pthread_mutex_lock(&android_app->mutex);
311+
312+
// NB: we have to consider that the native thread could have already
313+
// (gracefully) exit (setting android_app->destroyed) and so we need
314+
// to be careful to avoid a deadlock waiting for a thread that's
315+
// already exit.
316+
if (android_app->destroyed) {
317+
pthread_mutex_unlock(&android_app->mutex);
318+
return;
319+
}
311320
if (android_app->pendingWindow != NULL) {
312321
android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
313322
}
@@ -324,15 +333,30 @@ static void android_app_set_window(struct android_app* android_app,
324333
static void android_app_set_activity_state(struct android_app* android_app,
325334
int8_t cmd) {
326335
pthread_mutex_lock(&android_app->mutex);
327-
android_app_write_cmd(android_app, cmd);
328-
while (android_app->activityState != cmd) {
329-
pthread_cond_wait(&android_app->cond, &android_app->mutex);
336+
337+
// NB: we have to consider that the native thread could have already
338+
// (gracefully) exit (setting android_app->destroyed) and so we need
339+
// to be careful to avoid a deadlock waiting for a thread that's
340+
// already exit.
341+
if (!android_app->destroyed) {
342+
android_app_write_cmd(android_app, cmd);
343+
while (android_app->activityState != cmd) {
344+
pthread_cond_wait(&android_app->cond, &android_app->mutex);
345+
}
330346
}
331347
pthread_mutex_unlock(&android_app->mutex);
332348
}
333349

334350
static void android_app_free(struct android_app* android_app) {
335351
pthread_mutex_lock(&android_app->mutex);
352+
353+
// It's possible that onDestroy is called after we have already 'destroyed'
354+
// the app (via `android_app_destroy` due to `android_main` returning.
355+
//
356+
// In this case `->destroyed` will already be set (so we won't deadlock in
357+
// the loop below) but we still need to close the messaging fds and finish
358+
// freeing the android_app
359+
336360
android_app_write_cmd(android_app, APP_CMD_DESTROY);
337361
while (!android_app->destroyed) {
338362
pthread_cond_wait(&android_app->cond, &android_app->mutex);
@@ -372,6 +396,16 @@ static void onSaveInstanceState(GameActivity* activity,
372396

373397
struct android_app* android_app = ToApp(activity);
374398
pthread_mutex_lock(&android_app->mutex);
399+
400+
// NB: we have to consider that the native thread could have already
401+
// (gracefully) exit (setting android_app->destroyed) and so we need
402+
// to be careful to avoid a deadlock waiting for a thread that's
403+
// already exit.
404+
if (android_app->destroyed) {
405+
pthread_mutex_unlock(&android_app->mutex);
406+
return;
407+
}
408+
375409
android_app->stateSaved = 0;
376410
android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
377411
while (!android_app->stateSaved) {
@@ -481,6 +515,15 @@ static bool onTouchEvent(GameActivity* activity,
481515
struct android_app* android_app = ToApp(activity);
482516
pthread_mutex_lock(&android_app->mutex);
483517

518+
// NB: we have to consider that the native thread could have already
519+
// (gracefully) exit (setting android_app->destroyed) and so we need
520+
// to be careful to avoid a deadlock waiting for a thread that's
521+
// already exit.
522+
if (android_app->destroyed) {
523+
pthread_mutex_unlock(&android_app->mutex);
524+
return false;
525+
}
526+
484527
if (android_app->motionEventFilter != NULL &&
485528
!android_app->motionEventFilter(event)) {
486529
pthread_mutex_unlock(&android_app->mutex);
@@ -563,6 +606,15 @@ static bool onKey(GameActivity* activity, const GameActivityKeyEvent* event) {
563606
struct android_app* android_app = ToApp(activity);
564607
pthread_mutex_lock(&android_app->mutex);
565608

609+
// NB: we have to consider that the native thread could have already
610+
// (gracefully) exit (setting android_app->destroyed) and so we need
611+
// to be careful to avoid a deadlock waiting for a thread that's
612+
// already exit.
613+
if (android_app->destroyed) {
614+
pthread_mutex_unlock(&android_app->mutex);
615+
return false;
616+
}
617+
566618
if (android_app->keyEventFilter != NULL &&
567619
!android_app->keyEventFilter(event)) {
568620
pthread_mutex_unlock(&android_app->mutex);
@@ -599,8 +651,9 @@ static void onTextInputEvent(GameActivity* activity,
599651
const GameTextInputState* state) {
600652
struct android_app* android_app = ToApp(activity);
601653
pthread_mutex_lock(&android_app->mutex);
602-
603-
android_app->textInputState = 1;
654+
if (!android_app->destroyed) {
655+
android_app->textInputState = 1;
656+
}
604657
pthread_mutex_unlock(&android_app->mutex);
605658
}
606659

0 commit comments

Comments
 (0)