@@ -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,
324333static 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
334350static 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