Home | History | Annotate | Download | only in native_app_glue
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  *
     16  */
     17 
     18 #include <jni.h>
     19 
     20 #include <errno.h>
     21 #include <string.h>
     22 #include <unistd.h>
     23 #include <sys/resource.h>
     24 
     25 #include "android_native_app_glue.h"
     26 #include <android/log.h>
     27 
     28 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
     29 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__))
     30 
     31 /* For debug builds, always enable the debug traces in this library */
     32 #ifndef NDEBUG
     33 #  define LOGV(...)  ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__))
     34 #else
     35 #  define LOGV(...)  ((void)0)
     36 #endif
     37 
     38 static void free_saved_state(struct android_app* android_app) {
     39     pthread_mutex_lock(&android_app->mutex);
     40     if (android_app->savedState != NULL) {
     41         free(android_app->savedState);
     42         android_app->savedState = NULL;
     43         android_app->savedStateSize = 0;
     44     }
     45     pthread_mutex_unlock(&android_app->mutex);
     46 }
     47 
     48 int8_t android_app_read_cmd(struct android_app* android_app) {
     49     int8_t cmd;
     50     if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
     51         switch (cmd) {
     52             case APP_CMD_SAVE_STATE:
     53                 free_saved_state(android_app);
     54                 break;
     55         }
     56         return cmd;
     57     } else {
     58         LOGE("No data on command pipe!");
     59     }
     60     return -1;
     61 }
     62 
     63 static void print_cur_config(struct android_app* android_app) {
     64     char lang[2], country[2];
     65     AConfiguration_getLanguage(android_app->config, lang);
     66     AConfiguration_getCountry(android_app->config, country);
     67 
     68     LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
     69             "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
     70             "modetype=%d modenight=%d",
     71             AConfiguration_getMcc(android_app->config),
     72             AConfiguration_getMnc(android_app->config),
     73             lang[0], lang[1], country[0], country[1],
     74             AConfiguration_getOrientation(android_app->config),
     75             AConfiguration_getTouchscreen(android_app->config),
     76             AConfiguration_getDensity(android_app->config),
     77             AConfiguration_getKeyboard(android_app->config),
     78             AConfiguration_getNavigation(android_app->config),
     79             AConfiguration_getKeysHidden(android_app->config),
     80             AConfiguration_getNavHidden(android_app->config),
     81             AConfiguration_getSdkVersion(android_app->config),
     82             AConfiguration_getScreenSize(android_app->config),
     83             AConfiguration_getScreenLong(android_app->config),
     84             AConfiguration_getUiModeType(android_app->config),
     85             AConfiguration_getUiModeNight(android_app->config));
     86 }
     87 
     88 void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
     89     switch (cmd) {
     90         case APP_CMD_INPUT_CHANGED:
     91             LOGV("APP_CMD_INPUT_CHANGED\n");
     92             pthread_mutex_lock(&android_app->mutex);
     93             if (android_app->inputQueue != NULL) {
     94                 AInputQueue_detachLooper(android_app->inputQueue);
     95             }
     96             android_app->inputQueue = android_app->pendingInputQueue;
     97             if (android_app->inputQueue != NULL) {
     98                 LOGV("Attaching input queue to looper");
     99                 AInputQueue_attachLooper(android_app->inputQueue,
    100                         android_app->looper, LOOPER_ID_INPUT, NULL,
    101                         &android_app->inputPollSource);
    102             }
    103             pthread_cond_broadcast(&android_app->cond);
    104             pthread_mutex_unlock(&android_app->mutex);
    105             break;
    106 
    107         case APP_CMD_INIT_WINDOW:
    108             LOGV("APP_CMD_INIT_WINDOW\n");
    109             pthread_mutex_lock(&android_app->mutex);
    110             android_app->window = android_app->pendingWindow;
    111             pthread_cond_broadcast(&android_app->cond);
    112             pthread_mutex_unlock(&android_app->mutex);
    113             break;
    114 
    115         case APP_CMD_TERM_WINDOW:
    116             LOGV("APP_CMD_TERM_WINDOW\n");
    117             pthread_cond_broadcast(&android_app->cond);
    118             break;
    119 
    120         case APP_CMD_RESUME:
    121         case APP_CMD_START:
    122         case APP_CMD_PAUSE:
    123         case APP_CMD_STOP:
    124             LOGV("activityState=%d\n", cmd);
    125             pthread_mutex_lock(&android_app->mutex);
    126             android_app->activityState = cmd;
    127             pthread_cond_broadcast(&android_app->cond);
    128             pthread_mutex_unlock(&android_app->mutex);
    129             break;
    130 
    131         case APP_CMD_CONFIG_CHANGED:
    132             LOGV("APP_CMD_CONFIG_CHANGED\n");
    133             AConfiguration_fromAssetManager(android_app->config,
    134                     android_app->activity->assetManager);
    135             print_cur_config(android_app);
    136             break;
    137 
    138         case APP_CMD_DESTROY:
    139             LOGV("APP_CMD_DESTROY\n");
    140             android_app->destroyRequested = 1;
    141             break;
    142     }
    143 }
    144 
    145 void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
    146     switch (cmd) {
    147         case APP_CMD_TERM_WINDOW:
    148             LOGV("APP_CMD_TERM_WINDOW\n");
    149             pthread_mutex_lock(&android_app->mutex);
    150             android_app->window = NULL;
    151             pthread_cond_broadcast(&android_app->cond);
    152             pthread_mutex_unlock(&android_app->mutex);
    153             break;
    154 
    155         case APP_CMD_SAVE_STATE:
    156             LOGV("APP_CMD_SAVE_STATE\n");
    157             pthread_mutex_lock(&android_app->mutex);
    158             android_app->stateSaved = 1;
    159             pthread_cond_broadcast(&android_app->cond);
    160             pthread_mutex_unlock(&android_app->mutex);
    161             break;
    162 
    163         case APP_CMD_RESUME:
    164             free_saved_state(android_app);
    165             break;
    166     }
    167 }
    168 
    169 void app_dummy() {
    170 
    171 }
    172 
    173 static void android_app_destroy(struct android_app* android_app) {
    174     LOGV("android_app_destroy!");
    175     free_saved_state(android_app);
    176     pthread_mutex_lock(&android_app->mutex);
    177     if (android_app->inputQueue != NULL) {
    178         AInputQueue_detachLooper(android_app->inputQueue);
    179     }
    180     AConfiguration_delete(android_app->config);
    181     android_app->destroyed = 1;
    182     pthread_cond_broadcast(&android_app->cond);
    183     pthread_mutex_unlock(&android_app->mutex);
    184     // Can't touch android_app object after this.
    185 }
    186 
    187 static void process_input(struct android_app* app, struct android_poll_source* source) {
    188     AInputEvent* event = NULL;
    189     if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
    190         LOGV("New input event: type=%d\n", AInputEvent_getType(event));
    191         if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
    192             return;
    193         }
    194         int32_t handled = 0;
    195         if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
    196         AInputQueue_finishEvent(app->inputQueue, event, handled);
    197     } else {
    198         LOGE("Failure reading next input event: %s\n", strerror(errno));
    199     }
    200 }
    201 
    202 static void process_cmd(struct android_app* app, struct android_poll_source* source) {
    203     int8_t cmd = android_app_read_cmd(app);
    204     android_app_pre_exec_cmd(app, cmd);
    205     if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
    206     android_app_post_exec_cmd(app, cmd);
    207 }
    208 
    209 static void* android_app_entry(void* param) {
    210     struct android_app* android_app = (struct android_app*)param;
    211 
    212     android_app->config = AConfiguration_new();
    213     AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
    214 
    215     print_cur_config(android_app);
    216 
    217     android_app->cmdPollSource.id = LOOPER_ID_MAIN;
    218     android_app->cmdPollSource.app = android_app;
    219     android_app->cmdPollSource.process = process_cmd;
    220     android_app->inputPollSource.id = LOOPER_ID_INPUT;
    221     android_app->inputPollSource.app = android_app;
    222     android_app->inputPollSource.process = process_input;
    223 
    224     ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    225     ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
    226             &android_app->cmdPollSource);
    227     android_app->looper = looper;
    228 
    229     pthread_mutex_lock(&android_app->mutex);
    230     android_app->running = 1;
    231     pthread_cond_broadcast(&android_app->cond);
    232     pthread_mutex_unlock(&android_app->mutex);
    233 
    234     android_main(android_app);
    235 
    236     android_app_destroy(android_app);
    237     return NULL;
    238 }
    239 
    240 // --------------------------------------------------------------------
    241 // Native activity interaction (called from main thread)
    242 // --------------------------------------------------------------------
    243 
    244 static struct android_app* android_app_create(ANativeActivity* activity,
    245         void* savedState, size_t savedStateSize) {
    246     struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
    247     memset(android_app, 0, sizeof(struct android_app));
    248     android_app->activity = activity;
    249 
    250     pthread_mutex_init(&android_app->mutex, NULL);
    251     pthread_cond_init(&android_app->cond, NULL);
    252 
    253     if (savedState != NULL) {
    254         android_app->savedState = malloc(savedStateSize);
    255         android_app->savedStateSize = savedStateSize;
    256         memcpy(android_app->savedState, savedState, savedStateSize);
    257     }
    258 
    259     int msgpipe[2];
    260     if (pipe(msgpipe)) {
    261         LOGE("could not create pipe: %s", strerror(errno));
    262         return NULL;
    263     }
    264     android_app->msgread = msgpipe[0];
    265     android_app->msgwrite = msgpipe[1];
    266 
    267     pthread_attr_t attr;
    268     pthread_attr_init(&attr);
    269     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    270     pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
    271 
    272     // Wait for thread to start.
    273     pthread_mutex_lock(&android_app->mutex);
    274     while (!android_app->running) {
    275         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    276     }
    277     pthread_mutex_unlock(&android_app->mutex);
    278 
    279     return android_app;
    280 }
    281 
    282 static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
    283     if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
    284         LOGE("Failure writing android_app cmd: %s\n", strerror(errno));
    285     }
    286 }
    287 
    288 static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
    289     pthread_mutex_lock(&android_app->mutex);
    290     android_app->pendingInputQueue = inputQueue;
    291     android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
    292     while (android_app->inputQueue != android_app->pendingInputQueue) {
    293         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    294     }
    295     pthread_mutex_unlock(&android_app->mutex);
    296 }
    297 
    298 static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
    299     pthread_mutex_lock(&android_app->mutex);
    300     if (android_app->pendingWindow != NULL) {
    301         android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
    302     }
    303     android_app->pendingWindow = window;
    304     if (window != NULL) {
    305         android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
    306     }
    307     while (android_app->window != android_app->pendingWindow) {
    308         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    309     }
    310     pthread_mutex_unlock(&android_app->mutex);
    311 }
    312 
    313 static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
    314     pthread_mutex_lock(&android_app->mutex);
    315     android_app_write_cmd(android_app, cmd);
    316     while (android_app->activityState != cmd) {
    317         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    318     }
    319     pthread_mutex_unlock(&android_app->mutex);
    320 }
    321 
    322 static void android_app_free(struct android_app* android_app) {
    323     pthread_mutex_lock(&android_app->mutex);
    324     android_app_write_cmd(android_app, APP_CMD_DESTROY);
    325     while (!android_app->destroyed) {
    326         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    327     }
    328     pthread_mutex_unlock(&android_app->mutex);
    329 
    330     close(android_app->msgread);
    331     close(android_app->msgwrite);
    332     pthread_cond_destroy(&android_app->cond);
    333     pthread_mutex_destroy(&android_app->mutex);
    334     free(android_app);
    335 }
    336 
    337 static void onDestroy(ANativeActivity* activity) {
    338     LOGV("Destroy: %p\n", activity);
    339     android_app_free((struct android_app*)activity->instance);
    340 }
    341 
    342 static void onStart(ANativeActivity* activity) {
    343     LOGV("Start: %p\n", activity);
    344     android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
    345 }
    346 
    347 static void onResume(ANativeActivity* activity) {
    348     LOGV("Resume: %p\n", activity);
    349     android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
    350 }
    351 
    352 static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
    353     struct android_app* android_app = (struct android_app*)activity->instance;
    354     void* savedState = NULL;
    355 
    356     LOGV("SaveInstanceState: %p\n", activity);
    357     pthread_mutex_lock(&android_app->mutex);
    358     android_app->stateSaved = 0;
    359     android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
    360     while (!android_app->stateSaved) {
    361         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    362     }
    363 
    364     if (android_app->savedState != NULL) {
    365         savedState = android_app->savedState;
    366         *outLen = android_app->savedStateSize;
    367         android_app->savedState = NULL;
    368         android_app->savedStateSize = 0;
    369     }
    370 
    371     pthread_mutex_unlock(&android_app->mutex);
    372 
    373     return savedState;
    374 }
    375 
    376 static void onPause(ANativeActivity* activity) {
    377     LOGV("Pause: %p\n", activity);
    378     android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
    379 }
    380 
    381 static void onStop(ANativeActivity* activity) {
    382     LOGV("Stop: %p\n", activity);
    383     android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
    384 }
    385 
    386 static void onConfigurationChanged(ANativeActivity* activity) {
    387     struct android_app* android_app = (struct android_app*)activity->instance;
    388     LOGV("ConfigurationChanged: %p\n", activity);
    389     android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
    390 }
    391 
    392 static void onLowMemory(ANativeActivity* activity) {
    393     struct android_app* android_app = (struct android_app*)activity->instance;
    394     LOGV("LowMemory: %p\n", activity);
    395     android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
    396 }
    397 
    398 static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
    399     LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);
    400     android_app_write_cmd((struct android_app*)activity->instance,
    401             focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
    402 }
    403 
    404 static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
    405     LOGV("NativeWindowCreated: %p -- %p\n", activity, window);
    406     android_app_set_window((struct android_app*)activity->instance, window);
    407 }
    408 
    409 static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
    410     LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);
    411     android_app_set_window((struct android_app*)activity->instance, NULL);
    412 }
    413 
    414 static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
    415     LOGV("InputQueueCreated: %p -- %p\n", activity, queue);
    416     android_app_set_input((struct android_app*)activity->instance, queue);
    417 }
    418 
    419 static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
    420     LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);
    421     android_app_set_input((struct android_app*)activity->instance, NULL);
    422 }
    423 
    424 void ANativeActivity_onCreate(ANativeActivity* activity,
    425         void* savedState, size_t savedStateSize) {
    426     LOGV("Creating: %p\n", activity);
    427     activity->callbacks->onDestroy = onDestroy;
    428     activity->callbacks->onStart = onStart;
    429     activity->callbacks->onResume = onResume;
    430     activity->callbacks->onSaveInstanceState = onSaveInstanceState;
    431     activity->callbacks->onPause = onPause;
    432     activity->callbacks->onStop = onStop;
    433     activity->callbacks->onConfigurationChanged = onConfigurationChanged;
    434     activity->callbacks->onLowMemory = onLowMemory;
    435     activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
    436     activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
    437     activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
    438     activity->callbacks->onInputQueueCreated = onInputQueueCreated;
    439     activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
    440 
    441     activity->instance = android_app_create(activity, savedState, savedStateSize);
    442 }
    443