자료제공 : 휴인스 www.huins.com

안드로이드에서 속도 문제가 있는 계산 루틴을 처리한다거나 특정 하드웨어를 제어할 때는 JNI를 사용해야 한다. 또한 기존에 C/C++로 작성된 프로그램이나 시스템과의 연계를 위해 사용된다. JNI는 JAVA에서 Native code를 사용할 수 있는 인터페이스를 말하며, 좀 더 쉽게 말하면 C나 C++로 작성한 API를 JAVA에서 호출하게 해준다. JNI에 대한 이해를 위해 먼저 안드로이드 플랫폼의 구조를 살펴보자.

안드로이드 플랫폼 구조

1. 리눅스커널
- 태스크 간의 스케줄링
- 메모리, 디스크, 네트워크 등의 자원을 사용할 수 있는 시스템 콜 제공
- 네이티브 라이브러리를 통해 응용프로그램이 편하게 사용할 수 있는 형태로 제공

2. 안드로이드 응용프로그램
- 애플리케이션 프레임워크를 이용해 Java로 작성
- 안드로이드 SDK를 이용해 빌드 Java 컴파일러와 dex converter를 거쳐 Dalvik VM에서 동작하는 바이트 코드 생성
- 애플리케이션 프래임워크(.jar형태의 java class)를 이용해 VM에서 제공하는 코어라이브러리 기능사용
- 코어 라이브러리는 리눅스 커널 위에서 동작하는 다양한 C/C++ 라이브러리(c/c++)을 호출
- 필요에 따라 리눅스 커널의 system call을 호출

3. 안드로이드 런타임 계층과 라이브러리 계층을 연결하는 과정에서 추가적으로 C/C++ 과 Java 호출 사이에 연결고리가 존재한다.
- 이것으로 인해 안드로이드 프레임워크는 OS의 기능을 리눅스 커널로부터 가져다 쓸 수 있는 것이다.

C/C++과 JAVA의 연결

1. Java Native Access(JNA)
- 자바 코드에서 네이티브 코드와 같은 형태로 네이티브 함수를 호출하는 방식
- 기존 코드 최소 수정으로 최상의 방법
- Dalvik VM에서는 지원하지 않는다.

2. Java Native Interface(JNI)
- Java 초창기부터 존재하는 방법
- Dalvik VM에서 지원
- 안드로이드 플랫폼 소스 여러 부분에서 사용
- 개발 시간 소요, 에러 발생 요소

3. Simplified Wrapper and Interface Generator(SWIG)
- JNI를 좀 더 쉽게 사용할 수 있도록 해주는 도구
- C/C++ 인터페이스를 정의한 파일을 입력 받아 C/C++ JNI wrapper 코드를 생성
- Dalvik VM과는 호환성 문제가 존재

JNI는 자바와 자바이외의 언어로 만들어진 애플리케이션이나 라이브러리가 상호 작용할 수 있도록 연결시켜 주는 인터페이스이다.

 

<그림 1>

JNI를 사용해야 하는 경우

• 속도 문제가 있는 계산 루틴
- 자바가 Native Code(플랫폼에 종속적인 기계어 코드)에 비해 느림
- 아주 빠른 처리가 요구되는 대량의 계산 작업, 실시간(real time)처리
• 자바에서 하드웨어를 제어
- 특수한 목적으로 제작된 하드웨어를 제어 할 수 없음
- 자바에서는 동적으로 어드레스를 할당하기 때문에 특정번지를 할당 할 수 없음
• 자바에서 지원되지 않는 특정 운영체제 서비스
- 자바의 클래스 라이브러리는 방대하고 다양한 서비스를 제공하지만, 특정 플랫폼에서 제공하는 고유의 서비스의 기능을 모두 포함할 수는 없다.
- 특히, 특수한 목적으로 제작된 하드웨어를 자바에서 제어해야 할 필요가 있다고 한다면, 자바만으로 해결하기는 힘들다.
- 플랫폼에 따라 제공되는 서비스 이용
•기존의 프로그램(C/C++)에서 자바가 제공하는 서비스를 이용
- 기존에 작성된 프로그램이나 기존의 시스템과의 연계 문제

자바가 엔터프라이즈 솔루션에 많이 사용되는 것은 자바가 갖고 있는 많은 장점들이 대규모 시스템 구축에 적합하다는 강점을 인정받고 있는 셈이다. JNI는 그 자체가 중요한 솔루션이 될 수는 없지만, 기존의 코드나 기존의 시스템 혹은 이질적인 다른 시스템과의 인터페이스에 사용될 수 있는, 자바가 가진 좋은 기능 중의 하나다.

다음은 JNI를 이용하여 실제 LED 디바이스 드라이버를 제어하는 예제이다.


1. Android Project 만들기
- File → New → Other...


<그림 2>

- New Android Project에 생성할 Project 속성을 입력한다.


<그림 3>


- Project에서 jni 폴더를 만들고 led_jni.c 파일를 추가한다.


<그림 4>

- led_jni.c 파일에 소스 내용을 입력하고 저장한다. 


<그림 5>

* navtive 함수 형식
- Jni에 쓰이는 native 함수 이름에는 규칙이 있다.

예를 들어 java_com_huins_android_ledjni_LedJni_nativeSetLedIndex라는 native 함수명은 이 함수를 사용할 java 파일에 참조하여 만들어야 된다. java에서 java_com_huins_android_ledjni는 com.huins.android. ledjni라는 package명이고. LedJni는  파일명, nativeSetLedIndex는 함수명으로 사용된다.

- Project의 jni 폴더에 Android.mk 파일 추가한다.


<그림 6>

- led_jni.c를 컴파일하기 위해서는 Android.mk에 다음과 같이 내용을 추가시켜 준다.


<그림 7>

- ndk로 c언어 파일을 compile하기 위해서 ndk-build를 실행한다.

 
<그림 8>

* ndk-build에서 -C옵션은 경로를 포함한 프로젝트를 build할 경우 사용된다.
그리고 ndk-build 경로를 PATH에 추가 시켜 두면 경로와 상관없이 build를 할 수 있다.
ex) .bashrc파일에 [export PATH=$PATH:]를 추가함.


- ndk-build 후에는 project에서 Refresh[F5]를 해주면 project 목록에 libs라는 폴더가 생성된 것을 확인할 수 있다.


<그림 9>

- libs가 추가된 것을 확인했으면 Java 코드를 작성한다.


<그림 10>

 * java파일에서 native 함수를 호출하기 위해서
public native void nativeSetLedIndex(int index);와 static { System.loadLibray("led_jni"); }를 선언해 주어야 된다.

2. linux kernel에 led를 gpio로 제어할 수 있도록 driver module을 추가한다.


<그림 11>

* led_jni.c 코드에 있는 /dev/gpio 장치를 사용하기 위해서는 led와 연결된 gpio를 제어할 수 있는 led_driver.ko라는 모듈이 커널에 적재되어야 된다.

3. 실행화면 보기


<그림 12>

4. 보드 실행 사진       


<그림 13>
 
회원가입 후 이용바랍니다.
개의 댓글
0 / 400
댓글 정렬
BEST댓글
BEST 댓글 답글과 추천수를 합산하여 자동으로 노출됩니다.
댓글삭제
삭제한 댓글은 다시 복구할 수 없습니다.
그래도 삭제하시겠습니까?
댓글수정
댓글 수정은 작성 후 1분내에만 가능합니다.
/ 400
내 댓글 모음
저작권자 © 테크월드뉴스 무단전재 및 재배포 금지