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