리눅스, J2ME, 그리고 OSGi와의 융화 - 구글 안드로이드 플랫폼 아키텍처

2007 년 11월 공개된 구글의 안드로이드(Android)는 휴대폰 개발에 필요한 소프트웨어 플랫폼 일체를 제공하는 공개 소프트웨어의 이름이다. 구글이 모바일 환경에서도 이름에 걸맞은 영향력을 발휘할 수 있을지는 전적으로 안드로이드 플랫폼이 지닌 활용성에 달려 있다고 해도 지나치진 않다. 이 글에서는 임베디드 개발환경의 변화 방향을 가늠케 하는 안드로이드 플랫폼 아키텍처를 집중적으로 분석해 본다.

김석우 suhgoo.kim@samsung.com

휴 대폰의 소프트웨어는 하루아침에 만들 수 없다. 이르면 2008년 말 상품화되어 처음 선보이는 안드로이드도 현시점에서 공개된 것은 여전히 극히 일부이다. 그러나 안드로이드의 구성이나 설계 철학은 공개된 범위에서 표면화되고 있다. 커널은 리눅스지만 그 이외의 부분은 일반적인 임베디드 리눅스와는 매우 다르다. 독자적인 가상머신(VM)을 채택한 설계지만, 한편으로 기존의 자바 프로그램과의 호환성을 활용하려고 하는 등 장점만을 ‘취사선택’하려고 한다. 필자는 지난해 12월 공개된 정보(Android DSK)를 바탕으로 안드로이드가 어떠한 플랫폼인지를 분석해 봤다. 결론적으로 안드로이드는 향후 2~3년 후에 전 세계 표준이 될 가능성이 있는 타깃으로, 현 시점에서 적절한 기술을 조합한 것이라 할 수 있다.

기존의 오픈소스 기술이나 자바 개발자들의 경험 등을 충분히 살릴 수 있도록 안드로이드는 아키텍처를 디자인해 새로운 기술을 담아 완벽하게 정리했다. 필자는 이번 플랫폼 분석을 위해 크게 두 가지 관점에서 접근했는데, 각각 안드로이드의 컴포넌트 아키텍처 구성과 API(Application Programming Interface)이다.

전자는 안드로이드의 이식성 및 안드로이드 아키텍처에 대한 평가와 관련되고, 휴대폰에 안드로이드 플랫폼을 탑재할 경우에 중요하다. 플랫폼 구성 형태를 면밀히 살펴본 결과, 전체적으로 과거와의 계승성 등을 고려하지 않고 새로운 운영체제를 처음부터 다시 만든다는 의욕이 느껴졌다. 예를 들면 리눅스를 커널에 사용하면서도 라이브러리 군에 일반적인 리눅스와는 다른 소프트웨어를 이용하는 점이 남달랐다. 이는 휴대폰 개발업체의 요구사항을 감안해 자유롭게 사용할 수 있는 오픈소스 소프트웨어를 모은 결과이다. 후자인 API에 대한 평가는 애플리케이션 프로그램 개발이나 배포의 용이성 등 플랫폼으로서 앞으로 보급할 여지가 있는지가 핵심이다. 분석 결과, 안드로이드는 물론 기존의 모바일 소프트웨어 개발자들이 쉽게 접근할 수 있도록 플랫폼을 설계했다. 하지만 무엇보다 기존 자바(J2SE/EE)를 통해 데스크톱이나 서버 사이드 애플리케이션을 만드는 개발자들이 큰 거부감 없이 안드로이드를 이용해 개발할 수 있도록 했다. 즉 전 세계의 수많은 자바 개발자들을 흡수하려는 노력이 매우 돋보인 플랫폼이라고 생각된다.

안드로이드 아키텍처의 특징

안 드로이드의 아키텍처는 리눅스 커널 상에 네이티브 코드로 동작하는 라이브러리군과 ‘Dalvik 가상머신(Dalvik VM)’이라 부르는 독자 VM 실행환경, 그리고 그 위에서 동작하는 애플리케이션 프레임워크로 구성되어 있다. 프레임워크에 근거해 애플리케이션 프로그램을 기술함으로써 개발의 부하를 줄일 수 있다. 애플리케이션 프로그램은 원칙적으로 Dalvik VM으로 실행한다. 프로그램의 기술언어는 자바이다. 이 가운데 가장 먼저 눈에 띄는 것은 독자적인 가상머신을 전면적으로 채택했다는 점이다. 이는 복수의 하드웨어 아키텍처가 혼재된 내장 용도인데다, 마이크로프로세서의 성능이 향상된 현재로서는 필연적인 선택이라고 할 수 있다. 가상머신을 설치함으로써 다른 기기에서 프로그램을 공통화할 수 있으며, 개발효율을 향상시킬 수 있다. 가상머신은 성능 면에서 오버헤드가 크지만 2008년 이후에 등장할 기기라면 임베디드 또는 모바일용으로 충분히 이용할 수 있다고 판단했을 것이다.

또 하나의 특징은 리눅스를 커널에 채택했다는 점이다. 그렇게 함으로써 새로운 하드웨어나 주변기기에 대응하기 쉬워진다. 리눅스에는 하드웨어 메이커가 직접 디바이스 드라이버를 제공한다. 리눅스를 커널에 채택한 것은 모든 하드웨어가 이식되기 때문이며, 다양한 하드웨어를 설계하고 채택하는 휴대폰 제조업체들에게는 매우 반가운 일이 아닐 수 없다. 한편 커널 이외에는 리눅스 관련 소프트웨어를 사용하지 않는다. 예를 들면 구글은 표준 C 라이브러리 ‘libc’는 BSD UNIX의 것임을 분명히 밝히고 있다.

현재 구글이 공개한 오버뷰를 통해 판단할 수 있는 것은 이 정도이다. 그 이상은 내부 구조로 더 들어가지 않으면 알 수 없다. 현 상황에서는 안드로이드의 소스 코드 공개 범위가 너무나 좁다. 개발 툴을 제외하면 커널과 HTML의 렌더링 엔진(Webkit) 뿐으로 이는 구성요소의 극히 일부에 지나지 않는다. 그러나 실제 동작하는 안드로이드 SDK를 통해 꽤 많은 사실이 표면화되었다. SDK에 부속된 에뮬레이터는 오픈소스인 QEMU를 안드로이드용에 적용한 것이다. 에뮬레이터의 대상이 되는 하드웨어를 QEMU로 설치해, 그 위에서 안드로이드의 실행 환경을 동작시키고 있다. 우리는 안드로이드의 실행 프로세스를 살펴보기 위해 에뮬레이터를 통해 API 실행을 구현하는 방식, 즉 시뮬레이션이 아니라 실제 소프트웨어를 에뮬레이터가 설치된 타깃 하드웨어에서 동작시키고 있다. 에뮬레이터의 소스 코드를 보면 안드로이드가 대상이 되는 하드웨어가 나타난다.

메인 메모리 영역은 소스 코드에 표시된 것처럼 96MB이고(<그림 2>의 (a) 부분), 거기서 연속적으로 V램 영역이 이어진다(<그림 2>의 (b) 부분). 그리고 메모리 맵I/O가 최상위 공간에 할당되어 있다.

<그림1> 안드로이드 플랫폼 아키텍처

<그림2> goldfish의 메모리 맵

주 요 하드웨어의 구성은 ‘Android_arm.c’ 파일에 기술되어 있다. 마이크로프로세서는 ‘ARM926’, 코어는 ARM9E이다. 접속하는 주변기기나 인터럽트 제어기 등은 동일한 파일에 기술되어 있다. 그러나 메인 메모리의 메모리 사이즈는 ‘vl.h’ 파일에 분산시켜 기술되어 있었다. 전자는 96MB, 후자는 8MB이다. 이렇게 해서 정의된 하드웨어에는 ‘goldfish’라는 명칭을 붙였다. 고려하는 화면 사이즈는 두 가지로 320×240 화소의 QVGA와 480×320 화소의 HVGA이다. 이는 각각 가로가 긴 랜드스케이프 모드와 세로가 긴 포트레이트 모드에서 이용할 수 있다. 화면 사이즈의 변화에 따른 영상의 차이 등은 에뮬레이터로 체크할 수 있다.

안드로이드 파일시스템

에 뮬레이션 환경에서는 PC에서 동작하는 ‘Android Debug Bridge(adb)’라는 툴을 사용해 리눅스의 쉘(Shell)을 조작할 수 있다. 이는 에뮬레이터 상에서 동작하는 ‘adbd’라는 프로세스와 통신함으로써 실현된다. 이 쉘(Shell)을 통해 디렉토리나 파일 구성을 들여다보면 지극히 평범한 리눅스에 가까운 것처럼 보인다. 예를 들면 구동 시에 실행되는 스크립트는 ‘etc’ 디렉토리에 저장되어 있다. 그러나 자세히 보면 안드로이드에서 특징적인 파일은 표준 리눅스에서는 그다지 볼 수 없는 ‘system’, ‘data’등의 디렉토리에 있다. 예를 들면 안드로이드의 Dalvik VM의 본체는 system 디렉토리 아래에 있는 bin 디렉토리에 들어 있다.

<그림 3>을 보면 일반적인 리눅스와 비슷한 이름의 디렉토리도 있지만 다른 부분도 많이 눈에 띈다. 예를 들면 일반적인 리눅스에서 ‘usr/bin/’에 저장되는 프로그램 구성들이 ‘system/ bin/’에 저장되어 있다.

쉘(Shell) 조작으로 이용하는 ‘ls’나 ‘mv’ 등의 명령어는 안드로이드에서는 toolbox라 부르는 하나의 프로그램이 통합해 관리하고 있다. 임베디드 리눅스의 경우는 같은 기능을 제공하는 프로그램을 BusyBox를 통해 사용하는 경우가 많다. 여기에서도 일반적인 리눅스와의 차이점이 나타난다.

프로세스의 메모리 구조

통 상적인 리눅스와의 차이가 더욱 확연한 부분은 논리 메모리 공간의 구성이다. 이러한 기본적인 부분에서 리눅스와 다른 것을 보면 리눅스를 커널에만 한정하고 있음을 재확인할 수 있다. 논리 메모리 공간은 각각의 프로세스에 할당된 것으로 애플리케이션 프로그램이 이용할 수 있는 메모리 공간이다.

SDK에 표준으로 부속되는 ‘mem_profiler’ 명령어로는 알 수 없지만, KMC의 디버그를 사용하면 조금 더 자세한 메모리 구성을 알 수 있다. 통상적인 리눅스의 경우는 동적으로 로드(load)되는 라이브러리(‘.so’ 모듈이라 불린다)가 논리 메모리 공간의 저위 어드레스에서 고위 쪽으로 할당된다. 이 할당을 실행하는 것은 ‘ld.so’ 프로그램이 일반적이다. 이와 관련해 안드로이드에서는 공유 라이브러리가 논리 어드레스 공간의 고위 어드레스에서 저위방향으로 확보된다.

필자는 일반적인 임베디드 리눅스와 안드로이드의 메모리 매핑을 비교했다. 일반적인 임베디드 리눅스의 예로, ARM Embedded 리눅스 2.2.0을 이용했다. 일반적인 임베디드 리눅스는 40000000번지부터 공유 라이브러리나 파일을 순서대로 배치하고 있다. 안드로이드는 파일을 40000000번지부터 순방향으로, 라이브러리를 B0000000번지부터 역방향으로 배치하고 있다. 라이브러리를 로드하는 역할을 하는 것은 ‘linker’라는 명칭의 프로그램이다. 메모리 공간의 구성에서 또 한 가지 특징적인 것은 Dalvik VM용 영역을 별도로 확보하고 있다는 점이다. 일반적으로 리눅스용 JVM인 경우에는 이를 위한 영역을 별도로 준비하지는 않는다. 안드로이드의 경우는 모든 애플리케이션 프로그램을 Dalvik VM으로 동작시키기 때문에 Dalvik VM에 관련되어 소비하는 메모리의 양이 늘어남을 전제로 배치한 것으로 분석된다.

<그림3> 안드로이드의 파일시스템

<그림4> 독특한 메모리 매핑

독자적인 Dalvik VM

안 드로이드에서 많은 이들이 가장 궁금해 하는 부분이 바로 안드로이드의 독자적인 VM인 Dalvik이다. 하지만 Dalvik VM 자체의 소스 코드는 공개되지 않았으므로 안드로이드의 쉘(Shell)에서 동작하는 ‘dexdump’ 프로그램을 사용해 분석했다. dexdump 프로그램은 Dalvik VM의 실행형식인 ‘.dex’ 파일을 조작하기 위한 프로그램으로 파일 헤더의 정보를 취득하거나 코드 섹션을 역어셈블하는 기능 등을 갖추고 있다. 헤더 부분에는 그 파일에 저장되어 있는 클래스의 명칭이나 새로운 클래스의 명칭, 메소드 명칭 등의 정보가 들어 있다.

<그림5> 바이너리 코드를 역어셈블한 결과

자 바 가상머신이 스택형을 채택하고 있는 것에 반해 Dalvik VM은 레지스터형의 가상머신임을 알 수 있다. 실제로 dexdump를 이용해 <그림 5>와 같이 .dex 파일을 역어셈블해 보았다. 독자적으로 작성한 애플리케이션 프로그램인 ‘uiTest’의 ‘onCreate’ 메소드의 서두 부분을 표시한 것으로, ‘move-object’라는 명령이 4개 연속되어 있다. 바이트 코드를 보면 모두 ‘07’이라는 코드로 시작되며 이어지는 바이트의 상위와 하위를 각각 인수(argument)로 할당하고 있다. 예를 들어 ‘40’에 대응하는 역어셈블 결과는 v0, v4가 되며 ‘51’이라면 v1, v5가 되는 식이다. 아마 v0, v1 등이 레지스터이고, 4비트로 레지스터 번호를 나타내는 것으로 보인다. 따라서 레지스터는 16개까지 존재할 수 있다. 이어지는 invoke-super-quick은 새로운 클래스의 메소드를 불러내는 명령으로 이는 ‘fa02’로 표시되고 있다. 다음의 2바이트는 동적 링크를 위한 링크 테이블 번호를 나타내는 듯하다. const 명령은 어떠한 정수를 레지스터에 대입하는 조작으로 보인다. 또한 invoke-virtual-quick은 메소드를 불러내기 위한 명령일 것이다.

레지스터형을 채택하고 있다는 것은 분명 Dalvik VM의 명확한 특징 가운데 하나로, 굳이 가상머신의 사양을 변경해야만 하는 이유가 있는 듯하다. 구글의 한 엔지니어는 “자바에는 프로그램을 로드했을 때, 동작의 정당성 등을 검증하는 ‘Bytecode verifier’라는 기술이 있다. 이 특허를 썬마이크로시스템즈(이하 썬)가 소유하고 있으므로, 이에 저촉되는 것을 피하기 위한 것은 아닐까”라고 추측했다. 또한 레지스터형을 도입하면 ARM926 등에서 제공되는 자바 프로그램의 고속화기구인 ‘Jazelle DBX’를 이용할 수 없게 된다. 그러나 앞으로 새롭게 등장할 ARM11 아키텍처의 경우에는 Jazelle DBX를 사용하지 못하게 되므로 문제가 없을 것으로 보는 의견도 있었다. 여기서 수행한 역어셈블의 결과만으로 가상머신 명령체계의 전체 모습을 파악하기란 어렵다. 소스 코드나 가상머신의 사양 공개가 기다려지는 것도 바로 이 때문이다.

안드로이드 API 형태

아직 공개가 지연되고 있는 안드로이드 본체와는 달리, 애플리케이션 프로그램 개발에 관한 정보는 대략 공개되어 있다. 이는 애플리케이션 소프트웨어 대부분이 플랫폼의 강력함으로 이어진다고 구글이 판단한 결과로 풀이된다.

실 제로 개발 콘테스트 등을 개최하고 있는 것도 같은 이유일 것이다. 안드로이드의 애플리케이션 프로그램에는 ‘Activity’, ‘Service’, ‘Content Provider’, ‘Intent Receiver’라고 하는 네 가지 형태가 있다. 유저 인터페이스(UI)를 가진 안드로이드의 애플리케이션 프로그램은 Activity로서 수행된다. Service는 UI를 가지고 있지 않으며 연속적으로 정보를 제공하는 프로그램이다. Content Provider는 데이터베이스와 같은 특정 조건 하에서 데이터를 제공하는 것이다. Intent Receiver는 외부의 이벤트에 대해 어떠한 반응을 나타낼 때에 사용한다. 보통 애플리케이션 프로그램을 만들 때에는 Activity를 사용한다. 각각의 Activity는 Activity 클래스의 하위 클래스로 수행된다. 실행 시에는 애플리케이션 프레임워크가 라이프 사이클 모델에 근거해 Activity를 호출한다.

<그림6> activity의 라이프 사이클 모델

분산환경 지원

안 드로이드의 API에서 특징적인 개념 중 하나가 ‘Intent’이다. 프로그램 간 연계 시스템으로 CORBA나 COM 시스템을 더욱 진화시킨 것이라 할 수 있다. 안드로이드 프로그램의 경우, 원칙적으로 애플리케이션 프로그램은 각각 독립된 논리 메모리 공간에서 동작한다. 때문에 직접 세마포어 등을 사용해 메모리를 공유하는 등의 일은 할 수 없다. 그래서 다른 프로그램에 처리를 부탁하는 것을 Intent로 정의한다. 이 Intent를 처리할 수 있는 프로그램을 운영체제가 적절하게 할당하는 형태를 취한다.

<그림7> activity와 intent

안 드로이드의 프로그래밍에서 특징적인 존재가 Activity와 Intent이다. Activity는 유저 인터페이스를 갖는 프로그램으로 반드시 갖추고 있어야만 한다. Intent는 Activity 등이 데이터 처리를 의뢰할 때에 의향을 명시하기 위한 데이터 구조로, Intent에 대응하는 적절한 프로그램을 안드로이드의 Activity Manager와 커널이 적절하게 판정해 처리를 할당한다. Intent를 받을 수 있는 것은 안드로이드가 규정하는 네 가지 형태 중에서 Activity와 Intent Receiver이다. 유저 인터페이스를 갖는 프로그램이 받을 경우는 Activity로 수행되고, 모두 백그라운드로 통신되는 경우는 Intent Receiver로 수행된다.

안드로이드와 J2SE

안 드로이드는 애플리케이션 구현에 필요한 개발환경으로 자바를(J2ME/SE) 선택했는데, 실제 문제는 바로 어떤 자바 클래스를 이용할 것인가이다. 안드로이드의 경우는 ‘java.io’나 ‘java.net’ 등 자바의 표준적인 패키지 가운데 이용할 수 있는 것이 적지 않다. 커다란 차이는 UI 부분이며, MVC 모델 등에 근거해 프로그램을 만들면 의외로 간단하게 자바 프로그램을 안드로이드용으로 변환할 수 있을 것이다.

<그림8> 안드로이드와 J2ME/SE 구조

안 드로이드가 표준으로 제공하는 클래스 라이브러리 패키지를 휴대폰용 자바 애플리케이션 개발 기반인 ‘CLDC 1.1’ 및 ‘MIDP 2.0’, 서버나 PC용 개발 기반인 ‘Java SE’와 비교해 보자. 안드로이드의 클래스 라이브러리 패키지는 J2ME의 CLDC-MIDP와의 호환성은 의식하지 않고, Java SE의 서브셋에 구글의 독자 라이브러리를 추구한 것이라 할 수 있다. 결국 이러한 애플리케이션 구조는 심비안이나 CLDC-MIDP 기반에서 개발된 휴대폰용 자바 프로그램의 이식에 어려운 점이 있다. 예를 들어 휴대폰에서 서버와 통신하는 분산 네트워크 환경과 같은 고급 기능의 측면에서 보면, 안드로이드와 휴대폰용 자바의 규약인 CLDC인 경우에는 큰 차이가 있기 때문이다. 안드로이드가 채택한 자바 클래스를 보면 휴대폰용 소프트웨어 개발자보다는 서버에서 동작하는 서비스를 개발해 온 개발자들을 흡수하기 위한 것이라는 해석이 성립된다. 안드로이드의 네트워크 기능은 J2EE와 크게 다르지 않다. 저장할 수 있는 데이터의 양에 차이는 있지만 서버 사이드에서 개발해 온 서비스 아이디어를 그대로 휴대폰의 애플리케이션으로 개발할 수 있다.

<그림9> 안드로이드와 OSGi공통 분야

안드로이드와 OSGi

사 전을 찾아보면, 안드로이드는 그리스어가 어원이고 ‘인간을 닮은 것’이라는 의미를 지니고 있다. 그렇다. 확실히 구글의 안드로이드는 자바 플랫폼을 많이 닮아있다. 하지만 안드로이드가 인간이 아니듯, 구글의 안드로이드 플랫폼은 정확히 말해 자바는 아니다. 오픈소스가 IT 업계의 큰 트렌드로 자리 잡은 이 시점에 나타나는 문제점 가운데 하나는 급격한 소스의 파생이 이뤄지고 있다는 점이다. 이른바 ‘fork’라고도 하는데, 어쩌면 구글의 안드로이드는 자바의 Fork가 될 수도 있겠다. 구글은 왜 모바일과 임베디드 업계에서 점차 확산되고 있는 J2ME를 채택하지 않았을까? 더 나아가서 채택하지 않았으면서 왜 J2ME의 아키텍처를 템플릿으로 참조해 안드로이드 플랫폼을 탄생시켰을까? 아마도 그것은 썬의 자바에 대한 지나치게 폐쇄적인 JCP 정책과 항상 뒤늦은 대응정책 때문이었을 것이다. 썬은 JCP를 통해 자바의 로고와 스펙, 그리고 업그레이드에 대한 독립적이면서 독자적인 권한을 가진다. 구글로서는 자바 환경에서 독립적인, 그리고 무소불위의 권한을 가진 썬이 자사의 모바일 전략에 큰 걸림돌로 여겨졌을 것이다(물론 뛰어난 자바의 기술력과 확장성은 탐이 났겠지만). 결국 자바와 극히 비슷한(J2ME의 CDC 환경) 안드로이드 플랫폼은 일반적인 JVM이 아니라 독립적인 DALVIK VM을 탄생시켰고, Dex 파일이라는 고유한 Dalvik 포맷(format)을 개발자들에게 선물했다.

물론, 모바일 업계에서 아직 J2ME-CLDC/MIDP는 메인 스트림이 아니다. 점차 스마트폰을 중심으로 확산되고는 있지만 제조업체마다 독립적인 API와 서로 다른 RMI 방식, 고급 UI를 지향하면서 무거워져만 가는 GUI 모듈, manifest를 위한 거대한 XML 타입 등과 같이 다양한 모바일 실행 환경에서 여러 가지 문제점들을 나타내고 있다. 구글은 이러한 문제점들을 해결하고 더욱 고급화되는 UI나 멀티태스킹, 강력한 애플리케이션 및 관리 솔루션을 J2ME를 벤치마킹함으로써 개선하고자 했다. 그러나 오픈된 안드로이드 아키텍처를 보면 구글이 플랫폼 구조와 애플리케이션 구동에는 많은 관심을 보여 왔지만, J2ME-OSGi 플랫폼에 비해 독립적인 모듈구조, 애플리케이션의 라이프 사이클, 애플리케이션을 통합 관리할 수 있는 미들웨어 부분에서는 약점을 드러내고 있음을 알 수 있다. 이러한 문제점들은 OSGi(Open Service Gateway Initiatives) 프레임워크에서 장점으로 내세울 수 있는 부분이며, 따라서 안드로이드를 오픈한지 얼마 되지 않은 구글 입장에서 OSGi를 안드로이드 플랫폼에 통합 및 연동하거나 안드로이드-OSGi 솔루션으로 확대될 것을 기대하는 개발자들이 늘어나고 있다. 또한 이러한 개발자들의 요구에 맞춰 몇몇 전문 벤더에서는 안드로이드-OSGi 솔루션을 이미 개발해 시장에 진입하려 하고 있다. 그렇다면, 안드로이드와 OSGi는 어떻게 다르고 그 둘의 연동이 우리에게 가져다주는 장점은 무엇인가? 먼저 안드로이드와 OSGi는 VM을 지원하는 방식이 다르다.

<그림10> 안드로이드와 OSGi의 차이

OSGi 는 하나의 VM 위에서 구동되어, 각 서비스 또는 애플리케이션이 번들 타입으로 작동하게 된다. 따라서 리소스 및 데이터의 공유가 쉽고 각 번들의 결합을 통해 서비스의 생성과 참조가 쉽게 이뤄진다. 하지만 안드로이드는 하나의 VM에서 하나의 프로세스가 애플리케이션으로 구동되어 작동된다. 따라서 프로세스 간 데이터, 리소스 공유시 IPC, 메타포어 등을 통해야 한다. 그러나 안정성과 보안 측면에서는 OSGi보다 우수하다고 할 수 있다. 그러나 PC 애플리케이션이나 서버급의 엔터프라이즈가 아닌 모바일 및 임베디드 환경에서는 더 작은 메모리로 빠르게 서로를 공유 및 참조할 수 있고 번들과 서비스의 모듈성이 보장되는 OSGi 구조가 훨씬 더 효율적이다.

<그림11> 효율적인 OSGi 컴포넌트의 참조와 공유

또 한 안드로이드에서 오브젝트의 모듈성에 대한 문제점이 노출되고 있는데, 그것은 바로 Dex 파일의 구성이다. 표준 클래스 로더가 바이트 코드를 로드하려면 반드시 하나의 JAR 파일과 함께 작성되어야 한다. 따라서 JAR 파일 내에 위치한 번들을 찾기 위해 번들-클래스패스(Bundle-Classpath) 같은 기능을 사용하려면 JAR 파일 전체를 핸들(handle)하는 불필요한 메모리 누수가 발생한다. 이러한 문제점들은 하나 내지 소수의 애플리케이션을 작성하고 구동할 때보다, 다수의 애플리케이션들이 구동될 때에 치명적인 약점으로 나타날 수 있다.

그렇다면 OSGi와 안드로이드가 결합될 때에 가져다주는 장점은 무엇인가? 그것은 단연 번들의 재사용성이다. J2ME, J2SE를 기반으로 하는 수많은 기존의 번들 코드를 그대로 사용할 수 있고, 또한 기존의 코드를 이용해 다양한 서비스의 참조나 생성을 통해 안드로이드용 애플리케이션을 빠르게 작성할 수 있다. 또한 안드로이드 플랫폼에서 작성하는 애플리케이션에 비해 OSGi 프레임워크의 번들은 OSGi에서 지원하는 다이내믹한 코드의 모듈성과 강력한 번들 라이프사이클 관리시스템으로 인해 코드 사이즈가 작아진다.

그러므로 안드로이드-OSGi 애플리케이션(번들 구현)은 실제로 수행되는 Activity 코드와 GUI 부분에 집중해 개발되어 기존의 애플리케이션보다 훨씬 작은 바이트 코드로 개발할 수 있다. 마지막으로는 강력한 개발 툴의 지원을 꼽을 수 있다. 이미 OSGi는 이클립스에 통합되어 있고 RCP & eRCP라는 개발방법론으로 임베디드-모바일-데스크탑에 이르기까지 다양한 플랫폼에서 전 세계 자바 개발자들에게 각광받고 있다. 이러한 통합된 개발환경과 방법론으로 전 세계 자바 개발자들에게 안드로이드는 더욱 쉽게 다가갈 수 있을 것이다. 안드로이드-OSGi 솔루션이 이러한 장점을 지니고 있어 기존의 OSGi 분야 강자인 IBM과 Prosyst도 지난해 구글에서 공개된 이후부터 이 분야를 강력하게 밀고 있다.

그럼 안드로이드-OSGi는 쉽게 통합되고 연동될 수 있는가? 이에 대한 답은 올해 3월 미국 캘리포니아에서 열린 이클립스 개발자 컨퍼런스 ‘EclipseCON’에서 찾아볼 수 있었다. EclipseCON은 과거 이클립스 분야의 오픈소스 개발자들이 모여 시작된 작은 컨퍼런스인데, 재작년부터 OSGi DevCON과 통합되어 이클립스 뿐만 아니라 RCP, OSGi, Server Framework 등 다양한 주제들로 꾸며지고 있다. 이번 OSGi 개발자 세션 역시 별도로 열렸는데, 이번 컨퍼런스에서 IBM의 B.J Hargrave가 안드로이드-OSGi 통합이라는 주제를 발표해 큰 호응을 이끌어냈다.

안드로이드-OSGi 연동은 크게 두 가지로 이뤄진다. 하나는 안드로이드 플랫폼에 프레임워크를 탑재하는 부분이고, 또 하나는 다이내믹한 번들의 수정 또는 개발이다.

안드로이드-OSGi 통합

첫 번째로 안드로이드에 OSGi를 탑재해 구동하는 것은 그렇게 어려운 문제는 아니다. 그것은 이미 OSGi가 다양한 VM에 포팅되어 탑재된 경험이 있기 때문이다. OSGi는 기존 JVM이 아닌 Dalvik VM을 통해 구동되므로, Dexification이라는 절차를 거쳐 JAR 파일이 Dex 파일로 수행됨을 인식시켜 준다.

Apache-Felix에서는 큰 문제없이 구동되었으나, Equinox에서는 몇 가지 사항을 수정해야만 했다. Equinox에서는 어떤 Properties를 수정하기 위해 CodeSource를 사용하는데 반해, 안드로이드에서는 ProtectionDomain이 null이기 때문에 아예 CodeSource를 사용할 수 없다. 따라서 직접 코드에 정해 주어야만 한다.

또한 ClassLoader.getResource()는 hook된 Confi guration Property File의 리스트를 사용하는데 반해, 안드로이드는 아예 null 값을 리턴하므로 configuration.ini에 직접 리스트 값을 정의해야 한다. 이러한 각 OSGi와 안드로이드의 환경설정을 맞춰 주면, 안드로이드에서 OSGi 프레임워크를 수행하는 것에 무리가 없다.

마 지막으로, 번들의 구성이다. 번들의 개발은 OSGi 프레임워크 구동과는 좀 다른 차원의 문제이다. 가장 큰 문제점들이 자바에서 공식적으로 발표되고 사용하는 API가 수정을 거쳐야 하거나 또는 아예 안드로이드에서는 지원되지 않는다는 것이다. 이 부분은 매우 중요한 부분으로 OSGi 프레임워크에서는 번들을 다이내믹하게 로드하고 수행하는 데 표준 API가 필요한다. 만일 안드로이드가 지원하지 않으면 독자적인 안드로이드 API를 사용하기 위해 직접 개발해 주어야 하는 문제가 따른다. 그것은 무엇보다 Dalvik VM의 특성을 따르게 된다. 일반적인 Class Loader.defineClass()가 작동하지 않고 Dalvik의 android. dalvik.Dexfile을 사용하거나, Nested JARs와 Directory Bundles 기능을 사용할 수 없다. 또한 간단한 번들 클래스패스(Bundle Class path)만 사용할 수 있는 등의 제약사항들이 있다. 따라서 그에 대한 Exception 처리 또는 코드를 수정해야만 한다.

하지만 가장 큰 문제점은 역시 수행시간이다. Dexification이라고 불리는 단계에서 바이트 코드와 Dex 파일 변환이 동시에 이뤄지기가 어렵기 때문에 JIT 기능을 수행하는 성능이 매우 떨어지게 된다. Dexification의 JIT 최적화 문제는 반드시 해결되어야 하는 이슈이다. 또한 풀 번들 클래스패스(Full Bundle ClassPath) 지원도 필요하다. 지금은 간단한 번들 클래스패스 지원만 가능한데, 이 부분은 불필요한 메모리 낭비가 동반되기 때문에 역시 반드시 해결되어야 하는 부분이다. 따라서 이러한 문제점을 보완하고 해결하기 위해 Equinox Incubator 프로젝트로 안드로이드-OSGi 솔루션이 개발되고 있다.

Prosyst OSGi와 안드로이드

안 드로이드 플랫폼 위에 OSGi를 탑재하려는 벤더들의 노력들이 이어지고 있는데, 그중 대표적인 업체가 바로 Prosyst이다. 이 업체에서도 역시 안드로이드 플랫폼에 자사의 OSGi 솔루션을 탑재하는 것을 목표로 다양한 연구 개발을 진행하고 있는데, 대표적으로 OSGi 상용화 솔루션으로 널리 알려진 mBS와 OSGi 전용 DBMS-DB4O을 안드로이드에 탑재해 구성한 Servo 솔루션을 들 수 있다. Prosyst에서 내세우는 안드로이드-OSGi의 장점은 다음과 같다.

Lack of class-sharing

안 드로이드는 각각의 VM에서 프로세스가 구동되는 구조이므로, 클래스의 공유는 클래스를 복제하는 방법으로 지원한다. 이러한 구조는 심각한 메모리 누수를 가져오고, 성능의 저하가 예상된다. 안드로이드와 달리 OSGi는 직접적인 클래스 공유를 통해 메모리 사용량을 줄이고 성능 향상을 나타낸다.

Fine-grained components

안 드로이드는 구조적으로 컴포넌트 간 IPC와 같은 추상화 레벨의 인터페이스로 통신하게 된다. 컴포넌트 간의 가장 효율적인 통신 방안은 Directly Method Calls이다. 이러한 컴포넌트 간 통신 모델은 이클립스의 RCP, eRCP와 같은 플러그인 아키텍처를 가능하게 하며, 한층 효율적인 컴포넌트 구성을 돕는다.

Device Management

원 격 관리 및 지원 기능은 모바일 디바이스와 서비스 업체의 서버간 중요 기능으로 점차 부각되고 있다. 하지만 아쉽게도 안드로이드는 원격 관리에 대한 기능이 지원되지 않는다. OSGi에서는 rOSGi를 비롯해 OMA-DM을 통한 다양한 원격 모바일 솔루션을 이미 상용화해 서비스하고 있다.

이러한 특징을 전면에 내세우며 Prosyst는 mBS와 Servo 솔루션의 상용화에 심혈을 기울이고 있다. mBS가 전통적인 안드로이드-OSGi 솔루션이라면, Servo는 더 현실적으로 안드로이드에 접근하고 있다. 이는 안드로이드를 채택한 휴대폰에서 구현 및 저장되는 다양한 데이터를 저장하고 관리하는 데 초점을 맞춘 솔루션이다.

특히 사용자가 지닌 다양한 형태의 자료를 저장하는 것을 UGD(User Generated Data)로 명명하고 기존 안드로이드의 SQLite가 아닌 DB4O라는 OODB를 채택해 사용한다. DB4O 엔진이 OSGi 번들로 구성되어 있어서 다이내믹한 로드와 OSGi의 직접적인 관리를 받게 된다.

한편 DB4O는 OSGi 번들용으로 구현되어 기존의 임베디드 DB보다도 작은 코드 사이즈와 빠른 성능, 완벽한 SQL 지원이 특징이다. 그리고 무엇보다 오픈소스로서 SQLite를 채택하고 있는 안드로이드 플랫폼에 더욱 적합한 OSGi용 DB 솔루션으로 주목받고 있다.

이상으로 우리는 구글에서 공개한 안드로이드 플랫폼과 안드로이드 위에 OSGi를 탑재하는 솔루션에 대해 살펴봤다. 휴대폰 소프트웨어 개발이 지금까지 다른 플랫폼에 비해 폐쇄적이었던 터라 일반 개발자들이 다가가기 어려웠던 분야였는데, 안드로이드는 그러한 장벽을 없애 휴대폰 플랫폼에 전 세계 개발자들이 쉽게 다가갈 수 있는 길을 열었다는 데 큰 의미가 있다고 생각한다. 또한 안드로이드를 통해 지금보다 훨씬 강력하고 다양한 기능을 가진 휴대폰이 우리 곁에 빠르게 다가올 것이다.