android.c (6045B)
1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build android 6 7 #include <android/log.h> 8 #include <dlfcn.h> 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <stdint.h> 12 #include <string.h> 13 #include "_cgo_export.h" 14 15 #define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, "Go", __VA_ARGS__) 16 #define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "Go", __VA_ARGS__) 17 18 static jclass current_class; 19 20 static jclass find_class(JNIEnv *env, const char *class_name) { 21 jclass clazz = (*env)->FindClass(env, class_name); 22 if (clazz == NULL) { 23 (*env)->ExceptionClear(env); 24 LOG_FATAL("cannot find %s", class_name); 25 return NULL; 26 } 27 return clazz; 28 } 29 30 static jmethodID find_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) { 31 jmethodID m = (*env)->GetMethodID(env, clazz, name, sig); 32 if (m == 0) { 33 (*env)->ExceptionClear(env); 34 LOG_FATAL("cannot find method %s %s", name, sig); 35 return 0; 36 } 37 return m; 38 } 39 40 static jmethodID find_static_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) { 41 jmethodID m = (*env)->GetStaticMethodID(env, clazz, name, sig); 42 if (m == 0) { 43 (*env)->ExceptionClear(env); 44 LOG_FATAL("cannot find method %s %s", name, sig); 45 return 0; 46 } 47 return m; 48 } 49 50 static jmethodID key_rune_method; 51 52 jint JNI_OnLoad(JavaVM* vm, void* reserved) { 53 JNIEnv* env; 54 if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) { 55 return -1; 56 } 57 58 return JNI_VERSION_1_6; 59 } 60 61 static int main_running = 0; 62 63 // Entry point from our subclassed NativeActivity. 64 // 65 // By here, the Go runtime has been initialized (as we are running in 66 // -buildmode=c-shared) but the first time it is called, Go's main.main 67 // hasn't been called yet. 68 // 69 // The Activity may be created and destroyed multiple times throughout 70 // the life of a single process. Each time, onCreate is called. 71 void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_t savedStateSize) { 72 if (!main_running) { 73 JNIEnv* env = activity->env; 74 75 // Note that activity->clazz is mis-named. 76 current_class = (*env)->GetObjectClass(env, activity->clazz); 77 current_class = (*env)->NewGlobalRef(env, current_class); 78 key_rune_method = find_static_method(env, current_class, "getRune", "(III)I"); 79 80 setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz)); 81 82 // Set TMPDIR. 83 jmethodID gettmpdir = find_method(env, current_class, "getTmpdir", "()Ljava/lang/String;"); 84 jstring jpath = (jstring)(*env)->CallObjectMethod(env, activity->clazz, gettmpdir, NULL); 85 const char* tmpdir = (*env)->GetStringUTFChars(env, jpath, NULL); 86 if (setenv("TMPDIR", tmpdir, 1) != 0) { 87 LOG_INFO("setenv(\"TMPDIR\", \"%s\", 1) failed: %d", tmpdir, errno); 88 } 89 (*env)->ReleaseStringUTFChars(env, jpath, tmpdir); 90 91 // Call the Go main.main. 92 uintptr_t mainPC = (uintptr_t)dlsym(RTLD_DEFAULT, "main.main"); 93 if (!mainPC) { 94 LOG_FATAL("missing main.main"); 95 } 96 callMain(mainPC); 97 main_running = 1; 98 } 99 100 // These functions match the methods on Activity, described at 101 // http://developer.android.com/reference/android/app/Activity.html 102 // 103 // Note that onNativeWindowResized is not called on resize. Avoid it. 104 // https://code.google.com/p/android/issues/detail?id=180645 105 activity->callbacks->onStart = onStart; 106 activity->callbacks->onResume = onResume; 107 activity->callbacks->onSaveInstanceState = onSaveInstanceState; 108 activity->callbacks->onPause = onPause; 109 activity->callbacks->onStop = onStop; 110 activity->callbacks->onDestroy = onDestroy; 111 activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; 112 activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; 113 activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded; 114 activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; 115 activity->callbacks->onInputQueueCreated = onInputQueueCreated; 116 activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; 117 activity->callbacks->onConfigurationChanged = onConfigurationChanged; 118 activity->callbacks->onLowMemory = onLowMemory; 119 120 onCreate(activity); 121 } 122 123 // TODO(crawshaw): Test configuration on more devices. 124 static const EGLint RGB_888[] = { 125 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 126 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 127 EGL_BLUE_SIZE, 8, 128 EGL_GREEN_SIZE, 8, 129 EGL_RED_SIZE, 8, 130 EGL_DEPTH_SIZE, 16, 131 EGL_CONFIG_CAVEAT, EGL_NONE, 132 EGL_NONE 133 }; 134 135 EGLDisplay display = NULL; 136 EGLSurface surface = NULL; 137 138 static char* initEGLDisplay() { 139 display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 140 if (!eglInitialize(display, 0, 0)) { 141 return "EGL initialize failed"; 142 } 143 return NULL; 144 } 145 146 char* createEGLSurface(ANativeWindow* window) { 147 char* err; 148 EGLint numConfigs, format; 149 EGLConfig config; 150 EGLContext context; 151 152 if (display == 0) { 153 if ((err = initEGLDisplay()) != NULL) { 154 return err; 155 } 156 } 157 158 if (!eglChooseConfig(display, RGB_888, &config, 1, &numConfigs)) { 159 return "EGL choose RGB_888 config failed"; 160 } 161 if (numConfigs <= 0) { 162 return "EGL no config found"; 163 } 164 165 eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); 166 if (ANativeWindow_setBuffersGeometry(window, 0, 0, format) != 0) { 167 return "EGL set buffers geometry failed"; 168 } 169 170 surface = eglCreateWindowSurface(display, config, window, NULL); 171 if (surface == EGL_NO_SURFACE) { 172 return "EGL create surface failed"; 173 } 174 175 const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 176 context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); 177 178 if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { 179 return "eglMakeCurrent failed"; 180 } 181 return NULL; 182 } 183 184 char* destroyEGLSurface() { 185 if (!eglDestroySurface(display, surface)) { 186 return "EGL destroy surface failed"; 187 } 188 return NULL; 189 } 190 191 int32_t getKeyRune(JNIEnv* env, AInputEvent* e) { 192 return (int32_t)(*env)->CallStaticIntMethod( 193 env, 194 current_class, 195 key_rune_method, 196 AInputEvent_getDeviceId(e), 197 AKeyEvent_getKeyCode(e), 198 AKeyEvent_getMetaState(e) 199 ); 200 }