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