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