diff --git a/frontend/drivers/platform_linux.c b/frontend/drivers/platform_linux.c index 604feaa073..3da781b39a 100644 --- a/frontend/drivers/platform_linux.c +++ b/frontend/drivers/platform_linux.c @@ -630,6 +630,34 @@ static void onResume(ANativeActivity* activity) activity->instance, APP_CMD_RESUME); } +static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) +{ + void* savedState = NULL; + struct android_app* android_app = (struct android_app*)activity->instance; + + RARCH_LOG("SaveInstanceState: %p\n", activity); + + slock_lock(android_app->mutex); + + android_app->stateSaved = 0; + android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); + + while (!android_app->stateSaved) + scond_wait(android_app->cond, android_app->mutex); + + if (android_app->savedState != NULL) + { + savedState = android_app->savedState; + *outLen = android_app->savedStateSize; + android_app->savedState = NULL; + android_app->savedStateSize = 0; + } + + slock_unlock(android_app->mutex); + + return savedState; +} + static void onPause(ANativeActivity* activity) { RARCH_LOG("Pause: %p\n", activity); @@ -656,6 +684,13 @@ static void onConfigurationChanged(ANativeActivity *activity) android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED); } +static void onLowMemory(ANativeActivity* activity) +{ + struct android_app* android_app = (struct android_app*)activity->instance; + RARCH_LOG("LowMemory: %p\n", activity); + android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY); +} + static void onWindowFocusChanged(ANativeActivity* activity, int focused) { RARCH_LOG("WindowFocusChanged: %p -- %d\n", activity, focused); @@ -748,59 +783,34 @@ end: exit(0); } -/* - * Native activity interaction (called from main thread) - **/ - -void ANativeActivity_onCreate(ANativeActivity* activity, - void* savedState, size_t savedStateSize) +static struct android_app* android_app_create(ANativeActivity* activity, + void* savedState, size_t savedStateSize) { int msgpipe[2]; - struct android_app* android_app; + struct android_app *android_app = + (struct android_app*)calloc(1, sizeof(*android_app)); - (void)savedState; - (void)savedStateSize; - - RARCH_LOG("Creating Native Activity: %p\n", activity); - activity->callbacks->onDestroy = onDestroy; - activity->callbacks->onStart = onStart; - activity->callbacks->onResume = onResume; - activity->callbacks->onSaveInstanceState = NULL; - activity->callbacks->onPause = onPause; - activity->callbacks->onStop = onStop; - activity->callbacks->onConfigurationChanged = onConfigurationChanged; - activity->callbacks->onLowMemory = NULL; - activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; - activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; - activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; - activity->callbacks->onInputQueueCreated = onInputQueueCreated; - activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; - - /* These are set only for the native activity, - * and are reset when it ends. */ - ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON - | AWINDOW_FLAG_FULLSCREEN, 0); - - if (pthread_key_create(&thread_key, jni_thread_destruct)) - RARCH_ERR("Error initializing pthread_key\n"); - - android_app = (struct android_app*)calloc(1, sizeof(*android_app)); if (!android_app) { RARCH_ERR("Failed to initialize android_app\n"); - return; + return NULL; } - - memset(android_app, 0, sizeof(struct android_app)); - android_app->activity = activity; + android_app->mutex = slock_new(); android_app->cond = scond_new(); + if (savedState != NULL) + { + android_app->savedState = malloc(savedStateSize); + android_app->savedStateSize = savedStateSize; + memcpy(android_app->savedState, savedState, savedStateSize); + } + if (pipe(msgpipe)) { RARCH_ERR("could not create pipe: %s.\n", strerror(errno)); - activity->instance = NULL; + return NULL; } android_app->msgread = msgpipe[0]; android_app->msgwrite = msgpipe[1]; @@ -813,7 +823,40 @@ void ANativeActivity_onCreate(ANativeActivity* activity, scond_wait(android_app->cond, android_app->mutex); slock_unlock(android_app->mutex); - activity->instance = android_app; + return android_app; +} + +/* + * Native activity interaction (called from main thread) + **/ + +void ANativeActivity_onCreate(ANativeActivity* activity, + void* savedState, size_t savedStateSize) +{ + RARCH_LOG("Creating Native Activity: %p\n", activity); + activity->callbacks->onDestroy = onDestroy; + activity->callbacks->onStart = onStart; + activity->callbacks->onResume = onResume; + activity->callbacks->onSaveInstanceState = onSaveInstanceState; + activity->callbacks->onPause = onPause; + activity->callbacks->onStop = onStop; + activity->callbacks->onConfigurationChanged = onConfigurationChanged; + activity->callbacks->onLowMemory = onLowMemory; + activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; + activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; + activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; + activity->callbacks->onInputQueueCreated = onInputQueueCreated; + activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; + + /* These are set only for the native activity, + * and are reset when it ends. */ + ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON + | AWINDOW_FLAG_FULLSCREEN, 0); + + if (pthread_key_create(&thread_key, jni_thread_destruct)) + RARCH_ERR("Error initializing pthread_key\n"); + + activity->instance = android_app_create(activity, savedState, savedStateSize); } diff --git a/frontend/drivers/platform_linux.h b/frontend/drivers/platform_linux.h index 8a3dd41fdb..8e173f7221 100644 --- a/frontend/drivers/platform_linux.h +++ b/frontend/drivers/platform_linux.h @@ -72,23 +72,59 @@ char sdcard_dir[PATH_MAX_LENGTH]; struct android_app { + /* The ANativeActivity object instance that this app is running in. */ ANativeActivity* activity; + + /* This is the last instance's saved state, as provided at creation time. + * It is NULL if there was no state. You can use this as you need; the + * memory will remain around until you call android_app_exec_cmd() for + * APP_CMD_RESUME, at which point it will be freed and savedState set to NULL. + * These variables should only be changed when processing a APP_CMD_SAVE_STATE, + * at which point they will be initialized to NULL and you can malloc your + * state and place the information here. In that case the memory will be + * freed for you later. + */ + void* savedState; + size_t savedStateSize; + + /* The ALooper associated with the app's thread. */ ALooper* looper; + + /* When non-NULL, this is the input queue from which the app will + * receive user input events. */ AInputQueue* inputQueue; + AInputQueue* pendingInputQueue; + + /* When non-NULL, this is the window surface that the app can draw in. */ ANativeWindow* window; + ANativeWindow* pendingWindow; + + /* This is non-zero when the application's NativeActivity is being + * destroyed and waiting for the app thread to complete. */ + int destroyRequested; + slock_t *mutex; scond_t *cond; + + /* Current state of the app's activity. May be either APP_CMD_START, + * APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. */ int activityState; + int msgread; int msgwrite; + + sthread_t *thread; + int running; + int stateSaved; + int destroyed; + bool unfocused; unsigned accelerometer_event_rate; const ASensor* accelerometerSensor; uint64_t sensor_state_mask; - sthread_t *thread; char current_ime[PATH_MAX_LENGTH]; jmethodID getIntent; jmethodID onRetroArchExit; diff --git a/input/drivers/android_input.c b/input/drivers/android_input.c index 5800f00f58..64e400e871 100644 --- a/input/drivers/android_input.c +++ b/input/drivers/android_input.c @@ -241,7 +241,9 @@ static void android_input_poll_main_cmd(void) rarch_system_info_t *system = rarch_system_info_get_ptr(); if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd)) + { cmd = -1; + } switch (cmd) { @@ -276,27 +278,16 @@ static void android_input_poll_main_cmd(void) event_command(EVENT_CMD_REINIT); break; + case APP_CMD_SAVE_STATE: + slock_lock(android_app->mutex); + android_app->stateSaved = 1; + scond_broadcast(android_app->cond); + slock_unlock(android_app->mutex); + break; + case APP_CMD_RESUME: - slock_lock(android_app->mutex); - android_app->activityState = cmd; - scond_broadcast(android_app->cond); - slock_unlock(android_app->mutex); - break; - case APP_CMD_START: - slock_lock(android_app->mutex); - android_app->activityState = cmd; - scond_broadcast(android_app->cond); - slock_unlock(android_app->mutex); - break; - case APP_CMD_PAUSE: - slock_lock(android_app->mutex); - android_app->activityState = cmd; - scond_broadcast(android_app->cond); - slock_unlock(android_app->mutex); - break; - case APP_CMD_STOP: slock_lock(android_app->mutex); android_app->activityState = cmd; @@ -359,7 +350,9 @@ static void android_input_poll_main_cmd(void) break; case APP_CMD_DESTROY: + RARCH_LOG("APP_CMD_DESTROY\n"); system->shutdown = true; + android_app->destroyRequested = 1; break; } }