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 #define LOG_TAG "NativeActivity" 18 #include <utils/Log.h> 19 20 #include <poll.h> 21 #include <dlfcn.h> 22 #include <fcntl.h> 23 24 #include <android_runtime/AndroidRuntime.h> 25 #include <android_runtime/android_view_Surface.h> 26 #include <android_runtime/android_app_NativeActivity.h> 27 #include <android_runtime/android_util_AssetManager.h> 28 #include <surfaceflinger/Surface.h> 29 #include <ui/egl/android_natives.h> 30 #include <ui/InputTransport.h> 31 #include <utils/Looper.h> 32 33 #include "JNIHelp.h" 34 #include "android_os_MessageQueue.h" 35 #include "android_view_InputChannel.h" 36 #include "android_view_KeyEvent.h" 37 38 #define LOG_TRACE(...) 39 //#define LOG_TRACE(...) LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) 40 41 namespace android 42 { 43 44 static struct { 45 jmethodID dispatchUnhandledKeyEvent; 46 jmethodID preDispatchKeyEvent; 47 jmethodID finish; 48 jmethodID setWindowFlags; 49 jmethodID setWindowFormat; 50 jmethodID showIme; 51 jmethodID hideIme; 52 } gNativeActivityClassInfo; 53 54 // ------------------------------------------------------------------------ 55 56 struct ActivityWork { 57 int32_t cmd; 58 int32_t arg1; 59 int32_t arg2; 60 }; 61 62 enum { 63 CMD_DEF_KEY = 1, 64 CMD_FINISH, 65 CMD_SET_WINDOW_FORMAT, 66 CMD_SET_WINDOW_FLAGS, 67 CMD_SHOW_SOFT_INPUT, 68 CMD_HIDE_SOFT_INPUT, 69 }; 70 71 static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) { 72 ActivityWork work; 73 work.cmd = cmd; 74 work.arg1 = arg1; 75 work.arg2 = arg2; 76 77 LOG_TRACE("write_work: cmd=%d", cmd); 78 79 restart: 80 int res = write(fd, &work, sizeof(work)); 81 if (res < 0 && errno == EINTR) { 82 goto restart; 83 } 84 85 if (res == sizeof(work)) return; 86 87 if (res < 0) LOGW("Failed writing to work fd: %s", strerror(errno)); 88 else LOGW("Truncated writing to work fd: %d", res); 89 } 90 91 static bool read_work(int fd, ActivityWork* outWork) { 92 int res = read(fd, outWork, sizeof(ActivityWork)); 93 // no need to worry about EINTR, poll loop will just come back again. 94 if (res == sizeof(ActivityWork)) return true; 95 96 if (res < 0) LOGW("Failed reading work fd: %s", strerror(errno)); 97 else LOGW("Truncated reading work fd: %d", res); 98 return false; 99 } 100 101 // ------------------------------------------------------------------------ 102 103 } // namespace android 104 105 using namespace android; 106 107 AInputQueue::AInputQueue(const sp<InputChannel>& channel, int workWrite) : 108 mWorkWrite(workWrite), mConsumer(channel), mSeq(0) { 109 int msgpipe[2]; 110 if (pipe(msgpipe)) { 111 LOGW("could not create pipe: %s", strerror(errno)); 112 mDispatchKeyRead = mDispatchKeyWrite = -1; 113 } else { 114 mDispatchKeyRead = msgpipe[0]; 115 mDispatchKeyWrite = msgpipe[1]; 116 int result = fcntl(mDispatchKeyRead, F_SETFL, O_NONBLOCK); 117 SLOGW_IF(result != 0, "Could not make AInputQueue read pipe " 118 "non-blocking: %s", strerror(errno)); 119 result = fcntl(mDispatchKeyWrite, F_SETFL, O_NONBLOCK); 120 SLOGW_IF(result != 0, "Could not make AInputQueue write pipe " 121 "non-blocking: %s", strerror(errno)); 122 } 123 } 124 125 AInputQueue::~AInputQueue() { 126 close(mDispatchKeyRead); 127 close(mDispatchKeyWrite); 128 } 129 130 void AInputQueue::attachLooper(ALooper* looper, int ident, 131 ALooper_callbackFunc callback, void* data) { 132 mLooper = static_cast<android::Looper*>(looper); 133 mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(), 134 ident, ALOOPER_EVENT_INPUT, callback, data); 135 mLooper->addFd(mDispatchKeyRead, 136 ident, ALOOPER_EVENT_INPUT, callback, data); 137 } 138 139 void AInputQueue::detachLooper() { 140 mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd()); 141 mLooper->removeFd(mDispatchKeyRead); 142 } 143 144 int32_t AInputQueue::hasEvents() { 145 struct pollfd pfd[2]; 146 147 pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd(); 148 pfd[0].events = POLLIN; 149 pfd[0].revents = 0; 150 pfd[1].fd = mDispatchKeyRead; 151 pfd[1].events = POLLIN; 152 pfd[1].revents = 0; 153 154 int nfd = poll(pfd, 2, 0); 155 if (nfd <= 0) return 0; 156 return ((pfd[0].revents & POLLIN) || (pfd[1].revents & POLLIN)) ? 1 : -1; 157 } 158 159 int32_t AInputQueue::getEvent(AInputEvent** outEvent) { 160 *outEvent = NULL; 161 162 bool finishNow = false; 163 164 char byteread; 165 ssize_t nRead = read(mDispatchKeyRead, &byteread, 1); 166 if (nRead == 1) { 167 mLock.lock(); 168 if (mDispatchingKeys.size() > 0) { 169 KeyEvent* kevent = mDispatchingKeys[0]; 170 *outEvent = kevent; 171 mDispatchingKeys.removeAt(0); 172 in_flight_event inflight; 173 inflight.event = kevent; 174 inflight.seq = -1; 175 inflight.doFinish = false; 176 mInFlightEvents.push(inflight); 177 } 178 if (mFinishPreDispatches.size() > 0) { 179 finish_pre_dispatch finish(mFinishPreDispatches[0]); 180 mFinishPreDispatches.removeAt(0); 181 const size_t N = mInFlightEvents.size(); 182 for (size_t i=0; i<N; i++) { 183 const in_flight_event& inflight(mInFlightEvents[i]); 184 if (inflight.seq == finish.seq) { 185 *outEvent = inflight.event; 186 finishNow = finish.handled; 187 } 188 } 189 if (*outEvent == NULL) { 190 LOGW("getEvent couldn't find inflight for seq %d", finish.seq); 191 } 192 } 193 mLock.unlock(); 194 195 if (finishNow) { 196 finishEvent(*outEvent, true, false); 197 *outEvent = NULL; 198 return -1; 199 } else if (*outEvent != NULL) { 200 return 0; 201 } 202 } 203 204 int32_t res = mConsumer.receiveDispatchSignal(); 205 if (res != android::OK) { 206 LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d", 207 mConsumer.getChannel()->getName().string(), res); 208 return -1; 209 } 210 211 InputEvent* myEvent = NULL; 212 res = mConsumer.consume(this, &myEvent); 213 if (res != android::OK) { 214 LOGW("channel '%s' ~ Failed to consume input event. status=%d", 215 mConsumer.getChannel()->getName().string(), res); 216 mConsumer.sendFinishedSignal(false); 217 return -1; 218 } 219 220 in_flight_event inflight; 221 inflight.event = myEvent; 222 inflight.seq = -1; 223 inflight.doFinish = true; 224 mInFlightEvents.push(inflight); 225 226 *outEvent = myEvent; 227 return 0; 228 } 229 230 bool AInputQueue::preDispatchEvent(AInputEvent* event) { 231 if (((InputEvent*)event)->getType() != AINPUT_EVENT_TYPE_KEY) { 232 // The IME only cares about key events. 233 return false; 234 } 235 236 // For now we only send system keys to the IME... this avoids having 237 // critical keys like DPAD go through this path. We really need to have 238 // the IME report which keys it wants. 239 if (!((KeyEvent*)event)->isSystemKey()) { 240 return false; 241 } 242 243 return preDispatchKey((KeyEvent*)event); 244 } 245 246 void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultHandling) { 247 LOG_TRACE("finishEvent: %p handled=%d, didDefaultHandling=%d", event, 248 handled ? 1 : 0, didDefaultHandling ? 1 : 0); 249 250 if (!handled && !didDefaultHandling 251 && ((InputEvent*)event)->getType() == AINPUT_EVENT_TYPE_KEY 252 && ((KeyEvent*)event)->hasDefaultAction()) { 253 // The app didn't handle this, but it may have a default action 254 // associated with it. We need to hand this back to Java to be 255 // executed. 256 doUnhandledKey((KeyEvent*)event); 257 return; 258 } 259 260 mLock.lock(); 261 const size_t N = mInFlightEvents.size(); 262 for (size_t i=0; i<N; i++) { 263 const in_flight_event& inflight(mInFlightEvents[i]); 264 if (inflight.event == event) { 265 if (inflight.doFinish) { 266 int32_t res = mConsumer.sendFinishedSignal(handled); 267 if (res != android::OK) { 268 LOGW("Failed to send finished signal on channel '%s'. status=%d", 269 mConsumer.getChannel()->getName().string(), res); 270 } 271 } 272 if (static_cast<InputEvent*>(event)->getType() == AINPUT_EVENT_TYPE_KEY) { 273 mAvailKeyEvents.push(static_cast<KeyEvent*>(event)); 274 } else { 275 mAvailMotionEvents.push(static_cast<MotionEvent*>(event)); 276 } 277 mInFlightEvents.removeAt(i); 278 mLock.unlock(); 279 return; 280 } 281 } 282 mLock.unlock(); 283 284 LOGW("finishEvent called for unknown event: %p", event); 285 } 286 287 void AInputQueue::dispatchEvent(android::KeyEvent* event) { 288 mLock.lock(); 289 LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(), 290 mDispatchKeyWrite); 291 mDispatchingKeys.add(event); 292 wakeupDispatch(); 293 mLock.unlock(); 294 } 295 296 void AInputQueue::finishPreDispatch(int seq, bool handled) { 297 mLock.lock(); 298 LOG_TRACE("finishPreDispatch: seq=%d handled=%d\n", seq, handled ? 1 : 0); 299 finish_pre_dispatch finish; 300 finish.seq = seq; 301 finish.handled = handled; 302 mFinishPreDispatches.add(finish); 303 wakeupDispatch(); 304 mLock.unlock(); 305 } 306 307 KeyEvent* AInputQueue::consumeUnhandledEvent() { 308 KeyEvent* event = NULL; 309 310 mLock.lock(); 311 if (mUnhandledKeys.size() > 0) { 312 event = mUnhandledKeys[0]; 313 mUnhandledKeys.removeAt(0); 314 } 315 mLock.unlock(); 316 317 LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event); 318 319 return event; 320 } 321 322 KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) { 323 KeyEvent* event = NULL; 324 325 mLock.lock(); 326 if (mPreDispatchingKeys.size() > 0) { 327 const in_flight_event& inflight(mPreDispatchingKeys[0]); 328 event = static_cast<KeyEvent*>(inflight.event); 329 *outSeq = inflight.seq; 330 mPreDispatchingKeys.removeAt(0); 331 } 332 mLock.unlock(); 333 334 LOG_TRACE("consumePreDispatchingEvent: KeyEvent=%p", event); 335 336 return event; 337 } 338 339 KeyEvent* AInputQueue::createKeyEvent() { 340 mLock.lock(); 341 KeyEvent* event; 342 if (mAvailKeyEvents.size() <= 0) { 343 event = new KeyEvent(); 344 } else { 345 event = mAvailKeyEvents.top(); 346 mAvailKeyEvents.pop(); 347 } 348 mLock.unlock(); 349 return event; 350 } 351 352 MotionEvent* AInputQueue::createMotionEvent() { 353 mLock.lock(); 354 MotionEvent* event; 355 if (mAvailMotionEvents.size() <= 0) { 356 event = new MotionEvent(); 357 } else { 358 event = mAvailMotionEvents.top(); 359 mAvailMotionEvents.pop(); 360 } 361 mLock.unlock(); 362 return event; 363 } 364 365 void AInputQueue::doUnhandledKey(KeyEvent* keyEvent) { 366 mLock.lock(); 367 LOG_TRACE("Unhandled key: pending=%d write=%d\n", mUnhandledKeys.size(), mWorkWrite); 368 if (mUnhandledKeys.size() <= 0 && mWorkWrite >= 0) { 369 write_work(mWorkWrite, CMD_DEF_KEY); 370 } 371 mUnhandledKeys.add(keyEvent); 372 mLock.unlock(); 373 } 374 375 bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { 376 mLock.lock(); 377 LOG_TRACE("preDispatch key: pending=%d write=%d\n", mPreDispatchingKeys.size(), mWorkWrite); 378 const size_t N = mInFlightEvents.size(); 379 for (size_t i=0; i<N; i++) { 380 in_flight_event& inflight(mInFlightEvents.editItemAt(i)); 381 if (inflight.event == keyEvent) { 382 if (inflight.seq >= 0) { 383 // This event has already been pre-dispatched! 384 LOG_TRACE("Event already pre-dispatched!"); 385 mLock.unlock(); 386 return false; 387 } 388 mSeq++; 389 if (mSeq < 0) mSeq = 1; 390 inflight.seq = mSeq; 391 392 if (mPreDispatchingKeys.size() <= 0 && mWorkWrite >= 0) { 393 write_work(mWorkWrite, CMD_DEF_KEY); 394 } 395 mPreDispatchingKeys.add(inflight); 396 mLock.unlock(); 397 return true; 398 } 399 } 400 401 LOGW("preDispatchKey called for unknown event: %p", keyEvent); 402 return false; 403 } 404 405 void AInputQueue::wakeupDispatch() { 406 restart: 407 char dummy = 0; 408 int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy)); 409 if (res < 0 && errno == EINTR) { 410 goto restart; 411 } 412 413 if (res == sizeof(dummy)) return; 414 415 if (res < 0) LOGW("Failed writing to dispatch fd: %s", strerror(errno)); 416 else LOGW("Truncated writing to dispatch fd: %d", res); 417 } 418 419 namespace android { 420 421 // ------------------------------------------------------------------------ 422 423 /* 424 * Native state for interacting with the NativeActivity class. 425 */ 426 struct NativeCode : public ANativeActivity { 427 NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) { 428 memset((ANativeActivity*)this, 0, sizeof(ANativeActivity)); 429 memset(&callbacks, 0, sizeof(callbacks)); 430 dlhandle = _dlhandle; 431 createActivityFunc = _createFunc; 432 nativeWindow = NULL; 433 inputChannel = NULL; 434 nativeInputQueue = NULL; 435 mainWorkRead = mainWorkWrite = -1; 436 } 437 438 ~NativeCode() { 439 if (callbacks.onDestroy != NULL) { 440 callbacks.onDestroy(this); 441 } 442 if (env != NULL && clazz != NULL) { 443 env->DeleteGlobalRef(clazz); 444 } 445 if (looper != NULL && mainWorkRead >= 0) { 446 looper->removeFd(mainWorkRead); 447 } 448 if (nativeInputQueue != NULL) { 449 nativeInputQueue->mWorkWrite = -1; 450 } 451 setSurface(NULL); 452 setInputChannel(NULL); 453 if (mainWorkRead >= 0) close(mainWorkRead); 454 if (mainWorkWrite >= 0) close(mainWorkWrite); 455 if (dlhandle != NULL) { 456 // for now don't unload... we probably should clean this 457 // up and only keep one open dlhandle per proc, since there 458 // is really no benefit to unloading the code. 459 //dlclose(dlhandle); 460 } 461 } 462 463 void setSurface(jobject _surface) { 464 if (_surface != NULL) { 465 nativeWindow = android_Surface_getNativeWindow(env, _surface); 466 } else { 467 nativeWindow = NULL; 468 } 469 } 470 471 status_t setInputChannel(jobject _channel) { 472 if (inputChannel != NULL) { 473 delete nativeInputQueue; 474 env->DeleteGlobalRef(inputChannel); 475 } 476 inputChannel = NULL; 477 nativeInputQueue = NULL; 478 if (_channel != NULL) { 479 inputChannel = env->NewGlobalRef(_channel); 480 sp<InputChannel> ic = 481 android_view_InputChannel_getInputChannel(env, _channel); 482 if (ic != NULL) { 483 nativeInputQueue = new AInputQueue(ic, mainWorkWrite); 484 if (nativeInputQueue->getConsumer().initialize() != android::OK) { 485 delete nativeInputQueue; 486 nativeInputQueue = NULL; 487 return UNKNOWN_ERROR; 488 } 489 } else { 490 return UNKNOWN_ERROR; 491 } 492 } 493 return OK; 494 } 495 496 ANativeActivityCallbacks callbacks; 497 498 void* dlhandle; 499 ANativeActivity_createFunc* createActivityFunc; 500 501 String8 internalDataPathObj; 502 String8 externalDataPathObj; 503 String8 obbPathObj; 504 505 sp<ANativeWindow> nativeWindow; 506 int32_t lastWindowWidth; 507 int32_t lastWindowHeight; 508 509 jobject inputChannel; 510 struct AInputQueue* nativeInputQueue; 511 512 // These are used to wake up the main thread to process work. 513 int mainWorkRead; 514 int mainWorkWrite; 515 sp<Looper> looper; 516 }; 517 518 void android_NativeActivity_finish(ANativeActivity* activity) { 519 NativeCode* code = static_cast<NativeCode*>(activity); 520 write_work(code->mainWorkWrite, CMD_FINISH, 0); 521 } 522 523 void android_NativeActivity_setWindowFormat( 524 ANativeActivity* activity, int32_t format) { 525 NativeCode* code = static_cast<NativeCode*>(activity); 526 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FORMAT, format); 527 } 528 529 void android_NativeActivity_setWindowFlags( 530 ANativeActivity* activity, int32_t values, int32_t mask) { 531 NativeCode* code = static_cast<NativeCode*>(activity); 532 write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask); 533 } 534 535 void android_NativeActivity_showSoftInput( 536 ANativeActivity* activity, int32_t flags) { 537 NativeCode* code = static_cast<NativeCode*>(activity); 538 write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags); 539 } 540 541 void android_NativeActivity_hideSoftInput( 542 ANativeActivity* activity, int32_t flags) { 543 NativeCode* code = static_cast<NativeCode*>(activity); 544 write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags); 545 } 546 547 // ------------------------------------------------------------------------ 548 549 static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { 550 if (env->ExceptionCheck()) { 551 LOGE("An exception was thrown by callback '%s'.", methodName); 552 LOGE_EX(env); 553 env->ExceptionClear(); 554 return true; 555 } 556 return false; 557 } 558 559 /* 560 * Callback for handling native events on the application's main thread. 561 */ 562 static int mainWorkCallback(int fd, int events, void* data) { 563 NativeCode* code = (NativeCode*)data; 564 if ((events & POLLIN) == 0) { 565 return 1; 566 } 567 568 ActivityWork work; 569 if (!read_work(code->mainWorkRead, &work)) { 570 return 1; 571 } 572 573 LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd); 574 575 switch (work.cmd) { 576 case CMD_DEF_KEY: { 577 KeyEvent* keyEvent; 578 while ((keyEvent=code->nativeInputQueue->consumeUnhandledEvent()) != NULL) { 579 jobject inputEventObj = android_view_KeyEvent_fromNative( 580 code->env, keyEvent); 581 jboolean handled; 582 if (inputEventObj) { 583 handled = code->env->CallBooleanMethod(code->clazz, 584 gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj); 585 checkAndClearExceptionFromCallback(code->env, "dispatchUnhandledKeyEvent"); 586 code->env->DeleteLocalRef(inputEventObj); 587 } else { 588 LOGE("Failed to obtain key event for dispatchUnhandledKeyEvent."); 589 handled = false; 590 } 591 code->nativeInputQueue->finishEvent(keyEvent, handled, true); 592 } 593 int seq; 594 while ((keyEvent=code->nativeInputQueue->consumePreDispatchingEvent(&seq)) != NULL) { 595 jobject inputEventObj = android_view_KeyEvent_fromNative( 596 code->env, keyEvent); 597 if (inputEventObj) { 598 code->env->CallVoidMethod(code->clazz, 599 gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq); 600 checkAndClearExceptionFromCallback(code->env, "preDispatchKeyEvent"); 601 code->env->DeleteLocalRef(inputEventObj); 602 } else { 603 LOGE("Failed to obtain key event for preDispatchKeyEvent."); 604 } 605 } 606 } break; 607 case CMD_FINISH: { 608 code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.finish); 609 checkAndClearExceptionFromCallback(code->env, "finish"); 610 } break; 611 case CMD_SET_WINDOW_FORMAT: { 612 code->env->CallVoidMethod(code->clazz, 613 gNativeActivityClassInfo.setWindowFormat, work.arg1); 614 checkAndClearExceptionFromCallback(code->env, "setWindowFormat"); 615 } break; 616 case CMD_SET_WINDOW_FLAGS: { 617 code->env->CallVoidMethod(code->clazz, 618 gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2); 619 checkAndClearExceptionFromCallback(code->env, "setWindowFlags"); 620 } break; 621 case CMD_SHOW_SOFT_INPUT: { 622 code->env->CallVoidMethod(code->clazz, 623 gNativeActivityClassInfo.showIme, work.arg1); 624 checkAndClearExceptionFromCallback(code->env, "showIme"); 625 } break; 626 case CMD_HIDE_SOFT_INPUT: { 627 code->env->CallVoidMethod(code->clazz, 628 gNativeActivityClassInfo.hideIme, work.arg1); 629 checkAndClearExceptionFromCallback(code->env, "hideIme"); 630 } break; 631 default: 632 LOGW("Unknown work command: %d", work.cmd); 633 break; 634 } 635 636 return 1; 637 } 638 639 // ------------------------------------------------------------------------ 640 641 static jint 642 loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName, 643 jobject messageQueue, jstring internalDataDir, jstring obbDir, 644 jstring externalDataDir, int sdkVersion, 645 jobject jAssetMgr, jbyteArray savedState) 646 { 647 LOG_TRACE("loadNativeCode_native"); 648 649 const char* pathStr = env->GetStringUTFChars(path, NULL); 650 NativeCode* code = NULL; 651 652 void* handle = dlopen(pathStr, RTLD_LAZY); 653 654 env->ReleaseStringUTFChars(path, pathStr); 655 656 if (handle != NULL) { 657 const char* funcStr = env->GetStringUTFChars(funcName, NULL); 658 code = new NativeCode(handle, (ANativeActivity_createFunc*) 659 dlsym(handle, funcStr)); 660 env->ReleaseStringUTFChars(funcName, funcStr); 661 662 if (code->createActivityFunc == NULL) { 663 LOGW("ANativeActivity_onCreate not found"); 664 delete code; 665 return 0; 666 } 667 668 code->looper = android_os_MessageQueue_getLooper(env, messageQueue); 669 if (code->looper == NULL) { 670 LOGW("Unable to retrieve MessageQueue's Looper"); 671 delete code; 672 return 0; 673 } 674 675 int msgpipe[2]; 676 if (pipe(msgpipe)) { 677 LOGW("could not create pipe: %s", strerror(errno)); 678 delete code; 679 return 0; 680 } 681 code->mainWorkRead = msgpipe[0]; 682 code->mainWorkWrite = msgpipe[1]; 683 int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK); 684 SLOGW_IF(result != 0, "Could not make main work read pipe " 685 "non-blocking: %s", strerror(errno)); 686 result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK); 687 SLOGW_IF(result != 0, "Could not make main work write pipe " 688 "non-blocking: %s", strerror(errno)); 689 code->looper->addFd(code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code); 690 691 code->ANativeActivity::callbacks = &code->callbacks; 692 if (env->GetJavaVM(&code->vm) < 0) { 693 LOGW("NativeActivity GetJavaVM failed"); 694 delete code; 695 return 0; 696 } 697 code->env = env; 698 code->clazz = env->NewGlobalRef(clazz); 699 700 const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL); 701 code->internalDataPathObj = dirStr; 702 code->internalDataPath = code->internalDataPathObj.string(); 703 env->ReleaseStringUTFChars(internalDataDir, dirStr); 704 705 dirStr = env->GetStringUTFChars(externalDataDir, NULL); 706 code->externalDataPathObj = dirStr; 707 code->externalDataPath = code->externalDataPathObj.string(); 708 env->ReleaseStringUTFChars(externalDataDir, dirStr); 709 710 code->sdkVersion = sdkVersion; 711 712 code->assetManager = assetManagerForJavaObject(env, jAssetMgr); 713 714 dirStr = env->GetStringUTFChars(obbDir, NULL); 715 code->obbPathObj = dirStr; 716 code->obbPath = code->obbPathObj.string(); 717 env->ReleaseStringUTFChars(obbDir, dirStr); 718 719 jbyte* rawSavedState = NULL; 720 jsize rawSavedSize = 0; 721 if (savedState != NULL) { 722 rawSavedState = env->GetByteArrayElements(savedState, NULL); 723 rawSavedSize = env->GetArrayLength(savedState); 724 } 725 726 code->createActivityFunc(code, rawSavedState, rawSavedSize); 727 728 if (rawSavedState != NULL) { 729 env->ReleaseByteArrayElements(savedState, rawSavedState, 0); 730 } 731 } 732 733 return (jint)code; 734 } 735 736 static void 737 unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle) 738 { 739 LOG_TRACE("unloadNativeCode_native"); 740 if (handle != 0) { 741 NativeCode* code = (NativeCode*)handle; 742 delete code; 743 } 744 } 745 746 static void 747 onStart_native(JNIEnv* env, jobject clazz, jint handle) 748 { 749 LOG_TRACE("onStart_native"); 750 if (handle != 0) { 751 NativeCode* code = (NativeCode*)handle; 752 if (code->callbacks.onStart != NULL) { 753 code->callbacks.onStart(code); 754 } 755 } 756 } 757 758 static void 759 onResume_native(JNIEnv* env, jobject clazz, jint handle) 760 { 761 LOG_TRACE("onResume_native"); 762 if (handle != 0) { 763 NativeCode* code = (NativeCode*)handle; 764 if (code->callbacks.onResume != NULL) { 765 code->callbacks.onResume(code); 766 } 767 } 768 } 769 770 static jbyteArray 771 onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle) 772 { 773 LOG_TRACE("onSaveInstanceState_native"); 774 775 jbyteArray array = NULL; 776 777 if (handle != 0) { 778 NativeCode* code = (NativeCode*)handle; 779 if (code->callbacks.onSaveInstanceState != NULL) { 780 size_t len = 0; 781 jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len); 782 if (len > 0) { 783 array = env->NewByteArray(len); 784 if (array != NULL) { 785 env->SetByteArrayRegion(array, 0, len, state); 786 } 787 } 788 if (state != NULL) { 789 free(state); 790 } 791 } 792 } 793 794 return array; 795 } 796 797 static void 798 onPause_native(JNIEnv* env, jobject clazz, jint handle) 799 { 800 LOG_TRACE("onPause_native"); 801 if (handle != 0) { 802 NativeCode* code = (NativeCode*)handle; 803 if (code->callbacks.onPause != NULL) { 804 code->callbacks.onPause(code); 805 } 806 } 807 } 808 809 static void 810 onStop_native(JNIEnv* env, jobject clazz, jint handle) 811 { 812 LOG_TRACE("onStop_native"); 813 if (handle != 0) { 814 NativeCode* code = (NativeCode*)handle; 815 if (code->callbacks.onStop != NULL) { 816 code->callbacks.onStop(code); 817 } 818 } 819 } 820 821 static void 822 onConfigurationChanged_native(JNIEnv* env, jobject clazz, jint handle) 823 { 824 LOG_TRACE("onConfigurationChanged_native"); 825 if (handle != 0) { 826 NativeCode* code = (NativeCode*)handle; 827 if (code->callbacks.onConfigurationChanged != NULL) { 828 code->callbacks.onConfigurationChanged(code); 829 } 830 } 831 } 832 833 static void 834 onLowMemory_native(JNIEnv* env, jobject clazz, jint handle) 835 { 836 LOG_TRACE("onLowMemory_native"); 837 if (handle != 0) { 838 NativeCode* code = (NativeCode*)handle; 839 if (code->callbacks.onLowMemory != NULL) { 840 code->callbacks.onLowMemory(code); 841 } 842 } 843 } 844 845 static void 846 onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused) 847 { 848 LOG_TRACE("onWindowFocusChanged_native"); 849 if (handle != 0) { 850 NativeCode* code = (NativeCode*)handle; 851 if (code->callbacks.onWindowFocusChanged != NULL) { 852 code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0); 853 } 854 } 855 } 856 857 static void 858 onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) 859 { 860 LOG_TRACE("onSurfaceCreated_native"); 861 if (handle != 0) { 862 NativeCode* code = (NativeCode*)handle; 863 code->setSurface(surface); 864 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) { 865 code->callbacks.onNativeWindowCreated(code, 866 code->nativeWindow.get()); 867 } 868 } 869 } 870 871 static int32_t getWindowProp(ANativeWindow* window, int what) { 872 int value; 873 int res = window->query(window, what, &value); 874 return res < 0 ? res : value; 875 } 876 877 static void 878 onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface, 879 jint format, jint width, jint height) 880 { 881 LOG_TRACE("onSurfaceChanged_native"); 882 if (handle != 0) { 883 NativeCode* code = (NativeCode*)handle; 884 sp<ANativeWindow> oldNativeWindow = code->nativeWindow; 885 code->setSurface(surface); 886 if (oldNativeWindow != code->nativeWindow) { 887 if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { 888 code->callbacks.onNativeWindowDestroyed(code, 889 oldNativeWindow.get()); 890 } 891 if (code->nativeWindow != NULL) { 892 if (code->callbacks.onNativeWindowCreated != NULL) { 893 code->callbacks.onNativeWindowCreated(code, 894 code->nativeWindow.get()); 895 } 896 code->lastWindowWidth = getWindowProp(code->nativeWindow.get(), 897 NATIVE_WINDOW_WIDTH); 898 code->lastWindowHeight = getWindowProp(code->nativeWindow.get(), 899 NATIVE_WINDOW_HEIGHT); 900 } 901 } else { 902 // Maybe it resized? 903 int32_t newWidth = getWindowProp(code->nativeWindow.get(), 904 NATIVE_WINDOW_WIDTH); 905 int32_t newHeight = getWindowProp(code->nativeWindow.get(), 906 NATIVE_WINDOW_HEIGHT); 907 if (newWidth != code->lastWindowWidth 908 || newHeight != code->lastWindowHeight) { 909 if (code->callbacks.onNativeWindowResized != NULL) { 910 code->callbacks.onNativeWindowResized(code, 911 code->nativeWindow.get()); 912 } 913 } 914 } 915 } 916 } 917 918 static void 919 onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jint handle) 920 { 921 LOG_TRACE("onSurfaceRedrawNeeded_native"); 922 if (handle != 0) { 923 NativeCode* code = (NativeCode*)handle; 924 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) { 925 code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get()); 926 } 927 } 928 } 929 930 static void 931 onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) 932 { 933 LOG_TRACE("onSurfaceDestroyed_native"); 934 if (handle != 0) { 935 NativeCode* code = (NativeCode*)handle; 936 if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) { 937 code->callbacks.onNativeWindowDestroyed(code, 938 code->nativeWindow.get()); 939 } 940 code->setSurface(NULL); 941 } 942 } 943 944 static void 945 onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel) 946 { 947 LOG_TRACE("onInputChannelCreated_native"); 948 if (handle != 0) { 949 NativeCode* code = (NativeCode*)handle; 950 status_t err = code->setInputChannel(channel); 951 if (err != OK) { 952 jniThrowException(env, "java/lang/IllegalStateException", 953 "Error setting input channel"); 954 return; 955 } 956 if (code->callbacks.onInputQueueCreated != NULL) { 957 code->callbacks.onInputQueueCreated(code, 958 code->nativeInputQueue); 959 } 960 } 961 } 962 963 static void 964 onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel) 965 { 966 LOG_TRACE("onInputChannelDestroyed_native"); 967 if (handle != 0) { 968 NativeCode* code = (NativeCode*)handle; 969 if (code->nativeInputQueue != NULL 970 && code->callbacks.onInputQueueDestroyed != NULL) { 971 code->callbacks.onInputQueueDestroyed(code, 972 code->nativeInputQueue); 973 } 974 code->setInputChannel(NULL); 975 } 976 } 977 978 static void 979 onContentRectChanged_native(JNIEnv* env, jobject clazz, jint handle, 980 jint x, jint y, jint w, jint h) 981 { 982 LOG_TRACE("onContentRectChanged_native"); 983 if (handle != 0) { 984 NativeCode* code = (NativeCode*)handle; 985 if (code->callbacks.onContentRectChanged != NULL) { 986 ARect rect; 987 rect.left = x; 988 rect.top = y; 989 rect.right = x+w; 990 rect.bottom = y+h; 991 code->callbacks.onContentRectChanged(code, &rect); 992 } 993 } 994 } 995 996 static void 997 dispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, jobject eventObj) 998 { 999 LOG_TRACE("dispatchKeyEvent_native"); 1000 if (handle != 0) { 1001 NativeCode* code = (NativeCode*)handle; 1002 if (code->nativeInputQueue != NULL) { 1003 KeyEvent* event = code->nativeInputQueue->createKeyEvent(); 1004 status_t status = android_view_KeyEvent_toNative(env, eventObj, event); 1005 if (status) { 1006 delete event; 1007 jniThrowRuntimeException(env, "Could not read contents of KeyEvent object."); 1008 return; 1009 } 1010 code->nativeInputQueue->dispatchEvent(event); 1011 } 1012 } 1013 } 1014 1015 static void 1016 finishPreDispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, 1017 jint seq, jboolean handled) 1018 { 1019 LOG_TRACE("finishPreDispatchKeyEvent_native"); 1020 if (handle != 0) { 1021 NativeCode* code = (NativeCode*)handle; 1022 if (code->nativeInputQueue != NULL) { 1023 code->nativeInputQueue->finishPreDispatch(seq, handled ? true : false); 1024 } 1025 } 1026 } 1027 1028 static const JNINativeMethod g_methods[] = { 1029 { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I", 1030 (void*)loadNativeCode_native }, 1031 { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, 1032 { "onStartNative", "(I)V", (void*)onStart_native }, 1033 { "onResumeNative", "(I)V", (void*)onResume_native }, 1034 { "onSaveInstanceStateNative", "(I)[B", (void*)onSaveInstanceState_native }, 1035 { "onPauseNative", "(I)V", (void*)onPause_native }, 1036 { "onStopNative", "(I)V", (void*)onStop_native }, 1037 { "onConfigurationChangedNative", "(I)V", (void*)onConfigurationChanged_native }, 1038 { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native }, 1039 { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native }, 1040 { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native }, 1041 { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native }, 1042 { "onSurfaceRedrawNeededNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native }, 1043 { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native }, 1044 { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native }, 1045 { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native }, 1046 { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native }, 1047 { "dispatchKeyEventNative", "(ILandroid/view/KeyEvent;)V", (void*)dispatchKeyEvent_native }, 1048 { "finishPreDispatchKeyEventNative", "(IIZ)V", (void*)finishPreDispatchKeyEvent_native }, 1049 }; 1050 1051 static const char* const kNativeActivityPathName = "android/app/NativeActivity"; 1052 1053 #define FIND_CLASS(var, className) \ 1054 var = env->FindClass(className); \ 1055 LOG_FATAL_IF(! var, "Unable to find class %s", className); 1056 1057 #define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ 1058 var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ 1059 LOG_FATAL_IF(! var, "Unable to find method" methodName); 1060 1061 int register_android_app_NativeActivity(JNIEnv* env) 1062 { 1063 //LOGD("register_android_app_NativeActivity"); 1064 jclass clazz; 1065 FIND_CLASS(clazz, kNativeActivityPathName); 1066 1067 GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent, 1068 clazz, 1069 "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)Z"); 1070 GET_METHOD_ID(gNativeActivityClassInfo.preDispatchKeyEvent, 1071 clazz, 1072 "preDispatchKeyEvent", "(Landroid/view/KeyEvent;I)V"); 1073 1074 GET_METHOD_ID(gNativeActivityClassInfo.finish, 1075 clazz, 1076 "finish", "()V"); 1077 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags, 1078 clazz, 1079 "setWindowFlags", "(II)V"); 1080 GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat, 1081 clazz, 1082 "setWindowFormat", "(I)V"); 1083 GET_METHOD_ID(gNativeActivityClassInfo.showIme, 1084 clazz, 1085 "showIme", "(I)V"); 1086 GET_METHOD_ID(gNativeActivityClassInfo.hideIme, 1087 clazz, 1088 "hideIme", "(I)V"); 1089 1090 return AndroidRuntime::registerNativeMethods( 1091 env, kNativeActivityPathName, 1092 g_methods, NELEM(g_methods)); 1093 } 1094 1095 } // namespace android 1096