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