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