Skip to content

Commit

Permalink
[Android] Improvements around SendAndroidCommand to avoid ANRs. (#1576)
Browse files Browse the repository at this point in the history
This makes |g_app_running| an atomic (with barriers), and ensures it's
set to false before destroying ApplicationAndroid.

This should avoid dereferencing |ApplicationAndroid| during application
shutdown, avoiding the corresponding crashes and ANRs.

b/225209442
  • Loading branch information
jellefoks authored Sep 19, 2023
1 parent 00ecfb1 commit e6c8c4b
Showing 1 changed file with 23 additions and 16 deletions.
39 changes: 23 additions & 16 deletions starboard/android/shared/android_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "starboard/android/shared/jni_env_ext.h"
#include "starboard/android/shared/jni_utils.h"
#include "starboard/android/shared/log_internal.h"
#include "starboard/common/atomic.h"
#include "starboard/common/file.h"
#include "starboard/common/semaphore.h"
#include "starboard/common/string.h"
Expand Down Expand Up @@ -48,7 +49,7 @@ Semaphore* g_app_created_semaphore = nullptr;
// Safeguard to avoid sending AndroidCommands either when there is no instance
// of the Starboard application, or after the run loop has exited and the
// ALooper receiving the commands is no longer being polled.
bool g_app_running = false;
atomic_bool g_app_running;

std::vector<std::string> GetArgs() {
std::vector<std::string> args;
Expand Down Expand Up @@ -235,20 +236,20 @@ void* ThreadEntryPoint(void* context) {

// Mark the app running before signaling app created so there's no race to
// allow sending the first AndroidCommand after onCreate() returns.
g_app_running = true;
g_app_running.store(true);

// Signal GameActivity_onCreate() that it may proceed.
g_app_created_semaphore->Put();

// Enter the Starboard run loop until stopped.
int error_level =
app.Run(std::move(command_line), GetStartDeepLink().c_str());
#endif // SB_API_VERSION >= 15

// Mark the app not running before informing StarboardBridge that the app is
// stopped so that we won't send any more AndroidCommands as a result of
// shutting down the Activity.
g_app_running = false;
g_app_running.store(false);
#endif // SB_API_VERSION >= 15

// Our launcher.py looks for this to know when the app (test) is done.
SB_LOG(INFO) << "***Application Stopped*** " << error_level;
Expand All @@ -262,13 +263,13 @@ void* ThreadEntryPoint(void* context) {
}

void OnStart(GameActivity* activity) {
if (g_app_running) {
if (g_app_running.load()) {
ApplicationAndroid::Get()->SendAndroidCommand(AndroidCommand::kStart);
}
}

void OnResume(GameActivity* activity) {
if (g_app_running) {
if (g_app_running.load()) {
// Stop the MediaPlaybackService if activity state transits from background
// to foreground. Note that the MediaPlaybackService may already have
// been stopped before Cobalt's lifecycle state transits from Concealed
Expand All @@ -279,7 +280,7 @@ void OnResume(GameActivity* activity) {
}

void OnPause(GameActivity* activity) {
if (g_app_running) {
if (g_app_running.load()) {
// Start the MediaPlaybackService before activity state transits from
// foreground to background.
ApplicationAndroid::Get()->StartMediaPlaybackService();
Expand All @@ -288,43 +289,43 @@ void OnPause(GameActivity* activity) {
}

void OnStop(GameActivity* activity) {
if (g_app_running) {
if (g_app_running.load()) {
ApplicationAndroid::Get()->SendAndroidCommand(AndroidCommand::kStop);
}
}

bool OnTouchEvent(GameActivity* activity,
const GameActivityMotionEvent* event) {
if (g_app_running) {
if (g_app_running.load()) {
return ApplicationAndroid::Get()->SendAndroidMotionEvent(event);
}
return false;
}

bool OnKey(GameActivity* activity, const GameActivityKeyEvent* event) {
if (g_app_running) {
if (g_app_running.load()) {
return ApplicationAndroid::Get()->SendAndroidKeyEvent(event);
}
return false;
}

void OnWindowFocusChanged(GameActivity* activity, bool focused) {
if (g_app_running) {
if (g_app_running.load()) {
ApplicationAndroid::Get()->SendAndroidCommand(
focused ? AndroidCommand::kWindowFocusGained
: AndroidCommand::kWindowFocusLost);
}
}

void OnNativeWindowCreated(GameActivity* activity, ANativeWindow* window) {
if (g_app_running) {
if (g_app_running.load()) {
ApplicationAndroid::Get()->SendAndroidCommand(
AndroidCommand::kNativeWindowCreated, window);
}
}

void OnNativeWindowDestroyed(GameActivity* activity, ANativeWindow* window) {
if (g_app_running) {
if (g_app_running.load()) {
ApplicationAndroid::Get()->SendAndroidCommand(
AndroidCommand::kNativeWindowDestroyed);
}
Expand Down Expand Up @@ -380,7 +381,7 @@ extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_coat_VolumeStateReceiver_nativeVolumeChanged(JNIEnv* env,
jobject jcaller,
jint volumeDelta) {
if (g_app_running) {
if (g_app_running.load()) {
SbKey key =
volumeDelta > 0 ? SbKey::kSbKeyVolumeUp : SbKey::kSbKeyVolumeDown;
ApplicationAndroid::Get()->SendKeyboardInject(key);
Expand All @@ -390,7 +391,7 @@ Java_dev_cobalt_coat_VolumeStateReceiver_nativeVolumeChanged(JNIEnv* env,
extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_coat_VolumeStateReceiver_nativeMuteChanged(JNIEnv* env,
jobject jcaller) {
if (g_app_running) {
if (g_app_running.load()) {
ApplicationAndroid::Get()->SendKeyboardInject(SbKey::kSbKeyVolumeMute);
}
}
Expand All @@ -409,14 +410,20 @@ extern "C" int SbRunStarboardMain(int argc,

// Mark the app running before signaling app created so there's no race to
// allow sending the first AndroidCommand after onCreate() returns.
g_app_running = true;
g_app_running.store(true);

// Signal GameActivity_onCreate() that it may proceed.
g_app_created_semaphore->Put();

// Enter the Starboard run loop until stopped.
int error_level =
app.Run(std::move(command_line), GetStartDeepLink().c_str());

// Mark the app not running before informing StarboardBridge that the app is
// stopped so that we won't send any more AndroidCommands as a result of
// shutting down the Activity.
g_app_running.store(false);

return error_level;
}
#endif // SB_API_VERSION >= 15
Expand Down

0 comments on commit e6c8c4b

Please sign in to comment.