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 <memory>
25 
26 #include <android_runtime/android_app_NativeActivity.h>
27 #include <android_runtime/android_util_AssetManager.h>
28 #include <android_runtime/android_view_Surface.h>
29 #include <android_runtime/AndroidRuntime.h>
30 #include <input/InputTransport.h>
31 
32 #include <gui/Surface.h>
33 
34 #include <system/window.h>
35 
36 #include <utils/Looper.h>
37 
38 #include <nativehelper/JNIHelp.h>
39 #include "android_os_MessageQueue.h"
40 #include "android_view_InputChannel.h"
41 #include "android_view_KeyEvent.h"
42 
43 #include "android-base/stringprintf.h"
44 #include "nativebridge/native_bridge.h"
45 #include "nativeloader/native_loader.h"
46 
47 #include "core_jni_helpers.h"
48 
49 #include <nativehelper/ScopedUtfChars.h>
50 
51 #define LOG_TRACE(...)
52 //#define LOG_TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
53 
54 namespace android
55 {
56 
57 static const bool kLogTrace = false;
58 
59 static struct {
60     jmethodID finish;
61     jmethodID setWindowFlags;
62     jmethodID setWindowFormat;
63     jmethodID showIme;
64     jmethodID hideIme;
65 } gNativeActivityClassInfo;
66 
67 // ------------------------------------------------------------------------
68 
69 struct ActivityWork {
70     int32_t cmd;
71     int32_t arg1;
72     int32_t arg2;
73 };
74 
75 enum {
76     CMD_FINISH = 1,
77     CMD_SET_WINDOW_FORMAT,
78     CMD_SET_WINDOW_FLAGS,
79     CMD_SHOW_SOFT_INPUT,
80     CMD_HIDE_SOFT_INPUT,
81 };
82 
write_work(int fd,int32_t cmd,int32_t arg1=0,int32_t arg2=0)83 static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) {
84     ActivityWork work;
85     work.cmd = cmd;
86     work.arg1 = arg1;
87     work.arg2 = arg2;
88 
89     if (kLogTrace) {
90         ALOGD("write_work: cmd=%d", cmd);
91     }
92 
93 restart:
94     int res = write(fd, &work, sizeof(work));
95     if (res < 0 && errno == EINTR) {
96         goto restart;
97     }
98 
99     if (res == sizeof(work)) return;
100 
101     if (res < 0) ALOGW("Failed writing to work fd: %s", strerror(errno));
102     else ALOGW("Truncated writing to work fd: %d", res);
103 }
104 
read_work(int fd,ActivityWork * outWork)105 static bool read_work(int fd, ActivityWork* outWork) {
106     int res = read(fd, outWork, sizeof(ActivityWork));
107     // no need to worry about EINTR, poll loop will just come back again.
108     if (res == sizeof(ActivityWork)) return true;
109 
110     if (res < 0) ALOGW("Failed reading work fd: %s", strerror(errno));
111     else ALOGW("Truncated reading work fd: %d", res);
112     return false;
113 }
114 
115 /*
116  * Native state for interacting with the NativeActivity class.
117  */
118 struct NativeCode : public ANativeActivity {
NativeCodeandroid::NativeCode119     NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
120         memset((ANativeActivity*)this, 0, sizeof(ANativeActivity));
121         memset(&callbacks, 0, sizeof(callbacks));
122         dlhandle = _dlhandle;
123         createActivityFunc = _createFunc;
124         nativeWindow = NULL;
125         mainWorkRead = mainWorkWrite = -1;
126     }
127 
~NativeCodeandroid::NativeCode128     ~NativeCode() {
129         if (callbacks.onDestroy != NULL) {
130             callbacks.onDestroy(this);
131         }
132         if (env != NULL) {
133           if (clazz != NULL) {
134             env->DeleteGlobalRef(clazz);
135           }
136           if (javaAssetManager != NULL) {
137             env->DeleteGlobalRef(javaAssetManager);
138           }
139         }
140         if (messageQueue != NULL && mainWorkRead >= 0) {
141             messageQueue->getLooper()->removeFd(mainWorkRead);
142         }
143         setSurface(NULL);
144         if (mainWorkRead >= 0) close(mainWorkRead);
145         if (mainWorkWrite >= 0) close(mainWorkWrite);
146         if (dlhandle != NULL) {
147             // for now don't unload...  we probably should clean this
148             // up and only keep one open dlhandle per proc, since there
149             // is really no benefit to unloading the code.
150             //dlclose(dlhandle);
151         }
152     }
153 
setSurfaceandroid::NativeCode154     void setSurface(jobject _surface) {
155         if (_surface != NULL) {
156             nativeWindow = android_view_Surface_getNativeWindow(env, _surface);
157         } else {
158             nativeWindow = NULL;
159         }
160     }
161 
162     ANativeActivityCallbacks callbacks;
163 
164     void* dlhandle;
165     ANativeActivity_createFunc* createActivityFunc;
166 
167     String8 internalDataPathObj;
168     String8 externalDataPathObj;
169     String8 obbPathObj;
170 
171     sp<ANativeWindow> nativeWindow;
172     int32_t lastWindowWidth;
173     int32_t lastWindowHeight;
174 
175     // These are used to wake up the main thread to process work.
176     int mainWorkRead;
177     int mainWorkWrite;
178     sp<MessageQueue> messageQueue;
179 
180     // Need to hold on to a reference here in case the upper layers destroy our
181     // AssetManager.
182     jobject javaAssetManager;
183 };
184 
android_NativeActivity_finish(ANativeActivity * activity)185 void android_NativeActivity_finish(ANativeActivity* activity) {
186     NativeCode* code = static_cast<NativeCode*>(activity);
187     write_work(code->mainWorkWrite, CMD_FINISH, 0);
188 }
189 
android_NativeActivity_setWindowFormat(ANativeActivity * activity,int32_t format)190 void android_NativeActivity_setWindowFormat(
191         ANativeActivity* activity, int32_t format) {
192     NativeCode* code = static_cast<NativeCode*>(activity);
193     write_work(code->mainWorkWrite, CMD_SET_WINDOW_FORMAT, format);
194 }
195 
android_NativeActivity_setWindowFlags(ANativeActivity * activity,int32_t values,int32_t mask)196 void android_NativeActivity_setWindowFlags(
197         ANativeActivity* activity, int32_t values, int32_t mask) {
198     NativeCode* code = static_cast<NativeCode*>(activity);
199     write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask);
200 }
201 
android_NativeActivity_showSoftInput(ANativeActivity * activity,int32_t flags)202 void android_NativeActivity_showSoftInput(
203         ANativeActivity* activity, int32_t flags) {
204     NativeCode* code = static_cast<NativeCode*>(activity);
205     write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags);
206 }
207 
android_NativeActivity_hideSoftInput(ANativeActivity * activity,int32_t flags)208 void android_NativeActivity_hideSoftInput(
209         ANativeActivity* activity, int32_t flags) {
210     NativeCode* code = static_cast<NativeCode*>(activity);
211     write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags);
212 }
213 
214 // ------------------------------------------------------------------------
215 
216 /*
217  * Callback for handling native events on the application's main thread.
218  */
mainWorkCallback(int fd,int events,void * data)219 static int mainWorkCallback(int fd, int events, void* data) {
220     NativeCode* code = (NativeCode*)data;
221     if ((events & POLLIN) == 0) {
222         return 1;
223     }
224 
225     ActivityWork work;
226     if (!read_work(code->mainWorkRead, &work)) {
227         return 1;
228     }
229 
230     if (kLogTrace) {
231         ALOGD("mainWorkCallback: cmd=%d", work.cmd);
232     }
233 
234     switch (work.cmd) {
235         case CMD_FINISH: {
236             code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.finish);
237             code->messageQueue->raiseAndClearException(code->env, "finish");
238         } break;
239         case CMD_SET_WINDOW_FORMAT: {
240             code->env->CallVoidMethod(code->clazz,
241                     gNativeActivityClassInfo.setWindowFormat, work.arg1);
242             code->messageQueue->raiseAndClearException(code->env, "setWindowFormat");
243         } break;
244         case CMD_SET_WINDOW_FLAGS: {
245             code->env->CallVoidMethod(code->clazz,
246                     gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
247             code->messageQueue->raiseAndClearException(code->env, "setWindowFlags");
248         } break;
249         case CMD_SHOW_SOFT_INPUT: {
250             code->env->CallVoidMethod(code->clazz,
251                     gNativeActivityClassInfo.showIme, work.arg1);
252             code->messageQueue->raiseAndClearException(code->env, "showIme");
253         } break;
254         case CMD_HIDE_SOFT_INPUT: {
255             code->env->CallVoidMethod(code->clazz,
256                     gNativeActivityClassInfo.hideIme, work.arg1);
257             code->messageQueue->raiseAndClearException(code->env, "hideIme");
258         } break;
259         default:
260             ALOGW("Unknown work command: %d", work.cmd);
261             break;
262     }
263 
264     return 1;
265 }
266 
267 // ------------------------------------------------------------------------
268 
269 static thread_local std::string g_error_msg;
270 
271 static jlong
loadNativeCode_native(JNIEnv * env,jobject clazz,jstring path,jstring funcName,jobject messageQueue,jstring internalDataDir,jstring obbDir,jstring externalDataDir,jint sdkVersion,jobject jAssetMgr,jbyteArray savedState,jobject classLoader,jstring libraryPath)272 loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
273         jobject messageQueue, jstring internalDataDir, jstring obbDir,
274         jstring externalDataDir, jint sdkVersion, jobject jAssetMgr,
275         jbyteArray savedState, jobject classLoader, jstring libraryPath) {
276     if (kLogTrace) {
277         ALOGD("loadNativeCode_native");
278     }
279 
280     ScopedUtfChars pathStr(env, path);
281     std::unique_ptr<NativeCode> code;
282     bool needs_native_bridge = false;
283 
284     char* nativeloader_error_msg = nullptr;
285     void* handle = OpenNativeLibrary(env,
286                                      sdkVersion,
287                                      pathStr.c_str(),
288                                      classLoader,
289                                      nullptr,
290                                      libraryPath,
291                                      &needs_native_bridge,
292                                      &nativeloader_error_msg);
293 
294     if (handle == nullptr) {
295         g_error_msg = nativeloader_error_msg;
296         NativeLoaderFreeErrorMessage(nativeloader_error_msg);
297         ALOGW("NativeActivity LoadNativeLibrary(\"%s\") failed: %s",
298               pathStr.c_str(),
299               g_error_msg.c_str());
300         return 0;
301     }
302 
303     void* funcPtr = NULL;
304     const char* funcStr = env->GetStringUTFChars(funcName, NULL);
305     if (needs_native_bridge) {
306         funcPtr = NativeBridgeGetTrampoline(handle, funcStr, NULL, 0);
307     } else {
308         funcPtr = dlsym(handle, funcStr);
309     }
310 
311     code.reset(new NativeCode(handle, (ANativeActivity_createFunc*)funcPtr));
312     env->ReleaseStringUTFChars(funcName, funcStr);
313 
314     if (code->createActivityFunc == NULL) {
315         g_error_msg = needs_native_bridge ? NativeBridgeGetError() : dlerror();
316         ALOGW("ANativeActivity_onCreate not found: %s", g_error_msg.c_str());
317         return 0;
318     }
319 
320     code->messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueue);
321     if (code->messageQueue == NULL) {
322         g_error_msg = "Unable to retrieve native MessageQueue";
323         ALOGW("%s", g_error_msg.c_str());
324         return 0;
325     }
326 
327     int msgpipe[2];
328     if (pipe(msgpipe)) {
329         g_error_msg = android::base::StringPrintf("could not create pipe: %s", strerror(errno));
330         ALOGW("%s", g_error_msg.c_str());
331         return 0;
332     }
333     code->mainWorkRead = msgpipe[0];
334     code->mainWorkWrite = msgpipe[1];
335     int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK);
336     SLOGW_IF(result != 0, "Could not make main work read pipe "
337             "non-blocking: %s", strerror(errno));
338     result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
339     SLOGW_IF(result != 0, "Could not make main work write pipe "
340             "non-blocking: %s", strerror(errno));
341     code->messageQueue->getLooper()->addFd(
342             code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code.get());
343 
344     code->ANativeActivity::callbacks = &code->callbacks;
345     if (env->GetJavaVM(&code->vm) < 0) {
346         g_error_msg = "NativeActivity GetJavaVM failed";
347         ALOGW("%s", g_error_msg.c_str());
348         return 0;
349     }
350     code->env = env;
351     code->clazz = env->NewGlobalRef(clazz);
352 
353     const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
354     code->internalDataPathObj = dirStr;
355     code->internalDataPath = code->internalDataPathObj.string();
356     env->ReleaseStringUTFChars(internalDataDir, dirStr);
357 
358     if (externalDataDir != NULL) {
359         dirStr = env->GetStringUTFChars(externalDataDir, NULL);
360         code->externalDataPathObj = dirStr;
361         env->ReleaseStringUTFChars(externalDataDir, dirStr);
362     }
363     code->externalDataPath = code->externalDataPathObj.string();
364 
365     code->sdkVersion = sdkVersion;
366 
367     code->javaAssetManager = env->NewGlobalRef(jAssetMgr);
368     code->assetManager = NdkAssetManagerForJavaObject(env, jAssetMgr);
369 
370     if (obbDir != NULL) {
371         dirStr = env->GetStringUTFChars(obbDir, NULL);
372         code->obbPathObj = dirStr;
373         env->ReleaseStringUTFChars(obbDir, dirStr);
374     }
375     code->obbPath = code->obbPathObj.string();
376 
377     jbyte* rawSavedState = NULL;
378     jsize rawSavedSize = 0;
379     if (savedState != NULL) {
380         rawSavedState = env->GetByteArrayElements(savedState, NULL);
381         rawSavedSize = env->GetArrayLength(savedState);
382     }
383 
384     code->createActivityFunc(code.get(), rawSavedState, rawSavedSize);
385 
386     if (rawSavedState != NULL) {
387         env->ReleaseByteArrayElements(savedState, rawSavedState, 0);
388     }
389 
390     return (jlong)code.release();
391 }
392 
getDlError_native(JNIEnv * env,jobject clazz)393 static jstring getDlError_native(JNIEnv* env, jobject clazz) {
394   jstring result = env->NewStringUTF(g_error_msg.c_str());
395   g_error_msg.clear();
396   return result;
397 }
398 
399 static void
unloadNativeCode_native(JNIEnv * env,jobject clazz,jlong handle)400 unloadNativeCode_native(JNIEnv* env, jobject clazz, jlong handle)
401 {
402     if (kLogTrace) {
403         ALOGD("unloadNativeCode_native");
404     }
405     if (handle != 0) {
406         NativeCode* code = (NativeCode*)handle;
407         delete code;
408     }
409 }
410 
411 static void
onStart_native(JNIEnv * env,jobject clazz,jlong handle)412 onStart_native(JNIEnv* env, jobject clazz, jlong handle)
413 {
414     if (kLogTrace) {
415         ALOGD("onStart_native");
416     }
417     if (handle != 0) {
418         NativeCode* code = (NativeCode*)handle;
419         if (code->callbacks.onStart != NULL) {
420             code->callbacks.onStart(code);
421         }
422     }
423 }
424 
425 static void
onResume_native(JNIEnv * env,jobject clazz,jlong handle)426 onResume_native(JNIEnv* env, jobject clazz, jlong handle)
427 {
428     if (kLogTrace) {
429         ALOGD("onResume_native");
430     }
431     if (handle != 0) {
432         NativeCode* code = (NativeCode*)handle;
433         if (code->callbacks.onResume != NULL) {
434             code->callbacks.onResume(code);
435         }
436     }
437 }
438 
439 static jbyteArray
onSaveInstanceState_native(JNIEnv * env,jobject clazz,jlong handle)440 onSaveInstanceState_native(JNIEnv* env, jobject clazz, jlong handle)
441 {
442     if (kLogTrace) {
443         ALOGD("onSaveInstanceState_native");
444     }
445 
446     jbyteArray array = NULL;
447 
448     if (handle != 0) {
449         NativeCode* code = (NativeCode*)handle;
450         if (code->callbacks.onSaveInstanceState != NULL) {
451             size_t len = 0;
452             jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len);
453             if (len > 0) {
454                 array = env->NewByteArray(len);
455                 if (array != NULL) {
456                     env->SetByteArrayRegion(array, 0, len, state);
457                 }
458             }
459             if (state != NULL) {
460                 free(state);
461             }
462         }
463     }
464 
465     return array;
466 }
467 
468 static void
onPause_native(JNIEnv * env,jobject clazz,jlong handle)469 onPause_native(JNIEnv* env, jobject clazz, jlong handle)
470 {
471     if (kLogTrace) {
472         ALOGD("onPause_native");
473     }
474     if (handle != 0) {
475         NativeCode* code = (NativeCode*)handle;
476         if (code->callbacks.onPause != NULL) {
477             code->callbacks.onPause(code);
478         }
479     }
480 }
481 
482 static void
onStop_native(JNIEnv * env,jobject clazz,jlong handle)483 onStop_native(JNIEnv* env, jobject clazz, jlong handle)
484 {
485     if (kLogTrace) {
486         ALOGD("onStop_native");
487     }
488     if (handle != 0) {
489         NativeCode* code = (NativeCode*)handle;
490         if (code->callbacks.onStop != NULL) {
491             code->callbacks.onStop(code);
492         }
493     }
494 }
495 
496 static void
onConfigurationChanged_native(JNIEnv * env,jobject clazz,jlong handle)497 onConfigurationChanged_native(JNIEnv* env, jobject clazz, jlong handle)
498 {
499     if (kLogTrace) {
500         ALOGD("onConfigurationChanged_native");
501     }
502     if (handle != 0) {
503         NativeCode* code = (NativeCode*)handle;
504         if (code->callbacks.onConfigurationChanged != NULL) {
505             code->callbacks.onConfigurationChanged(code);
506         }
507     }
508 }
509 
510 static void
onLowMemory_native(JNIEnv * env,jobject clazz,jlong handle)511 onLowMemory_native(JNIEnv* env, jobject clazz, jlong handle)
512 {
513     if (kLogTrace) {
514         ALOGD("onLowMemory_native");
515     }
516     if (handle != 0) {
517         NativeCode* code = (NativeCode*)handle;
518         if (code->callbacks.onLowMemory != NULL) {
519             code->callbacks.onLowMemory(code);
520         }
521     }
522 }
523 
524 static void
onWindowFocusChanged_native(JNIEnv * env,jobject clazz,jlong handle,jboolean focused)525 onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jlong handle, jboolean focused)
526 {
527     if (kLogTrace) {
528         ALOGD("onWindowFocusChanged_native");
529     }
530     if (handle != 0) {
531         NativeCode* code = (NativeCode*)handle;
532         if (code->callbacks.onWindowFocusChanged != NULL) {
533             code->callbacks.onWindowFocusChanged(code, focused ? 1 : 0);
534         }
535     }
536 }
537 
538 static void
onSurfaceCreated_native(JNIEnv * env,jobject clazz,jlong handle,jobject surface)539 onSurfaceCreated_native(JNIEnv* env, jobject clazz, jlong handle, jobject surface)
540 {
541     if (kLogTrace) {
542         ALOGD("onSurfaceCreated_native");
543     }
544     if (handle != 0) {
545         NativeCode* code = (NativeCode*)handle;
546         code->setSurface(surface);
547         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
548             code->callbacks.onNativeWindowCreated(code,
549                     code->nativeWindow.get());
550         }
551     }
552 }
553 
getWindowProp(ANativeWindow * window,int what)554 static int32_t getWindowProp(ANativeWindow* window, int what) {
555     int value;
556     int res = window->query(window, what, &value);
557     return res < 0 ? res : value;
558 }
559 
560 static void
onSurfaceChanged_native(JNIEnv * env,jobject clazz,jlong handle,jobject surface,jint format,jint width,jint height)561 onSurfaceChanged_native(JNIEnv* env, jobject clazz, jlong handle, jobject surface,
562         jint format, jint width, jint height)
563 {
564     if (kLogTrace) {
565         ALOGD("onSurfaceChanged_native");
566     }
567     if (handle != 0) {
568         NativeCode* code = (NativeCode*)handle;
569         sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
570         code->setSurface(surface);
571         if (oldNativeWindow != code->nativeWindow) {
572             if (oldNativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
573                 code->callbacks.onNativeWindowDestroyed(code,
574                         oldNativeWindow.get());
575             }
576             if (code->nativeWindow != NULL) {
577                 if (code->callbacks.onNativeWindowCreated != NULL) {
578                     code->callbacks.onNativeWindowCreated(code,
579                             code->nativeWindow.get());
580                 }
581                 code->lastWindowWidth = getWindowProp(code->nativeWindow.get(),
582                         NATIVE_WINDOW_WIDTH);
583                 code->lastWindowHeight = getWindowProp(code->nativeWindow.get(),
584                         NATIVE_WINDOW_HEIGHT);
585             }
586         } else {
587             // Maybe it resized?
588             int32_t newWidth = getWindowProp(code->nativeWindow.get(),
589                     NATIVE_WINDOW_WIDTH);
590             int32_t newHeight = getWindowProp(code->nativeWindow.get(),
591                     NATIVE_WINDOW_HEIGHT);
592             if (newWidth != code->lastWindowWidth
593                     || newHeight != code->lastWindowHeight) {
594                 if (code->callbacks.onNativeWindowResized != NULL) {
595                     code->callbacks.onNativeWindowResized(code,
596                             code->nativeWindow.get());
597                 }
598             }
599         }
600     }
601 }
602 
603 static void
onSurfaceRedrawNeeded_native(JNIEnv * env,jobject clazz,jlong handle)604 onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jlong handle)
605 {
606     if (kLogTrace) {
607         ALOGD("onSurfaceRedrawNeeded_native");
608     }
609     if (handle != 0) {
610         NativeCode* code = (NativeCode*)handle;
611         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) {
612             code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get());
613         }
614     }
615 }
616 
617 static void
onSurfaceDestroyed_native(JNIEnv * env,jobject clazz,jlong handle,jobject surface)618 onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jlong handle, jobject surface)
619 {
620     if (kLogTrace) {
621         ALOGD("onSurfaceDestroyed_native");
622     }
623     if (handle != 0) {
624         NativeCode* code = (NativeCode*)handle;
625         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
626             code->callbacks.onNativeWindowDestroyed(code,
627                     code->nativeWindow.get());
628         }
629         code->setSurface(NULL);
630     }
631 }
632 
633 static void
onInputQueueCreated_native(JNIEnv * env,jobject clazz,jlong handle,jlong queuePtr)634 onInputQueueCreated_native(JNIEnv* env, jobject clazz, jlong handle, jlong queuePtr)
635 {
636     if (kLogTrace) {
637         ALOGD("onInputChannelCreated_native");
638     }
639     if (handle != 0) {
640         NativeCode* code = (NativeCode*)handle;
641         if (code->callbacks.onInputQueueCreated != NULL) {
642             AInputQueue* queue = reinterpret_cast<AInputQueue*>(queuePtr);
643             code->callbacks.onInputQueueCreated(code, queue);
644         }
645     }
646 }
647 
648 static void
onInputQueueDestroyed_native(JNIEnv * env,jobject clazz,jlong handle,jlong queuePtr)649 onInputQueueDestroyed_native(JNIEnv* env, jobject clazz, jlong handle, jlong queuePtr)
650 {
651     if (kLogTrace) {
652         ALOGD("onInputChannelDestroyed_native");
653     }
654     if (handle != 0) {
655         NativeCode* code = (NativeCode*)handle;
656         if (code->callbacks.onInputQueueDestroyed != NULL) {
657             AInputQueue* queue = reinterpret_cast<AInputQueue*>(queuePtr);
658             code->callbacks.onInputQueueDestroyed(code, queue);
659         }
660     }
661 }
662 
663 static void
onContentRectChanged_native(JNIEnv * env,jobject clazz,jlong handle,jint x,jint y,jint w,jint h)664 onContentRectChanged_native(JNIEnv* env, jobject clazz, jlong handle,
665         jint x, jint y, jint w, jint h)
666 {
667     if (kLogTrace) {
668         ALOGD("onContentRectChanged_native");
669     }
670     if (handle != 0) {
671         NativeCode* code = (NativeCode*)handle;
672         if (code->callbacks.onContentRectChanged != NULL) {
673             ARect rect;
674             rect.left = x;
675             rect.top = y;
676             rect.right = x+w;
677             rect.bottom = y+h;
678             code->callbacks.onContentRectChanged(code, &rect);
679         }
680     }
681 }
682 
683 static const JNINativeMethod g_methods[] = {
684     { "loadNativeCode",
685         "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[BLjava/lang/ClassLoader;Ljava/lang/String;)J",
686         (void*)loadNativeCode_native },
687     { "getDlError", "()Ljava/lang/String;", (void*) getDlError_native },
688     { "unloadNativeCode", "(J)V", (void*)unloadNativeCode_native },
689     { "onStartNative", "(J)V", (void*)onStart_native },
690     { "onResumeNative", "(J)V", (void*)onResume_native },
691     { "onSaveInstanceStateNative", "(J)[B", (void*)onSaveInstanceState_native },
692     { "onPauseNative", "(J)V", (void*)onPause_native },
693     { "onStopNative", "(J)V", (void*)onStop_native },
694     { "onConfigurationChangedNative", "(J)V", (void*)onConfigurationChanged_native },
695     { "onLowMemoryNative", "(J)V", (void*)onLowMemory_native },
696     { "onWindowFocusChangedNative", "(JZ)V", (void*)onWindowFocusChanged_native },
697     { "onSurfaceCreatedNative", "(JLandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
698     { "onSurfaceChangedNative", "(JLandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
699     { "onSurfaceRedrawNeededNative", "(JLandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native },
700     { "onSurfaceDestroyedNative", "(J)V", (void*)onSurfaceDestroyed_native },
701     { "onInputQueueCreatedNative", "(JJ)V",
702         (void*)onInputQueueCreated_native },
703     { "onInputQueueDestroyedNative", "(JJ)V",
704         (void*)onInputQueueDestroyed_native },
705     { "onContentRectChangedNative", "(JIIII)V", (void*)onContentRectChanged_native },
706 };
707 
708 static const char* const kNativeActivityPathName = "android/app/NativeActivity";
709 
register_android_app_NativeActivity(JNIEnv * env)710 int register_android_app_NativeActivity(JNIEnv* env)
711 {
712     //ALOGD("register_android_app_NativeActivity");
713     jclass clazz = FindClassOrDie(env, kNativeActivityPathName);
714 
715     gNativeActivityClassInfo.finish = GetMethodIDOrDie(env, clazz, "finish", "()V");
716     gNativeActivityClassInfo.setWindowFlags = GetMethodIDOrDie(env, clazz, "setWindowFlags",
717                                                                "(II)V");
718     gNativeActivityClassInfo.setWindowFormat = GetMethodIDOrDie(env, clazz, "setWindowFormat",
719                                                                 "(I)V");
720     gNativeActivityClassInfo.showIme = GetMethodIDOrDie(env, clazz, "showIme", "(I)V");
721     gNativeActivityClassInfo.hideIme = GetMethodIDOrDie(env, clazz, "hideIme", "(I)V");
722 
723     return RegisterMethodsOrDie(env, kNativeActivityPathName, g_methods, NELEM(g_methods));
724 }
725 
726 } // namespace android
727