임시작업공간
- 작성자
- 고친과정
2011년 0월 00일 : 처음씀
1.1. Android 개발
- Android SDK update (Command Line)
# cd <SDK-directory> # 반드시 해당 SDK디렉토리에서 실행해주어야 정상적인 SDK update가 수행됨. # ./tools/android update sdk --no-ui
- Android NDK 에서의 graphics 구현 선택
- OpenGL ES 를 사용한 접근이 가장 기본 근간임.
- AndroidBitmap_getInfo 를 통한 JNI graphics 를 통한 접근으로 하는 방법
- FrameBuffer를 직접 접근하여 그리는 방법 (최근 안드로이드에서는 권한이 허용되지 않아서 사용할 수 없음)
- Android에서 Frame Buffer 는 2개(또는 그 이상)의 화면을 담을만한 메모리 맵핑을 하고 좌측 상단에 해당하는 메모리 주소를 변경하는 방식으로 화면을 절체하도록 구현함
- NDK에서의 Startup entry
- NDK로 만든 Android App의 실행파일은 shared library (shared object) 형태에서 시작하며 최신 안드로이드 버젼의 경우 의존관계에 있는 library 들이 모두 탑재되어 실행이 되기는 하지만 이전 버젼에서는 그렇지 않기 때문에 호환을 위해서 NDK main에 해당하는 부분은 의존관계를 최소한으로 하는 형태로 만들고 여기서 dlopen을 통해서 실제 main역할을 하는 library를 호출하도록 하는 bootstrap형태가 고려해볼만함. (아니면 그냥 하나의 library로 모든 소스를 합치는 방법도 괜찮음)
- 가장 기본적인 구조로부터의 시작은 "ANativeActivity_onCreate" 함수로부터 시작됨.
#include <android/native_activity.h> #if defined(__cplusplus) extern "C" { #endif void ANativeActivity_onCreate(ANativeActivity *s_native_activity, void *s_saved_state, size_t s_saved_state_size); #if defined(__cplusplus) } #endif void ANativeActivity_onCreate(ANativeActivity *s_native_activity, void *s_saved_state, size_t s_saved_state_size) { /* ... */ }
- "native_app_glue" 모듈을 사용하여 "android_main"함수에서 시작하도록 할 수 있음. (좀더 유연한 구현을 위한 참고가 되므로 "<NDK-directory>/sources/androis/native_app_glue/" 디렉토리의 소스와 헤더는 한번쯤 보는게 좋음)
# include <EGL/egl.h> # include <GLES/gl.h> # include <android/native_activity.h> # include <android/log.h> # include <android/looper.h> # include <android/sensor.h> # include <android/configuration.h> # include <android_native_app_glue.h> struct saved_state { /* ... */ }; struct engine { struct android_app* app; ASensorManager* sensorManager; const ASensor* accelerometerSensor; ASensorEventQueue* sensorEventQueue; /* .... */ }; #if defined(__cplusplus) extern "C" { #endif void android_main(struct android_app *s_app); #if defined(__cplusplus) } #endif void android_main(struct android_app *s_app) { struct engine s_engine; app_dummy(); /* static library를 현재의 shared object 에 link 시에 링크가 생략될 수 있기 때문에 이를 방지하는 차원에서 그냥 호출 */ (void)memset((void *)(&s_engine), 0, sizeof(s_engine)); s_app->userData = &s_engine; s_app->onAppCmd = <handler>; s_app->onInputEvent = <handler>; /* ... */ s_engine.app = s_app; /* ... */ for(;;) { int s_ident; int s_events; struct android_poll_source *s_source; for(;;) { s_ident = ALooper_pollAll(0 /* 0 or (-1) */, NULL, &s_events, (void *)(&s_source)); if(s_ident < 0) { break; } if(s_ident == LOOPER_ID_USER) { /* ... */ } if(s_app->destroyRequested != 0) { return; } } } }
- NDK Package 구성에 맞는 "AndroidManifest.xml" 파일의 작성
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.minzkn.pgl.hwport" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="9" /> <!-- Tell the system this app requires OpenGL ES 1.0. --> <uses-feature android:glEsVersion="0x00010000" android:required="true" /> <application android:label="@string/app_name" android:hasCode="false"> <activity android:name="android.app.NativeActivity" android:label="@string/app_name"> <meta-data android:name="android.app.lib_name" android:value="hwport_activity" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
- source build를 위한 Android.mk(반드시 파일명이 이것일 필요는 없음) 파일 작성 및 ndk-build를 이용한 빌드
LOCAL_PATH:=$(call my-dir) # ---- def_hwport_cflags:=-Wall# def_hwport_cflags+=-W# def_hwport_cflags+=-Wshadow# def_hwport_cflags+=-Wcast-qual# def_hwport_cflags+=-Wcast-align# def_hwport_cflags+=-Wpointer-arith# def_hwport_cflags+=-Wbad-function-cast# def_hwport_cflags+=-Wstrict-prototypes# def_hwport_cflags+=-Wmissing-prototypes# def_hwport_cflags+=-Wmissing-declarations# def_hwport_cflags+=-Wnested-externs# def_hwport_cflags+=-Winline# def_hwport_cflags+=-Wwrite-strings# def_hwport_cflags+=-Wchar-subscripts# def_hwport_cflags+=-Wformat# def_hwport_cflags+=-Wformat-security# def_hwport_cflags+=-Wimplicit# def_hwport_cflags+=-Wmain# def_hwport_cflags+=-Wmissing-braces# def_hwport_cflags+=-Wnested-externs# def_hwport_cflags+=-Wparentheses# def_hwport_cflags+=-Wredundant-decls# def_hwport_cflags+=-Wreturn-type# def_hwport_cflags+=-Wsequence-point# def_hwport_cflags+=-Wsign-compare# def_hwport_cflags+=-Wswitch# def_hwport_cflags+=-Wuninitialized# def_hwport_cflags+=-Wunknown-pragmas# def_hwport_cflags+=-Wcomment# def_hwport_cflags+=-Wundef# def_hwport_cflags+=-Wunused# def_hwport_cflags+=-Wstrict-aliasing# #def_hwport_cflags+=-Wunreachable-code# def_hwport_cflags+=-Wconversion# #def_hwport_cflags+=-Wpadded# def_hwport_cflags+=-D_REENTRANT# Thread-Safe 를 위한 def_hwport_cflags+=-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_LFS64_LARGEFILE=1# 대용량 파일을 다루기 위한 def_hwport_cflags+=-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0# libc 호환성을 높이기 위한... def_hwport_c_includes:=$(LOCAL_PATH)/include# def_hwport_ldlibs:=-ldl -llog -landroid# 대부분 이정도 링크는 해줘야 함. def_hwport_ldlibs+=-lEGL -lGLESv3# OpenGL ES library link #def_hwport_ldlibs+=-ljnigraphics# JNI graphics 방식을 사용하는 경우 필요 # ---- include $(CLEAR_VARS) LOCAL_MODULE:=gbox_shared# LOCAL_CFLAGS:=$(def_hwport_cflags)# LOCAL_C_INCLUDES:=$(def_hwport_c_includes)# LOCAL_SRC_FILES:=$(abspath $(wildcard $(LOCAL_PATH)/source.gbox/main.c))# LOCAL_LDLIBS:=$(def_hwport_ldlibs)# LOCAL_SHARED_LIBRARIES:=gbox hwport_pgl# include $(BUILD_EXECUTABLE) # ---- include $(CLEAR_VARS) LOCAL_MODULE:=gbox_static# LOCAL_CFLAGS:=$(def_hwport_cflags)# LOCAL_C_INCLUDES:=$(def_hwport_c_includes)# LOCAL_SRC_FILES:=$(abspath $(wildcard $(LOCAL_PATH)/source/*.c $(LOCAL_PATH)/source.gbox/*.c))# LOCAL_LDLIBS:=$(def_hwport_ldlibs)# include $(BUILD_EXECUTABLE) # ---- include $(CLEAR_VARS) LOCAL_MODULE:=gbox_activity# LOCAL_CFLAGS:=-Ddef_hwport_android_native_activity_module_name='"gbox"' $(def_hwport_cflags)# LOCAL_C_INCLUDES:=$(def_hwport_c_includes)# LOCAL_SRC_FILES:=$(abspath $(wildcard $(LOCAL_PATH)/source.gbox/main.c))# LOCAL_LDLIBS:=$(def_hwport_ldlibs)# include $(BUILD_SHARED_LIBRARY) # ---- include $(CLEAR_VARS) LOCAL_MODULE:=gbox# LOCAL_CFLAGS:=-Ddef_hwport_android_native_activity_main=1 $(def_hwport_cflags)# LOCAL_C_INCLUDES+=$(def_hwport_c_includes)# LOCAL_SRC_FILES:=$(abspath $(filter-out $(LOCAL_PATH)/source.gbox/main.c,$(wildcard $(LOCAL_PATH)/source.gbox/*.c)))# LOCAL_LDLIBS:=$(def_hwport_ldlibs)# LOCAL_SHARED_LIBRARIES:=hwport_pgl# LOCAL_STATIC_LIBRARIES:=android_native_app_glue# include $(BUILD_SHARED_LIBRARY) # ---- include $(CLEAR_VARS) LOCAL_MODULE:=hwport_pgl# LOCAL_CFLAGS:=$(def_hwport_cflags)# LOCAL_C_INCLUDES:=$(def_hwport_c_includes)# LOCAL_SRC_FILES:=$(abspath $(wildcard $(LOCAL_PATH)/source/*.c))# LOCAL_LDLIBS:=$(def_hwport_ldlibs)# include $(BUILD_SHARED_LIBRARY) # ---- $(call import-module,android/native_app_glue) # ---- # End of Android.mk
- Signature 값 없는 방법(출처: http://dev.re.kr/72)
// Context 를 인자값을 받아서 Signature 의 값을 얻는다. char* getSignaiture(JNIEnv *env, jobject context) { jstring packageName; jobject packageManagerObj; jobject packageInfoObj; jclass contextClass = env->GetObjectClass( context); jmethodID getPackageNameMid = env->GetMethodID( contextClass, "getPackageName", "()Ljava/lang/String;"); jmethodID getPackageManager = env->GetMethodID( contextClass, "getPackageManager", "()Landroid/content/pm/PackageManager;"); jclass packageManagerClass = env->FindClass("android/content/pm/PackageManager"); jmethodID getPackageInfo = env->GetMethodID( packageManagerClass, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); jclass packageInfoClass = env->FindClass("android/content/pm/PackageInfo"); jfieldID signaturesFid = env->GetFieldID( packageInfoClass, "signatures", "[Landroid/content/pm/Signature;"); jclass signatureClass = env->FindClass("android/content/pm/Signature"); jmethodID signatureToByteArrayMid = env->GetMethodID( signatureClass, "toByteArray", "()[B"); jclass messageDigestClass = env->FindClass("java/security/MessageDigest"); jmethodID messageDigestUpdateMid = env->GetMethodID( messageDigestClass, "update", "([B)V"); jmethodID getMessageDigestInstanceMid = env->GetStaticMethodID( messageDigestClass, "getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;"); jmethodID digestMid = env->GetMethodID( messageDigestClass,"digest", "()[B"); jclass base64Class = env->FindClass("android/util/Base64"); jmethodID encodeToStringMid = env->GetStaticMethodID( base64Class,"encodeToString", "([BI)Ljava/lang/String;"); packageName = (jstring)env->CallObjectMethod( context, getPackageNameMid); packageManagerObj = env->CallObjectMethod(context, getPackageManager); // PackageManager.GET_SIGNATURES = 0x40 packageInfoObj = env->CallObjectMethod( packageManagerObj,getPackageInfo, packageName, 0x40); jobjectArray signatures = (jobjectArray)env->GetObjectField( packageInfoObj, signaturesFid); //int signatureLength = env->GetArrayLength(signatures); jobject signatureObj = env->GetObjectArrayElement(signatures, 0); jobject messageDigestObj = env->CallStaticObjectMethod(messageDigestClass, getMessageDigestInstanceMid, env->NewStringUTF("SHA1")); env->CallVoidMethod(messageDigestObj, messageDigestUpdateMid, env->CallObjectMethod( signatureObj,signatureToByteArrayMid)); // Base64.DEFAULT = 0 그렇기 때문에 맨 마지막 인자값은 0이다. jstring signatureHash = (jstring)env->CallStaticObjectMethod( base64Class, encodeToStringMid,env->CallObjectMethod( messageDigestObj, digestMid, signatureObj), 0); return (char*)env->GetStringUTFChars(signatureHash,0); }
1.2. Xlib를 이용한 root 하위 window의 alpha처리 방법 #1
/* Copyright (C) JAEHYUK CHO All rights reserved. Code by JaeHyuk Cho <mailto:minzkn@minzkn.com> */ Atom s_atom; hwport_uint32_t s_value[4]; s_value[0] = (hwport_uint32_t)0xa0000000u; /* 0x00000000u ~ 0xffffffffu */ s_atom = XInternAtom(s_xlib_demo->m_display, "_NET_WM_WINDOW_OPACITY", False); (void)XChangeProperty( s_xlib_demo->m_display, s_xlib_demo->m_window[hwport_xlib_demo_background_window], s_atom, XA_CARDINAL, (int)(sizeof(s_value[0]) << 3), PropModeReplace, (const unsigned char *)(&s_value[0]), 1); XSync(s_xlib_demo->m_display, False);