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 void ANativeActivity_onCreate(ANativeActivity* activity, 424 void* savedState, size_t savedStateSize) { 425 LOGV("Creating: %p\n", activity); 426 activity->callbacks->onDestroy = onDestroy; 427 activity->callbacks->onStart = onStart; 428 activity->callbacks->onResume = onResume; 429 activity->callbacks->onSaveInstanceState = onSaveInstanceState; 430 activity->callbacks->onPause = onPause; 431 activity->callbacks->onStop = onStop; 432 activity->callbacks->onConfigurationChanged = onConfigurationChanged; 433 activity->callbacks->onLowMemory = onLowMemory; 434 activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; 435 activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; 436 activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; 437 activity->callbacks->onInputQueueCreated = onInputQueueCreated; 438 activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; 439 440 activity->instance = android_app_create(activity, savedState, savedStateSize); 441 } 442