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