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     while (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             continue;
    193         }
    194         int32_t handled = 0;
    195         if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
    196         AInputQueue_finishEvent(app->inputQueue, event, handled);
    197     }
    198 }
    199 
    200 static void process_cmd(struct android_app* app, struct android_poll_source* source) {
    201     int8_t cmd = android_app_read_cmd(app);
    202     android_app_pre_exec_cmd(app, cmd);
    203     if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
    204     android_app_post_exec_cmd(app, cmd);
    205 }
    206 
    207 static void* android_app_entry(void* param) {
    208     struct android_app* android_app = (struct android_app*)param;
    209 
    210     android_app->config = AConfiguration_new();
    211     AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
    212 
    213     print_cur_config(android_app);
    214 
    215     android_app->cmdPollSource.id = LOOPER_ID_MAIN;
    216     android_app->cmdPollSource.app = android_app;
    217     android_app->cmdPollSource.process = process_cmd;
    218     android_app->inputPollSource.id = LOOPER_ID_INPUT;
    219     android_app->inputPollSource.app = android_app;
    220     android_app->inputPollSource.process = process_input;
    221 
    222     ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    223     ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
    224             &android_app->cmdPollSource);
    225     android_app->looper = looper;
    226 
    227     pthread_mutex_lock(&android_app->mutex);
    228     android_app->running = 1;
    229     pthread_cond_broadcast(&android_app->cond);
    230     pthread_mutex_unlock(&android_app->mutex);
    231 
    232     android_main(android_app);
    233 
    234     android_app_destroy(android_app);
    235     return NULL;
    236 }
    237 
    238 // --------------------------------------------------------------------
    239 // Native activity interaction (called from main thread)
    240 // --------------------------------------------------------------------
    241 
    242 static struct android_app* android_app_create(ANativeActivity* activity,
    243         void* savedState, size_t savedStateSize) {
    244     struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
    245     memset(android_app, 0, sizeof(struct android_app));
    246     android_app->activity = activity;
    247 
    248     pthread_mutex_init(&android_app->mutex, NULL);
    249     pthread_cond_init(&android_app->cond, NULL);
    250 
    251     if (savedState != NULL) {
    252         android_app->savedState = malloc(savedStateSize);
    253         android_app->savedStateSize = savedStateSize;
    254         memcpy(android_app->savedState, savedState, savedStateSize);
    255     }
    256 
    257     int msgpipe[2];
    258     if (pipe(msgpipe)) {
    259         LOGE("could not create pipe: %s", strerror(errno));
    260         return NULL;
    261     }
    262     android_app->msgread = msgpipe[0];
    263     android_app->msgwrite = msgpipe[1];
    264 
    265     pthread_attr_t attr;
    266     pthread_attr_init(&attr);
    267     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    268     pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
    269 
    270     // Wait for thread to start.
    271     pthread_mutex_lock(&android_app->mutex);
    272     while (!android_app->running) {
    273         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    274     }
    275     pthread_mutex_unlock(&android_app->mutex);
    276 
    277     return android_app;
    278 }
    279 
    280 static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
    281     if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
    282         LOGE("Failure writing android_app cmd: %s\n", strerror(errno));
    283     }
    284 }
    285 
    286 static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
    287     pthread_mutex_lock(&android_app->mutex);
    288     android_app->pendingInputQueue = inputQueue;
    289     android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
    290     while (android_app->inputQueue != android_app->pendingInputQueue) {
    291         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    292     }
    293     pthread_mutex_unlock(&android_app->mutex);
    294 }
    295 
    296 static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
    297     pthread_mutex_lock(&android_app->mutex);
    298     if (android_app->pendingWindow != NULL) {
    299         android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
    300     }
    301     android_app->pendingWindow = window;
    302     if (window != NULL) {
    303         android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
    304     }
    305     while (android_app->window != android_app->pendingWindow) {
    306         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    307     }
    308     pthread_mutex_unlock(&android_app->mutex);
    309 }
    310 
    311 static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
    312     pthread_mutex_lock(&android_app->mutex);
    313     android_app_write_cmd(android_app, cmd);
    314     while (android_app->activityState != cmd) {
    315         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    316     }
    317     pthread_mutex_unlock(&android_app->mutex);
    318 }
    319 
    320 static void android_app_free(struct android_app* android_app) {
    321     pthread_mutex_lock(&android_app->mutex);
    322     android_app_write_cmd(android_app, APP_CMD_DESTROY);
    323     while (!android_app->destroyed) {
    324         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    325     }
    326     pthread_mutex_unlock(&android_app->mutex);
    327 
    328     close(android_app->msgread);
    329     close(android_app->msgwrite);
    330     pthread_cond_destroy(&android_app->cond);
    331     pthread_mutex_destroy(&android_app->mutex);
    332     free(android_app);
    333 }
    334 
    335 static void onDestroy(ANativeActivity* activity) {
    336     LOGV("Destroy: %p\n", activity);
    337     android_app_free((struct android_app*)activity->instance);
    338 }
    339 
    340 static void onStart(ANativeActivity* activity) {
    341     LOGV("Start: %p\n", activity);
    342     android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
    343 }
    344 
    345 static void onResume(ANativeActivity* activity) {
    346     LOGV("Resume: %p\n", activity);
    347     android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
    348 }
    349 
    350 static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
    351     struct android_app* android_app = (struct android_app*)activity->instance;
    352     void* savedState = NULL;
    353 
    354     LOGV("SaveInstanceState: %p\n", activity);
    355     pthread_mutex_lock(&android_app->mutex);
    356     android_app->stateSaved = 0;
    357     android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
    358     while (!android_app->stateSaved) {
    359         pthread_cond_wait(&android_app->cond, &android_app->mutex);
    360     }
    361 
    362     if (android_app->savedState != NULL) {
    363         savedState = android_app->savedState;
    364         *outLen = android_app->savedStateSize;
    365         android_app->savedState = NULL;
    366         android_app->savedStateSize = 0;
    367     }
    368 
    369     pthread_mutex_unlock(&android_app->mutex);
    370 
    371     return savedState;
    372 }
    373 
    374 static void onPause(ANativeActivity* activity) {
    375     LOGV("Pause: %p\n", activity);
    376     android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
    377 }
    378 
    379 static void onStop(ANativeActivity* activity) {
    380     LOGV("Stop: %p\n", activity);
    381     android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
    382 }
    383 
    384 static void onConfigurationChanged(ANativeActivity* activity) {
    385     struct android_app* android_app = (struct android_app*)activity->instance;
    386     LOGV("ConfigurationChanged: %p\n", activity);
    387     android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
    388 }
    389 
    390 static void onLowMemory(ANativeActivity* activity) {
    391     struct android_app* android_app = (struct android_app*)activity->instance;
    392     LOGV("LowMemory: %p\n", activity);
    393     android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
    394 }
    395 
    396 static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
    397     LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);
    398     android_app_write_cmd((struct android_app*)activity->instance,
    399             focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
    400 }
    401 
    402 static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
    403     LOGV("NativeWindowCreated: %p -- %p\n", activity, window);
    404     android_app_set_window((struct android_app*)activity->instance, window);
    405 }
    406 
    407 static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
    408     LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);
    409     android_app_set_window((struct android_app*)activity->instance, NULL);
    410 }
    411 
    412 static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
    413     LOGV("InputQueueCreated: %p -- %p\n", activity, queue);
    414     android_app_set_input((struct android_app*)activity->instance, queue);
    415 }
    416 
    417 static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
    418     LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);
    419     android_app_set_input((struct android_app*)activity->instance, NULL);
    420 }
    421 
    422 void ANativeActivity_onCreate(ANativeActivity* activity,
    423         void* savedState, size_t savedStateSize) {
    424     LOGV("Creating: %p\n", activity);
    425     activity->callbacks->onDestroy = onDestroy;
    426     activity->callbacks->onStart = onStart;
    427     activity->callbacks->onResume = onResume;
    428     activity->callbacks->onSaveInstanceState = onSaveInstanceState;
    429     activity->callbacks->onPause = onPause;
    430     activity->callbacks->onStop = onStop;
    431     activity->callbacks->onConfigurationChanged = onConfigurationChanged;
    432     activity->callbacks->onLowMemory = onLowMemory;
    433     activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
    434     activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
    435     activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
    436     activity->callbacks->onInputQueueCreated = onInputQueueCreated;
    437     activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
    438 
    439     activity->instance = android_app_create(activity, savedState, savedStateSize);
    440 }
    441