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