TI OMAP의 Android 관련 페이지 모음

일단 TI의 오픈소스 git repository는 http://git.omapzoom.org/ 이다.
OMAP의 Android 관련 메인 위키 페이지는 http://omappedia.org/wiki/OMAP_Android_Main 이며, 소스를 얻는 것에 대해서는 http://omappedia.org/wiki/Android_source_code_versions 에 설명되어 있다.
또한 플랫폼 쪽의 manifest.xml 를 관리하기 위한 프로젝트는 git://git.omapzoom.org/platform/omapmanifest.git 으로 보인다.
리눅스 상에서 adb 사용에 관한 문서는 http://omappedia.org/wiki/Adb_over_USB 에서 볼 수 있고, 리눅스 및 윈도우즈 상에서의 adb 사용(Blaze 기준)은 http://omappedia.org/wiki/Support_Tools#ADB_over_USB 에서도 볼 수 있다.
툴체인은 http://omappedia.org/wiki/Android:_Configuring_the_Host_PC#ARM_Cross_Compiler 에서 볼 수 있는 것처럼 Code Sourcery의 툴체인을 권장하며 L27x 등 최신 버전은 2010-q1 이 사용되어야 한다고 쓰여져 있다.
방화벽 아래에서의 작업은 http://omappedia.org/wiki/Support_Tools#Firewalls 에서 해결 방법을 볼 수 있다. 해당 해결 방법은 GIT_PROXY_COMMAND 환경변수를 사용하는 것이 아닌 git의 core.gitproxy 설정을 통해 해결하고 있다. 또한 SSH 의 Proxy 를 .ssh/config 파일에서 설정하는 방법에 대해서도 http://omappedia.org/wiki/Gerrit#SSH_Proxy_Setup: 에 나와 있다. 둘다 corkscrew를 이용한다.

Ducati를 사용하는데 사용되는 Syslink에 대해서는 http://omappedia.org/wiki/Syslink_Project 에서 정보를 얻을 수 있고, 현재 Syslink 3(http://omappedia.org/wiki/Syslink_3)로 이행 중인 듯하다. Syslink3 는 Kernel space에서 수행되는 것들을 User space로 옮겨 Linux kernel 에 upstream이 되기 힘든 단점을 극복하려는 듯 하다.
XDCtools 는 http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/rtsc/index.html 에서 다운로드 받을 수 있고, CodeGen tool과 BIOS 등 모든 툴은 TI Account가 있어야 다운로드 받을 수 있는 듯 하다.

Ducati 에 대한 정보는 http://omappedia.org/wiki/Ducati_For_Dummies 에서 얻을 수 있는 듯 하다.

Android 개발 시 몇 가지 로그 확인 방법

1. Kernel 에서 pr_debug 등이 안나올 때,
간단히는 맨 위(“#include <linux/kernel.h>”보다 위)에 “#define DEBUG” 추가 혹은  http://www.kernel.org/doc/local/pr_debug.txt 처럼 makefile 수정
DEBUG를 추가했을 때 왜 pr_debug 가 Enable 되는지 보고 싶다면, include/linux/kernel.h 참고

커널 메시지 보기 : 커널이 어느정도 안정적이라면 UART 등을 이용하는 것보다 adb 쉘을 이용하는 것이 더 편하던데..

adb shell cat /proc/kmsg

2. Android 에서 LOGE, LOGW, LOGI, LOGD 가 안나올 때,
맨 위에 “#define LOG_NDEBUG 1” 추가
LOGV 까지 보고 싶을 땐 “#define LOG_NDEBUG 0” 추가
LOG_NDEBUG 가 미치는 영향을 보고 싶다면, system/core/include/cutils/log.h 파일 참고.

logcat 메시지 보기

adb logcat
그러나 로그 메시지 보기에는 역시 DDMS 가 가장 좋다.
로그 TAG를 통해 필터링해서 보는 것이 가장 보기 쉽고 깔끔하다.

아쉬우나마 adb logcat 을 이용해서 필터링 하고 싶다면 다음과 같이 한다.

adb logcat <TAG>:<LOGLEVEL> *:S
예를 들어, CameraTest 는 V 레벨로(CameraTest:V), Camera는 D 레벨로(Camera:D), 나머지는 안나오게 하고 싶다면(*:S) 다음과 같이 한다.

adb logcat CameraTest:V Camera:D *:S

filter-spec 등 adb의 사용법을 더 알고 싶다면 Android Debug Bridge(http://developer.android.com/guide/developing/tools/adb.html)를 참고한다.

[Android] userdata 지우기

개발 중에 App 설정이 userdata 에 저장되는데 잘못된 설정값을 설정하여 App가 계속 죽게될 경우 다시 진입해도 잘못 설정된 값이 저장되어 App가 계속 죽게 된다. 이럴 때 설정값을 날리기 위해서 adb shell 등으로 들어간 루트 쉘에서 다음 명령을 주면 된다.


# wipe data

[Android] Linux에서 adb와 fastboot 사용하기

http://androidforums.com/samsung-i7500/32481-howto-linux-adb-fastboot-mass-storage.html 에서 자세한 내용을 찾을 수 있다.
요약 정리하면,

Linux 에서 사용할 수 있는 fastboot은 플랫폼 빌드 시에 생성되며, out/host/linux-x86/bin/ 아래에서 찾을 수 있다.

그리고 사용하려는 Linux 머신의 /etc/udev/rules.d/ 경로에 다름 파일들을 생성한다.

50-android.rules

SUBSYSTEM==”usb”, ATTR{idVendor}==”18d1″, MODE=”0666″, OWNER=”<사용할 Machine 상의 USERNAME>”

90-android.rules

SUBSYSTEM==”usb”, ATTR{idVendor}==”04e8″, MODE=”0666″, OWNER=”<사용할 Machine 상의 USERNAME>”

그리고 다음 명령을 사용하여 udev rules을 갱신한다.

reload udev

2014.07.11. SYSFS{idVendor} 를 ATTR{idVendor} 로 변경.

구글 안드로이드 문서의 Content License

구글 안드로이드 관련 문서들을 살펴보다가 괜찮은 문서가 있으면 공부 및 정리 겸 해서 번역하면서 보려고 생각하다가 그냥 번역하고 인터넷 상에 올리면 안될 것 같아서 문서들 아래에 적혀있는 다음과 같은 문구의 링크된 Content License 부분을 눌러서 보게 되었다.


Android 1.5 r3 – 21 Jul 2009 11:19



일단 Content에 대해서 두가지로 나누고 있는데, 먼저, “Documentation content” 라 하여 “Dev Guide” 와 “Reference” 탭에 있는 샘플 코드나 소스코드로 부터 생성된 내용이나 그 외 내용들로 하나를 구분하고, 기타 다른 사이트 상의 모든 내용들, 이렇게 해서 두가지로 구분한다.

Content License 에 따르면, 일단 “Documentaion content”는 Android Open Source Project의 일부로 사용 가능하고, 어떤 코드가 포함된 문서들은 Apache 2.0 라이센스를 따른다고 한다. 물론 그에 앞서 GPLv2나 그 외의 라이센스에 해당하는 소스코드를 포함하는 경우에는 해당 라이센스가 우선된다. Apache 2.0 License에 관해서는 KLDPWiki: 오픈소스 소프트웨어 라이센스 가이드Apache 2.0 라이센스 원문, 그리고 Apache 2.0 라이센스의 번역본(김윤수님의 Apache License Version 2.0 번역 완료) 글을 참조해보기 바란다.

그리고 나머지 사이트 상의 다른 모든 자료들은 Creative Commons Attribution 2.5[우리말] 라이센스를 따른다.

Google Android 관련 Reference & JNI Complie 옵션

예전에 안드로이드 관련 과제를 진행하면서 보았던 Reference 들이다.

1.2 Reference #

[edit]

1.2.2 Android Internal #

이건 아마도 JNI 관련 라이브러리를 만드는 중에 시도했던 삽질 과정 중의 컴파일 옵션들..

  • ./configure –host=arm-none-linux-gnueabi –enable-shared CFLAGS=-fpic CXXFLAGS=-fpic LDFLAGS=-shared
  • ./configure –host=arm-none-linux-gnueabi –enable-shared
    CFLAGS=-fpic CXXFLAGS=-fpic CPPFLAGS=”-fpic -I/usr/local/include/
    -I/usr/lib/jvm/java-6-sun/include
    -I/usr/lib/jvm/java-6-sun/include/linux” LDFLAGS=-shared

이후에 자료들이 많이들 생긴 듯 해서 별로 필요는 없을 듯 하지만, 위키 쪽 자료들을 조금씩 정리하면서 블로그로 옮기고 정리해가자.

2012. 6. 19. 추가
Make shared native library: g++ -shared -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux -o libjnifunc.so jnifunc.cpp
Run: java -Djava.library.path=. JniFuncMain
Geting “Signature”: javap -s -p JniFuncMain

C++ library를 안드로이드에서 돌리기 위한 삽질

요즘 C/C++ 로 된 OpenCV 라이브러리를 안드로이드 플랫폼 안에 포팅해서 자바 라이브러리로 만드는 과정 중인데.. 순수 C App는 안드로이드 내부의 라이브러리로 빌드/실행이 가능한데 C++ 쪽은 문제를 겪고 있다.

내가 생각한 해결 방법은 그냥 GNU C++ library를 통째로 안드로이드 안으로 이식하려고 생각한 것이었다.

그러나 나같은 삽질을 한 사람이 또 있겠지 싶은 마음에..

여기저기 뒤져보던 중 구글의 Andorid Interanls 그룹에서 여러가지 포스팅 들을 찾을 수 있었는데,

글 들 중 가장 최신의 글은 삽질하지 말고 기다려라. 라는 것이다-_-

좌절이다.. OTL…

그러나 그 이전인 2월의 글 들 중 C++ Application 을 포팅하는데 성공했다는 사람(Susmith M R)이 있다.

이 포스팅(Dynamic Shared Library in Android Another Approach – Don’t Use android Linker)에서 찾을 수 있는데, 안드로이드 내부의 링커(/system/lib/linker)를 사용하지 말라는 이야기이다.

gcc의 옵션으로 -dynamic-linker=/system/lib/linker 대신,

링커 파일(ld-linux-so.6)을 넣고 –dynamic-linker=/system/lib/ld-linux-so.6 옵션으로 컴파일 한다는 건데.

링커 자체가 바뀐다면 추측상으론 DATA 섹션에서 RO 영역과 RW 영역 구분을 없앴던 부분도 수행하지 않고(바꿔 말하면 armelf_linux_eabi.xsc 를 사용하지 않고) 사용할 수 있을 듯도 하다. 음.. 잉? 아닌가? 음.. 생각해봐야겠다..

한번 해봐야겠다.

참고 :

Problem loading C++ library in android


Need little help for JNI


Dynamic Shared Library in Android Another Approach – Don’t Use android Linker

OpenCV의 안드로이드 포팅을 위한 첫단계!

OpenCV의 리눅스 소스를 안드로이드에 포팅하기 위해서 cvCreateImage와 cvReleaseImage 함수가 들어있는 cxcore 라이브러리의 빌드에 들어갔다.

소스의 루트디렉토리에서 ./configure 의 옵션을 조정하여 빌드하는 방법에 실패하고,

직접 cxcore/src 디렉토리 안에서 makefile을 작성하여 빌드하였다.

다음은 빌드할 때 사용한 makefile이다.

.SUFFIXES : .cpp .o

CC = arm-none-linux-gnueabi-gcc
LD = arm-none-linux-gnueabi-ld

INC =
LIBS =
CFLAGS = -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux -I../include -fpic -c
#LDFLAGS = -shared -T armelf_linux_eabi.xsc –dynamic-linker /system/bin/linker -nostdlib -rpath /system/lib -L/home/dasomoli/lib/arm-none-linux-eabi/ -lcv -lcxcore -lml
LDFLAGS = -shared -nostdlib -T /home/dasomoli/src/opencv_bak/opencv-1.0.0/armelf_linux_eabi.xsc -rpath /system/lib -rpath . -L . -L/home/dasomoli/androidinternal/system/lib -lc -lm -lstdc++

OBJS = cxalloc.o cxjacobieigens.o cxpersistence.o cxarithm.o cxlogic.o cxprecomp.o cxarray.o cxlut.o cxrand.o cxcmp.o cxmathfuncs.o cxsumpixels.o cxconvert.o cxmatmul.o cxsvd.o cxcopy.o cxmatrix.o cxswitcher.o cxdatastructs.o cxmean.o cxtables.o cxdrawing.o cxmeansdv.o cxutils.o cxdxt.o cxminmaxloc.o dummy.o cxerror.o cxnorm.o cximage.o cxouttext.o
SRCS = cxalloc.cpp cxjacobieigens.cpp cxpersistence.cpp cxarithm.cpp cxlogic.cpp cxprecomp.cpp cxarray.cpp cxlut.cpp cxrand.cpp cxcmp.cpp cxmathfuncs.cpp cxsumpixels.cpp cxconvert.cpp cxmatmul.cpp cxsvd.cpp cxcopy.cpp cxmatrix.cpp cxswitcher.cpp cxdatastructs.cpp cxmean.cpp cxtables.cpp cxdrawing.cpp cxmeansdv.cpp cxutils.cpp cxdxt.cpp cxminmaxloc.cpp dummy.cpp cxerror.cpp cxnorm.cpp cximage.cpp cxouttext.cpp

TARGET = libcxcore.so

all : $(TARGET)

$(TARGET) : $(OBJS)
    $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

$(OBJS) : $(SRCS)
    $(CC) $(CFLAGS) $(SRCS)

dep :
    gccmakedep $(INC) $(SRCS)

clean :
    rm -rf $(OBJS) $(TARGET) core

new :
    $(MAKE) clean
    $(MAKE)

CFLAGS의 옵션 중 -I/usr/lib/jvm/java-6-sun/include와 -I/usr/lib/jvm/java-6-sun/include/linux 옵션은 구글 안드로이드 Application 개발시 사용한 java 6 라이브러리의 include 경로이고, ../include 는 실제 $OPENCV_HOME/cxcore/include 이다. -c 옵션으로 *.o 파일을 생성한다.

물론, 이전에 javah로 구글 안드로이드 Application의 JNI를 사용하는 클래스의 C/C++용 헤더 파일(org_swssm_NativeOpenCV.h)이 생성되어져 있었고, 헤더 파일 안의 함수는 cxarray.cpp 함수 안에 구현되어져 있었다. 당연히 cxarray.cpp 에는 #include “org_swssm_NativeOpenCV.h” 가 들어가 있다. cpp 안의 함수 안에서 클래스를 env->FindClass 로 찾을 때 org.swssm.andCvSize 와 같이 클래스의 전체 경로를 적어주어야 한다는 점에 주의하자.

LFLAGS의 옵션 중 -T /home/dasomoli/src/opencv_bak/opencv-1.0.0/armelf_linux_eabi.xsc는 이전에 언급했던 툴체인 내의 ldscript의 수정본이다. 또한, -nostdlib 는 툴체인의 기본 라이브러리를 사용하지 않겠다는 옵션으로 보인다. 또, -rpath /system/lib -rpath . 는 라이브러리 실행 시 참조할 라이브러리 경로로써 안드로이드의 라이브러리 폴더인 /system/lib와 라이브러리가 들어가 있는 곳의 경로를 참조하도록 한다. -L . -L/home/dasomoli/androidinternal/system/lib 는 링킹 타임에 참조할 라이브러리가 들어가 있는 경로로 /home/androidinternal/ 아래에 Benno의 System image 가 압축 해제되어 있다. 이는 안드로이드에서 실제 사용되는 library를 링킹 시 참조하여 링킹하도록 한다. -lc -lm -lstdc++ 는 각각 안드로이드 /system/lib 의 libc.so, libm.so, libstdc++.so 를 참조하도록 한다.

make가 성공적으로 이루어지기 위해서는 OpenCV의 cxcore 라이브러리 내의 소스들에 약간의 수정이 필요한데, 이는 안드로이드 내부에서 사용되는 라이브러리들에서 지원되지 않는 함수(혹은, 내가 제대로 링크시키지 못했거나..;;)들을 제거해야 하기 때문이다. 대표적인 함수들로 assert 함수가 있으므로 include안의 #include <assert.h>를 주석처리 하고, cxtypes.h 내의 assert 문들이 사용된 부분을 삭제하도록 한다. 추가적으로 #define assert(x) (x) 하여 bool 처리만 하도록 처리하기도 하였다.

make clean; make를 마치면 libcxcore.so 파일이 생성되는데 이를 안드로이드 에뮬레이터의 /system/lib 안에 넣어주도록 한다.(adb push libcxcore.so /system/lib/)

안드로이드 플랫폼 내부에서의 libcxcore.so 파일의 동작여부를 확인하기 위해서 별도의 간단한 application을 build하여 테스트하도록 한다. 먼저 main.c 를 작성한다.

#include <stdio.h>
#include “cxcore.h”

int main(void)
{
    IplImage *pImage;
    CvSize size;

    size.width = 100;
    size.height = 100;

    pImage = cvCreateImage(size, 8, 3);

    cvReleaseImage(&pImage);

    return 0;
}

cvCreateImage와 cvReleaseImage 함수만을 사용하여 동작하는 지를 살펴본다.

main.c의 구동을 위해서 함수의 entry point가 되는 _start 함수를 구현한다. 이는 http://honeypod.blogspot.com/2007/12/dynamically-linked-hello-world-for.html 에서 사용한 start.c 파일을 그대로 사용하였다.(http://honeypod.blogspot.com/2007/12/initialize-libc-for-android.html의 _start 함수를 어셈블러로 구현하여 사용할 수도 있을 것 같다.)

#include <stdlib.h>
extern int main(int argc, char **argv);

void _start(int argc, char **argv)
{
        exit (main (argc, argv));
}

기억상으로는 start.o 는 arm-none-linux-gnueabi-gcc -c start.c 하여 그대로 사용했던 듯 하다.
main.o 는 arm-none-linux-gnueabi-gcc -c -I../include main.c 와 같이 하여 cxcore의 include 경로를 추가한 후 컴파일 하여 생성한다.
중요한 cxcoretest라는 간단한 Executable 생성은 다음의 옵션으로 한다.

arm-none-linux-gnueabi-ld –dynamic-linker /system/bin/linker -nostdlib -rpath /system/lib -rpath . -L . -L ~/androidinternal/system/lib -lc -lcxcore -lstdc++ -lm -ldl -o cxcoretest start.o main.o

shared library 생성시와는 다르게 armelf_linux_eabi.xsc 를 사용하지 않음에 주의한다. 이를 안드로이드 에뮬레이터에 넣고(adb push cxcoretest /data/) 실행해본다.

# ./cxcoretest
WARNING: `libcxcore.so` is not a prelinked library
#

실행은 잘 되는 것을 볼 수 있다. 근데, 제대로 호출된 것 맞는건가? 확인해보자. Benno의 strace를 받아 안드로이드에 넣고(adb push strace /data/), strace로 실행(./strace ./cxcoretest)해보자!

execve(“./cxcoretest”, [“./cxcoretest”], [/* 10 vars */]) = 0
getpid()                                = 1662
syscall_983045(0xb0015cb0, 0xb00128d8, 0x3d4, 0, 0xbeddddc8, 0x1, 0, 0xf0005, 0xb00128d8, 0, 0, 0xbeddddc4, 0, 0xbedddd78, 0xb0000dd9, 0xb00016fc, 0x10, 0xb0015cb0, 0, 0, 0xc764, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) = 0
gettid()                                = 1662
sigaction(SIGILL, {0xb0001471, [], SA_RESTART}, {SIG_DFL}, 0) = 0
sigaction(SIGABRT, {0xb0001471, [], SA_RESTART}, {SIG_DFL}, 0) = 0
sigaction(SIGBUS, {0xb0001471, [], SA_RESTART}, {SIG_DFL}, 0) = 0
sigaction(SIGFPE, {0xb0001471, [], SA_RESTART}, {SIG_DFL}, 0) = 0
sigaction(SIGSEGV, {0xb0001471, [], SA_RESTART}, {SIG_DFL}, 0) = 0
sigaction(SIGSTKFLT, {0xb0001471, [], SA_RESTART}, {SIG_DFL}, 0) = 0
open(“libc.so”, O_RDONLY|O_LARGEFILE)   = -1 ENOENT (No such file or directory)
open(“/system/lib/libc.so”, O_RDONLY|O_LARGEFILE) = 3
lseek(3, -8, SEEK_END)                  = 241860
read(3, “\0\0\340\257PRE “, 8)          = 8
mmap2(0xafe00000, 245760, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0xafe00000
close(3)                                = 0
mmap2(0xafe3c000, 45056, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) = 0xafe3c000
mprotect(0xafe00000, 233472, PROT_READ|PROT_EXEC) = 0
open(“libcxcore.so”, O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open(“/system/lib/libcxcore.so”, O_RDONLY|O_LARGEFILE) = 3
lseek(3, -8, SEEK_END)                  = 2199920
read(3, “veSlice\0”, 8)                 = 8
fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 0), …}) = 0
brk(0)                                  = 0x13000
brk(0x13000)                            = 0x13000
brk(0x14000)                            = 0x14000
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo …}) = 0
write(1, “WARNING: `libcxcore.so` is not a”…, 51WARNING: `libcxcore.so` is not a prelinked library
) = 51
lseek(3, 0, SEEK_END)                   = 2199928
mmap2(0x80100000, 2203648, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x80100000
close(3)                                = 0
open(“libm.so”, O_RDONLY|O_LARGEFILE)   = -1 ENOENT (No such file or directory)
open(“/system/lib/libm.so”, O_RDONLY|O_LARGEFILE) = 3
lseek(3, -8, SEEK_END)                  = 133184
read(3, “\0\0\300\257PRE “, 8)          = 8
mmap2(0xafc00000, 135168, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0xafc00000
close(3)                                = 0
mprotect(0xafc00000, 131072, PROT_READ|PROT_EXEC) = 0
open(“libstdc++.so”, O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open(“/system/lib/libstdc++.so”, O_RDONLY|O_LARGEFILE) = 3
lseek(3, -8, SEEK_END)                  = 4144
read(3, “\0\0\320\257PRE “, 8)          = 8
mmap2(0xafd00000, 8192, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0xafd00000
close(3)                                = 0
mprotect(0x80100000, 1986560, PROT_READ|PROT_EXEC) = 0
brk(0)                                  = 0x14000
brk(0x14000)                            = 0x14000
brk(0x15000)                            = 0x15000
brk(0x16000)                            = 0x16000
mprotect(0, 0, PROT_READ|PROT_EXEC)     = 0
brk(0x1d000)                            = 0x1d000
exit_group(0)                           = ?
Process 1662 detached

음… 봐도 잘 모르겠다.. 잘 안되는 것 같기도 하고… -_-;;;

흥미로운 점은, 빨간 색으로 표시한 부분을 보면 알겠지만, 사용된 안드로이드에서 제공하는 모든 library의 마지막 4 바이트에는 “PRE “가 들어가있다.

일단 JNI를 사용하는 Application을 사용해서 죽는지부터 보자-_-;;;

Call 버튼을 눌러보자!

사용자 삽입 이미지
오! 안죽는다! 안죽는게 뭐가 대단하냐고? ..당신은 삽질을 덜 한 것이다-_-+

그럼 cvCreateImage가 리턴하는 포인터의 값을 int로 찍어보자. 일단 값을 1234로 넣어두고 리턴하는 값을 받은 후에 찍어보자. 이왕 하는 김에 Object로 리턴하는 andCvSize 클래스의 값도 찍어보자!

                    int pImage = 1234;
                    Log.i(LOG_TAG, “pImage = ” + pImage);
                    pImage = NativeOpenCV.andcvCreateImage(cvSize, 8, 3);
                   
                    Log.i(LOG_TAG, “after call, pImage = ” + pImage);

                    andCvSize cvSize2 = NativeOpenCV.andcvGetSize(pImage);
                   
                    Log.i(LOG_TAG, “cvSize2.width : ” + cvSize2.width + “, cvSize2.height : ” + cvSize2.height);
                   
                    NativeOpenCV.andcvReleaseImage(pImage);

adb logcat

I/CallOpenCV( 1830): pImage = 1234
D/dalvikvm( 1830): LOADING path /system/lib/libcxcore.so 0x4006ddb0
I/dalvikvm( 1830): Added shared lib /system/lib/libcxcore.so 0x4006ddb0
I/dalvikvm( 1830): No JNI_OnLoad found in /system/lib/libcxcore.so 0x4006ddb0
D/dalvikvm( 1830): +++ not scanning ‘/system/lib/libwebcore.so’ for ‘andcvCreateImage’ (wrong CL)
D/dalvikvm( 1830): +++ not scanning ‘/system/lib/libmedia_jni.so’ for ‘andcvCreateImage’ (wrong CL)
I/CallOpenCV( 1830): after call, pImage = 1459360
D/dalvikvm( 1830): +++ not scanning ‘/system/lib/libwebcore.so’ for ‘andcvGetSize’ (wrong CL)
D/dalvikvm( 1830): +++ not scanning ‘/system/lib/libmedia_jni.so’ for ‘andcvGetSize’ (wrong CL)
I/CallOpenCV( 1830): cvSize2.width : 100, cvSize2.height : 100
D/dalvikvm( 1830): +++ not scanning ‘/system/lib/libwebcore.so’ for ‘andcvReleaseImage’ (wrong CL)

D/dalvikvm( 1830): +++ not scanning ‘/system/lib/libmedia_jni.so’ for ‘andcvReleaseImage’ (wrong CL)

오오! 잘된다! 한번 더!

I/CallOpenCV( 1830): onClick
I/CallOpenCV( 1830): calling native method
I/CallOpenCV( 1830): pImage = 1234

I/CallOpenCV( 1830): after call, pImage = 1459360


I/CallOpenCV( 1830): cvSize2.width : 100, cvSize2.height : 100

잉? 포인터 값이 같네? 제대로 된 거 맞나? Release했던 부분을 놔뒀다가 다시 사용하나? cvReleaseImage를 주석처리 하고 계속 할당하는지 보자!

I/CallOpenCV( 1889): pImage = 1234
D/dalvikvm( 1889): LOADING path /system/lib/libcxcore.so 0x40060948
I/dalvikvm( 1889): Added shared lib /system/lib/libcxcore.so 0x40060948
I/dalvikvm( 1889): No JNI_OnLoad found in /system/lib/libcxcore.so 0x40060948
D/dalvikvm( 1889): +++ not scanning ‘/system/lib/libwebcore.so’ for ‘andcvCreateImage’ (wrong CL)
D/dalvikvm( 1889): +++ not scanning ‘/system/lib/libmedia_jni.so’ for ‘andcvCreateImage’ (wrong CL)
I/CallOpenCV( 1889): after call, pImage = 1460544
D/dalvikvm( 1889): +++ not scanning ‘/system/lib/libwebcore.so’ for ‘andcvGetSize’ (wrong CL)
D/dalvikvm( 1889): +++ not scanning ‘/system/lib/libmedia_jni.so’ for ‘andcvGetSize’ (wrong CL)
I/CallOpenCV( 1889): cvSize2.width : 100, cvSize2.height : 100
I/CallOpenCV( 1889): onClick
I/CallOpenCV( 1889): calling native method
I/CallOpenCV( 1889): pImage = 1234
I/CallOpenCV( 1889): after call, pImage = 1490752
I/CallOpenCV( 1889): cvSize2.width : 100, cvSize2.height : 100

후후후.. 포인터 값이 계속 바뀌는군.. 그럼 계속 할당되는 게 맞겠지 ㅋㅋㅋ

그럼 성공!!! 으하하하하하하!

참고 :
http://groups.google.com/group/android-developers/browse_thread/thread/b3376922f5b7a93a
http://groups.google.co.jp/group/android-developers/browse_thread/thread/ed437a61e678aab8
http://benno.id.au/blog/2007/11/13/android-native-apps
http://honeypod.blogspot.com/2007/12/shared-library-hello-world-for-android.html
http://honeypod.blogspot.com/2007/12/dynamically-linked-hello-world-for.html
http://benno.id.au/blog/
http://honeypod.blogspot.com/2007/12/initialize-libc-for-android.html
http://davanum.wordpress.com/2007/12/09/android-invoke-jni-based-methods-bridging-cc-and-java/
http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html

JNI + Android

JNI 사용 구조는 다음 그림으로 요약할 수 있습니다.

Android에서 사용하는데 필요한 것은 5 단계에서 Cross Compiler로 컴파일 되어야 한다는 것입니다.

그리고 컴파일 된 결과가 “.DLL”이 아니라 “.so” 파일로 나온다는 거겠죠.

Cross Compiler는 http://www.codesourcery.com/gnu_toolchains/arm/download.html 에서 구할 수 있습니다.

그런데 gcc의 -shared 옵션으로 .so 파일을 만들고 실행해보면, 사용될 때 App가 죽어버립니다.

이는 precompiled-library에 관련된 문제로 보이는데, 이를 위해서 컴파일 단계의 ldscript를 수정해서 사용합니다.

http://honeypod.blogspot.com/2007/12/shared-library-hello-world-for-android.html 를 참고하면 다음과 같은 부분을 볼 수 있습니다.

Now, the default linker script need to be modified. The default
linker script is available at
$toolchains_home/arm-none-linux-gnueabi/lib/ldscripts/armelf_linux_eabi.xsc.
Copy it to the current directory. Comment out three lines and add one
line replacing the first commented out line.

/* . = ALIGN (CONSTANT (MAXPAGESIZE)) – ((CONSTANT (MAXPAGESIZE) – .) & (CONSTANT (MAXPAGESIZE) – 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); */
. = .; /* this line replaces the line above */

/* . = DATA_SEGMENT_RELRO_END (0, .); */

/* . = DATA_SEGMENT_END (.); */

$toolchains_home/arm-none-linux-gnueabi/lib/ldscripts/ 경로에 있는 armelf_linux_eabi.xsc 파일을 수정해야 한다는 이야기입니다.

수정한 파일을 사용해서 다음 명령으로 컴파일하면 실제 안드로이드에서 동작하는 라이브러리를 만들 수 있습니다.

arm-none-linux-gnueabi-gcc -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux -fpic -c <JNI 함수 구현소스>.c

arm-none-linux-gnueabi-ld -T armelf_linux_eabi.xsc -shared -o <library명>.so <Object파일>.o

그리고 emulator 실행 후 다음 명령으로 에뮬레이터에서 실행가능합니다.

adb push <라이브러리>.so /system/lib
adb install <JNI를 사용하는 Android APP>.apk

구글 Android SDK 셋팅(우분투 8.04 기준)

1. http://code.google.com/android 에서 Download the SDK 를 클릭

2. 라이센스 확인

3. Linux (i386) 용 zip 다운로드

4. 압축 해제.

4.1. 계정의 .profile 맨 마지막에 다음 내용을 추가하고 다시 로그인 << 여기 추가되었습니다.

PATH=”$HOME/android/tools:$PATH”
PATH=”$HOME/eclipse/tools:$PATH”

4.2. 압축해제한 디렉토리를 ~/android 로 symbolic link. << 여기 추가되었습니다.

5. JDK 설치(sudo apt-get install sun-java6-jdk)

6. http://code.google.com/android 의 Docs 를 눌러 Getting started / Installing the SDK

7. System and Software Requirements 의 Eclipse 를 눌러 Eclipse IDE for Java Developers를 다운로드

8. 홈폴더에서 압축해제.

[#M_* 바탕화면에서 실행하기 위해 $HOME/바탕화면/eclipse.desktop 생성|<<접기>>| [Desktop Entry]
Version=1.0
Exec=/home/dasomoli/eclipse/eclipse
Icon=/home/dasomoli/eclipse/icon.xpm
Name=Eclipse
GenericName=Development Tools
Comment=Eclipse
Encoding=UTF-8
Terminal=false
Type=Application
Categories=Application;Development;_M#]
9. Eclipse에서 WST 설치

10. Eclipse에서 https://dl-ssl.google.com/android/eclipse/ 를 추가하고 설치

11. Eclipse에서 Window/Preference 의 Android 의 SDK Location 을 아까 SDK의 압축 해제 디렉토리로 지정

12. 프로젝트 시작!