'Android'에 해당되는 글 53건
- 2009.07.19 Activity lifecycle 2
- 2009.07.17 Android Basic 194
- 2009.07.17 안드로이드 기본 개념. 6
- 2009.07.12 android full source app의 수정방법 1
- 2009.05.19 HOWTO: Cupcake (kernel 2.6.27) on VirtualBox 2.2.2 1
- 2009.05.15 Play media file 1
- 2009.05.12 Media(A/V) Playback 4
- 2009.05.12 Native C application제작(colsole용) 2
- 2009.05.01 android sdk 1.5에서 AVD(Android Virtual device) 설정방법
- 2009.04.25 안드로이드 APP개발 시작하기
- Android는 Linux Kernel을 기반으로 하고 있다. 왜 Linux System이 아닌 Kernel인가?
- 어찌보면 당연하다. Mobile Device 상에서 full linux는 필요없다. 하지만 Android를 넷북이나 UMPC 등으로 영역을 확장한다면 좀 다른 얘기가 될지도 모른다
- Android is not Linux
- Android는 Linux Kernel을 기반으로 하는 Mobile Platform이라고 정의하길 선호한다.
- Native windowing system, glibc support(gnu c library), 표준 linux utilities 등을 포함하지 않고 있다.
- 일종의 file system 및 하드웨어를 제어하기 위한 드라이버 등, 최소한의 Linux를 채용하고 있다고 볼 수 있다.
- Android는 Linux Kernel의 안정적인 System 운영 측면을 가져온 것이다. Linux의 지속적인 업데이트 또한 장점이 되었을 것이다.
- Linux 2.6.24를 기반으로 하였으나 최근 발표된 Android 1.5에서는 Linux 2.6.29로 업그레이드 됨
- Kernel enhancements를 통해 Android를 지원
- Alarm / Ashmen(Android shared memory) / Binder / Power Management / Low Memory Killer / Kernel Debugger / Logger
- Why Linux kernel?
- Great memory and process management
- Permissions-based security model
- Proven driver model
- Support for shared libraries
- It's already open source
- Application과 Service는 별개의 process에서 동작을 하지만 상호 communicate 하거나 data를 공유할 필요가 있다. 이는 IPC (Inter Process Communication)를 통해 지원 : Binder
- High performance through shared memory
- Per-process thread pool for processing requests
- Reference counting, and mapping of object reference across processes
- Synchronous calls between processes
- AIDL(Android Interface Definition Language)
- PM (Power Management) Solution
- 기본적으로 Linux Power Management를 기반으로 구성 (on top of it)
- More aggressive power management policy - 결국 좀 더 타이트한 policy를 통해 pm을 한다는 내용
- Components make requests to keep the power on throught "wake locks"
- Support different types of wake locks
- Android.os.PowerManager - use wake locks carefully!
- Bionic Libc
- What is - 일종의 c library로 android에서는 다음과 같은 이유로 standard c lib가 아닌 bionic libc를 쓰기로 함
- Bionic은 custom libc implementation, optimized for embedded use
- License 문제 - standard c lib는 GPL이므로 사용자는 자신의 code를 open 해야 함으로 이로부터 자유롭게 하기 위해
- BSD License
- Size - android에서는 will load in each process 해야 함으로, so it needs to be small
- Small size and fast code paths
- Fast - mobile device와 같은 한정된 CPU에 최적화되어 빠르다
- Very fast and small custom pthread implementation
- 단점 or 장점?
- Doesn't support certain POSIX features
- Not compatible with Gnu Libc (glibc)
- All native code must be compiled against bionic
- Function Libraries
- WebKit - 현재까지 알려진 Web 엔진 가운데 가장 괜찮음 : 애플사파리(아이폰포함), Nokia 등이 WebKit 기반 Web 엔진 사용
- Based on open source WebKit browser
- Renders pages in full (desktop) view
- Full CSS, Javascript, DOM, AJAX support
- Support for single-column and adative view rendering
- Media Framework
- Based on PacketVideo OpenCORE platform
- Supports standard video, audio, still-frame formats
- Support for hardware/software codec plug-ins - 기본 지원외에 format은 plug-in을 통해 또는 hardware accelerator등이 장착된 mobile device에도 plug-in을 사용하여 fully 지원할 수 있다.
- SQLite
- Light-weight transactional data store
- Back end for most platform data storage
- Native Servers
- Surface Flinger
- Provides system-wide surface "composer", handling all surface rendering to frame buffer device
- Can combine 2D and 3D surfaces and surfaces from multiple applications
- Surfaces passed as buffers via Binder IPC calls
- Can use OpenGL ES and 2D hardware accelerator for its compositions
- Double-buffering using page-flip
- Audio Flinger
- Manages all audio output devices
- Processes multiple audio streams into PCM audio out paths
- Handles audio routing to various outputs
- Hardware Abstraction Libraries
- User space C/C++ library layer
- Defines the interface that Android requires hardware "drivers" to implement
- Separates the Android platform logic from the hardware interface
- Why do we need a user-space HAL? - HAL 영역이 왜 필요한가 : 당연 - Linux에서 kernel driver가 존재할 텐데 왜 굳이 Android용 HAL을 제공하는가에 대한 문제
- Not all components have standardized kernel driver interface - 현재 제공되는 Linux system 상에서 모든 component의 driver interface에 대한 표준화가 되어있는 것은 아니다
- Kernel drivers are GPL which exposes any proprietary IP - kernel driver는 현재 GPL로 되어 있어 그대로 사용하게 되면 연계 소스코드에 대해 오픈을 해야 한다
- Android has specific requirements for hardware drivers
- Dalvik Virtual Machine
- 사용자에게 Java를 이용해 app을 작성하게 하고 이러한 Java platform 기반 app을 모바일 device상에서 동작하게 하기 위한 최적의 환경을 제공하기 위해 기존의 Java VM과는 별도로 Google이 제공하는 VM이라고 할 수 있다
- 일반 VM과는 다음과 같은 다른 특징을 가지고 있다
- The VM was slimmed down to use less space
- Dalvik has no Just-in-time compiler
- The constant pool has been modified to use only 32-bit indexes to simplify the interpreter
- It uses its own bytecode, not Java bytecode
- Android's custom clean-room implementation virtual machine
- Provides application portability and runtime consistency
- Runs optimized file format (.dex) and Dalvik bytecode
- Java .class/.jar files converted to .dex at build time
- Designed for embedded environment
- Supports multiple virtual machine processes per device
- Highly CPU-optimized bytecode interpreter
- Uses runtime memory very efficiently
- Core Libraries
- Core APIs for Java language provide a powerful, yet simple and familiar development platform
- Data structures, Utilities, File access, Network Access, Graphics, …
- Core Platform Services
- Services that are essential to the Android platform
- Behind the scenes - applications typically don’t access them directly
- Activity Manager, Package Manager, Window Manager, Resource Manager, Content Providers, View System
- Hardware Services
- Provide access to lower-level hardware APIs
- Typically accessed through local Manager object
- LocationManager lm = (LocationManager) Context.getSystemService(Context.LOCATION_SERVICE);
- Telephony Service, Location Service, Bluetooth Service, WiFi Service, USB Service, Sensor Service
- Runtime Walkthrough
- It all starts with init… - similar to most Linux-based systems at startup, the bootloader loads the Linux kernel and starts the init process.
- Init starts Linux daemons, including:
- USB Daemon (usbd) to manage USB connections
- Android Debug Bridge (adbd) to manage ADB connections
- Debugger Daemon (debuggerd) to manage debug processes requests (dump memory, etc.)
- Radio Interface Layer Daemon (rild) to manage communication with the radio
- Init process starts the zygote process:
- A nascent process which initializes a Dalvik VM instance
- Loads classes and listens on socket for requests to spawn VMs
- Forks on request to create VM instances for managed processes
- Copy-on-write to maximize re-use and minimize footprint
- Init starts runtime process:
- Initializes Service Manager - the context manager for Binder that handles service registration and lookup
- Registers Service Manager as default context manager for Binder services
- Runtime process sends request for Zygote to start System Service
- Zygote forks a new VM instance for the System Service process and starts the service
- System Service starts the native system servers, including:
- Surface Flinger, Audio Flinger
- Native system servers register with Service Manager as IPC service targets:
- System Service starts the Android managed services:
- Android managed Services register with Service Manager:
- After system server loads all services, the system is ready..
- Each subsequent application is launched in it's own process
- There are 3 main flavors of Android layer cake:
- App -> Runtime Service -> lib
- App -> Runtime Service -> Native Service -> lib
- App -> Runtime Service -> Native Daemon -> lib
- App -> Runtime Service -> lib
- App -> Runtime Service -> Native Service -> lib
- App -> Runtime Service -> Native Daemon -> lib
안드로이드에서 사용하는 언어는 자바이지만 SUN의 자바와 API와 버추얼머신이 다르다.
Dalvik 이라는 회사의 버추얼머신이 있었는데 구글에서 회사를 통째로 사들였다고 한다. 이때문에 안드로이드는 SUN의 라이센스로부터 자유롭다.
안드로이드 플랫폼은 크게 네 부분으로 나뉜다. 커널부분, 하드웨어추상레이어, 라이브러리, 응용프로그램 프레임워크. 라이브러리들은 C/C++로 구현이 되어 있다. 기존의 여러 프로젝트 들을 통합하였기 때문에 C로 구현된 것들이 대부분이고 C++도 있다. 응용프로그램 프레임워크는 자바로 구현되어 있다. 프레임워크와 라이브러리 사이에는 자바와 C 사이의 서로다른 호출 규약등을 맵핑하는 JNI라는 마셜러가 존재한다. 하드웨어 드라이버를 C로 만들면 JNI를 구현해야 한다. 이를 위한 구글 가이드가 있고 샘플도 공개되어 있다. 그리고 SDK를 생성하여 응용프로그램 개발자에게 전달하면 된다. 하드웨어 부분은 구글에서 표준으로 정해두었기 때문에 따로 만질 필요가 없다. 추상레이어도 스펙이 다 되어있어 응용프로그램을 개발할 때는 API로 보이게 된다.
기존 임베디드리눅스와 안드로이드의 차이점중 한가지는 장치드라이버들( 그래픽, 오디오, 카메라 등 )이 커널영역이 아닌 유저모드에서 동작한다. 유저모드로 동작 시키면 자신에게 할당되어 있는 번지에만 접근할 수 있기 때문에 조금 더 안전하지만 하드에어 제어시에는 MMU등을 참조하는 등의 추가적인 작업이 필요하기 때문에 조금 불편할 수 있다. 이렇게 드라이버들을 유저영역에 넣은 이유는 라이센스문제, 안정성, 문서화의 편리성( 커널버전이 업데이트 될 때마다 드라이버에 대한 문서를 갱신할 필요가 없다 ), 플러그인 방식으로 드라이버 배포가 가능한점이 있다. 안드로이드에서는 기존 리눅스의 라이브러리로 만든 것들은 동작하지 않는다고 보면 된다. 같은 이름의 라이브러리라 할지라도 안드로이드의 라이브러리들은 스마트폰에 탑재하는 것을 기준으로 불필요한 코드들을 제거하고 최적화를 해두었기 때문이다. POSIX Thread 관련 라이브러리를 예로 들면 create, join 등의 필수 함수를 제외한 나머지함수는 모두 제거되어있다.
Android Kernel
왜 안드로이드는 리눅스 커널 기반일까. 생각하기 나름이겠지만 우선 오픈소스이고 안전하게 입증된 드라이버 모델(well abstracted )이 적용되어 있고, 메모리 프로세스 관리 모델을 제공하고, 하드웨어와 입출력에 대한 보안모델을 제공하고, 공유라이브러리를 지원하는 등 비용과 시간이 적게 드는 이유가 한몫 한것 같다.
현재 커널 안정화버전은 2.6.27 이다. 구글에서 순수 리눅스 커널을 가져다가 안드로이드 용으로 패치한 것이다. 기존의 리눅스와는 다르게 GLIBC를 지원하지 않고 EABI( Embedded Arm Binary Interface?)와 Binder를 사용한다. 그리고 커널 기능 향상을 위해 Alarm, Ashamem(공유메모리), Low memory-killer, debugger, logger 컴포넌트가 추가되었다.
유저모드는 허가된 자원에만 접근이 가능하고 프로그램의 안정성을 높일 수 있지만 하드웨어 효율성은 떨어질 수 있다. 반대로 커널모드는 하드웨어 효율성은 높지만 안정성은 떨어질 수 있다. 안드로이드는 기본 드라이버들을 제외한 나머지 드라이버들은 유저스페이스에서 동작한다. 일반 PC는 사람의 생명을 빼았지는 않지만, 심장박동 컨트롤러, 핸드폰만 가지고 조난 당했을 경우와 같이 스마트폰을 모델로 하면 생명과 연결될 수 있기 때문에 안정성이 속도나 효율보다 더 중요하다.
이전에는 일반적으로 일반 gcc를 썼지만 최근의 리눅스 커널을 빌드할 경우에는 ARM사에서 표준으로 정해둔 ABI( arm binary interface ) 규격의 컴파일러를 사용한다. 현재 안드로이드는 EABI( Extended??..) 기능을 지원한다. 일반 컴파일러에서 빌드한 것을 EABI에서 실행할 수 없기 때문에 EABI 컴파일러로 다시 빌드해야 한다. 최근의 임베디드 컴파일러는 대부분 EABI컴파일러 이다. 실수 연산방식에 있어서 하드플로팅포인트와 소프트웨어 플로팅포인트를 혼합하여 빌드할 수 있다. 기존의 ABI는 빌드옵션에서 VFP(Vector Floating Point)를 선택하거나 해제할 수 있었는데 이는 환경이 달라지면 다시 빌드 해야하는 단점이 있었다. EABI는 혼용이 되기 때문에 빌드의 부담이 줄어든다. 또한 구조체 팩킹이 편해졌고 호환성이 증가하였다. 그리고 syscall 규약에 변경사항이 있다. 이전에는 전달인자 4개까지는 레지스터를 쓰고 5개부터는 스택을 사용했는데 레지스터를 r0, r1, r2, r4 처럼 연속된 순서로 했었다. EABI는 레지스터 간격이 달라지는등 호출 규약이 달라졌다.
Kernel Enhancement
기존의 임베디드 리눅스에 없던 안드로이드만의 향상된 기능에는 알람, 로우메모리킬러, 공유메모리드라이버, 커널디버거, 바인더, 파워매니지먼트, 로거가 있다. 결국 포팅 이슈는 이것들과 관련될 것이다. 스마트폰으로 만들다 보니까 알람이 기본적으로 제공되어야 한다. 포팅 시 이 기능을 사용하고 싶지 않다면 다른기능과 맞물려 있기 때문에 확인해보고 작업을 진행해야 한다. 공유메모리드라이버는 안드로이드에서 커스터마이징을 했고 메모리 할당이 필요하면 전부 ashmem에 있는 라이브러리를 이용한다.
리눅스에서는 각 프로세스마다 우선순위를 주고 메모리가 부족하면 우선순위가 낮은 것을 없앤다. 안드로이드는 프로세스마다 우선순위를 주지 않고 그룹마다 우선순위를 준다. 그 이유는 바인더 때문이다. 메모리 부족 시 우선순위가 낮은 그룹을 제거한다. 안드로이드에는 프로그램 종료 기능이 없다. 화면은 내릴 수 있지만 알아서 프로그램이 제거되기 때문이다. 자바로 응용프로그램을 만들기 때문에 가비지컬렉터가 있다. 종료버튼이 있다 하더라도 UI가 없어질 뿐 그 자체가 바로 종료되는 것은 아니다.
이중 가장 중요한 것은 바인더라고 할 수 있다. 바인더에 의해 안드로이드와 기존 리눅스의 차이가 생긴다. 커널버전 2.6.30이상부터는 커널과 안드로이드가 통합된다는 말이 있는데 2.6.29이전의 커널은 바인더폴트( 메모리 회수에 문제가 있는 버그)가 있었다. 그럼 기존에 나왔던 안드로이드폰들도 이 버그가 있었을까? 아마도 개발인력이 많기 때문에 자체적으로 해결했을 것 같다. 바인더 서비스를 넣으면 기존의 전통적인 커널구조가 객체지향 구조로 바뀐다. 컴포넌트 중심으로 양쪽간 메시지를 주고받는 구조로 바뀐다는 말이다. 이것의 장점은 한쪽이 잘못 되어도 반대쪽까지 잘못되지는 않는다는 점. 응답을 못받거나 결과만 이상하게 나올 뿐이다.
전원관리기능은 기존의 리눅스가 가지고 있는 3단계에 2개를 더해 5단계로 이루어진다. 안드로이드 커널을 설정할때는 자신의 하드웨어에 전원관리 모듈이 없어도 반드시 포함시켜야 한다. 포팅을 하게 되면 시간이 지날수록 이것들에 집중해야 할 것이다.
Binder
바인더는 프로그램과 데이터를 공유하기 위한 것이다. 기존의 IPC는 보안이슈와 오버헤드이슈가 있다. 리눅스에서도 오픈바인더를 쓸 수 있지만 안드로이드에서 더 활성화를 시켜 두었다. 2.6.29에 기존 버그들이 완벽하게 패치되었다. 이전의 방식은 커널을 통해서 데이터를 공유하였다.(커널의 공유메모리 영역에 데이터를 올려두고 시그널등의 이벤트를 받아 메시지 큐 등을 써서 - 세마포어, 뮤텍스, 스레드 등 ). 바인더는 커널쪽의 메인호스팅이 없고 바인드라는 서비스가 있는 것이다. 바인드를 호출하면 응용프로그램과 디바이스쪽에 바인드서비스가 붙어 서로 통신하게 된다. 바인드서비스는 커널이 아니다. 서로다른 서비스간, 응용프로그램간 데이터를 주고받을 때 동작하게 된다. 여기서의 단점은, 기존의 방식은 하나의 매개체가 있고 공유해서 썼지만 바인드는 각각의 서비스마다 바인더가 있어야 하기 때문에 메모리 낭비가 되는 측면이 있다. 그럼에도 불구하고 쓰는 이유는 바인더는 각각 별개로 동작하기 때문에 주고 받는 통신을 가로챔 당할 가능성이 더 낮아지므로 보안성이 더 오르기 때문이다. 메모리 낭비를 줄이기 위해 바인더를 230kb정도의 크기로 최소화 시켰다. 바인더는 원래 PalmOS에 있던 것이기 때문에 라이센스가 있다. 약 3000라인정도 된다.
바인더는 스레드 풀을 유지한다. 드라이버, 매니저 서비스마다 바인더가 양쪽에 붙게 되는데 풀로 관리한다는 것은 요구가 있기 전에 미리 자료구조화 시켜 자원을 확보해 두고 바로 맵핑해서 쓸 수 있도록, 바인드 하는데 시간이 걸리지 않도록 되어 있다. 응용 A가 B 디바이스드라이버와 통신을 하게 되면 채널이 생성되는데 만약 채널안에 연결되는 프로그램이 A 이외에 C도 존재 한다면 B가 종료되었다고 해서 바인더가 종료되면 안된다. 이를 위해 참조계수가 있어서 참조계수가 0이 되면 바인드서비스를 해제한다.
Low Memory Killer
리소스가 부족할 때 자동으로 실행된다. 안드로이드는 그룹 당 우선순위를 주어 해당되는 그룹을 한번에 해제한다. 그룹은 참조계수랑 연관이 있다. ( 아마도 참조계수가 0 인 것들이 먼저 해제 될듯. )
아래 그림은 Low Memory Killer 소스의 일부분이다. 프로세스가 실행되면 프로세스테이블에 등록되어 관리가 된다. 메모리 부족현상이 생기면 shirink 함수가 실행되어 링크드리스트로 되어있는 프로세스컨트롤 블록들을 끝까지 탐색한다. 제거되어야 할 프로세스가 있으면 SIGKILL을 전송한다.
Power Management
기존 리눅스드라이버의 파워매니저에 계층을 하나 더 올렸다. 보통 핸드폰은 5단계를 사용한다. 키보드-액정-CPU 순으로 전원이 차단되면서 제일 마지막은 D램에만 전원을 공급하는 상태가 된다. 전원은 CPU가 아닌 PMIC라는 전원공급칩이 제어를 한다. D램에만 전원이 공급되는 상태라도 터치스크린은 잠기지 않는다. 이 상태에서 발생하는 인터럽트도 PMIC가 관리한다.
Native Libraries
기존의 라이브러리를 그대로 사용하지 않고 EABI로 빌드된 라이브러리이다. 기존의 리눅스는 PC가 모태이기 때문에, 스마트 디바이스환경을 위해 만들어진 것이 아니기 때문에 arm또는 스마트디바이스에 최적화 되어 있지 않다. 바인더가 있고 자바의 JNI를 통해 C코드와 연결되기 때문에 필수적으로 사용되는 C라이브러리 사이즈를 줄이고 효율을 더 좋게 하였다. 안드로이드의 네이티브 라이브러리는 Bionic Lib이라고 부른다. 임베디드 리눅스쪽 라이브러리를 안드로이드로 가져오면 동작하지 않는다. 대부분이 BSD 라이센스기 때문에 코드공개의 의무가 없다. 그리고 프로세스마다 로드 되므로 작은 사이즈( libc.so 사이즈 231Kb )로 되어 있고 경량 pthread가 구현되어 있다. 모든 Native 코드는 bionic과 함께 컴파일 되어야 한다. 웹킷은 오픈소스 브라우저 기반이다. 애플의 사파리, 노키아의 심비안에 이미 적용되어 성능은 검증되어 있다. 브라우저 속도가 아주 빠른것이 특징이다. HTML 표준을 따르고 Active X는 지원하지 않는다. 미디어프레임워크는 PocketVideo OpenCORE 플랫폼 기반이다. 동영상 디코딩을 하며 표준 Video, Audio, Still-frame 포맷을 지원한다. 이를 이용해 상용제품을 양산할 경우 코덱 라이센스에 대한 비용이 발생할 수 있다. SQLite 는 기본 데이터 베이스이다. Mysql과 거의 유사하다. 위치기반 서비스등을 할 때 유용하게 쓰일 수 있다.
Surface Manager는 모든 응용프로그램의 surface rendering을 프레임버퍼로 전달한다. 프레임버퍼는 LCD와 CPU속도에 차이가 있기 때문에 DRAM 또는 SRAM에 똑같은 구조를 만들어 두고 메모리 블록 전체를 복사해서 한번에 LCD에 출력한다. 이 때 그 메모리 공간을 프레임버퍼라고 한다. 기존의 임베디드리눅스는 2D, 3D를 따로 처리했지만 이 경우에는 동시에 2D, 3D를 처리한다. 화면 합성이나 결합, 반투명 효과등을 한번에 처리할 수 있다. 2D는 단일버퍼로 충분하지만 3D는 데이터량이 많아 단일버퍼로는 병목현상이 생길 수 있기 때문에 프레임버퍼를 더블프레임을 쓴다. 기존의 버퍼 사이즈를 두배로 늘려주면 된다. 더블버퍼링을 2D에도 적용하면 전경그림과 배경그림을 별도로 관리할 수 있어 오버헤드가 줄어든다.
Audio Manager는 오디오 처리를 한다. 오디로 출력 라우팅 기능이 구현되어 있다. 이전에는 OSS를 사용했는데 안드로이드에서 제대로 동작하지 않기 때문에 ALSA를 써야한다. 기본적으로 ALSA는 디폴트 볼륨이 0 으로 설정되어 있기 때문에 테스트를 하기 위해서는 init 부분에서 볼륨설정을 먼저 해줘야 한다.
Android Runtime
SUN의 자바는 명령들이 전부 8비트 길이를 가지지만 안드로이드는 4바이트이다. 기존의 SUN은 명령어가 스택에 들어가기 때문에 PUSH,POP명령어를 쓰고 Dalvik은 뱅크드레지스터를 이용한 복사명령을 이용하고 레지스터에서 바로 실행시키기 때문에 속도가 더 빠르다. 4바이트가 레지스터에 전부 들어가기 때문에 낮은사양에서도 느려지지 않는 효과도 있다. 프로그램동작은 자바코드이고 드라이버들은 대부분 C/C++이지만 그 사이에 JNI가 있기때문에 동작이 가능하다. JNI는 자바코드에서 C나 C++ 라이브러리를 호출할 수 있도록 만들어진 규약이다. 안드로이드에서 응용프로그램은 C/C++로도 만들 수 있다. 대신 UI를 가지기는 힘들다. 백그라운드 서비스를 제작할 경우 굳이 자바로 할 필요는 없다.
HAL ( Hardware Abstraction Layer )
예전에는 하드웨어 드라이버를 하드웨어 제작자가 만들었지만 요즘은 추상계층을 두어 상위 드라이버나 하위 네이티브 드라이버를 서로 독립적으로 개발할 수 있고 응용프로그램도 독립적으로 동작할 수 있다. 이는 일관된 함수 이름과 형식이 있기때문에 가능하다. 개발자가 구현하기 쉽게 표준화된 API들이 존재하며 모든 제조사가 자신의 컴포넌트를 안드로이드 플랫폼에 넣을 수 있도록 구성되었다. HAL은 라이센스문제를 피하고 안정성을 위해 유저스페이스에 존재한다.
Application Framework
액티비티 매니저는 응용프로그램의 생명주기를 담당한다. 패키지 매니저는 시스템에서 동작중인 응용프로그램들의 정보를 담당한다. 윈도우 매니저는 모든 응용프로그램과 관련된 화면을 담당한다. 뷰 시스템은 표준 위젯을 담당한다. 처음 바탕화면이 위젯이다. 윈도우는 dll 파일이 많지만 안드로이드는 하나의 패키지 파일로 되어있어 프로그램 배포가 쉽다.
Bootup Sequence
리눅스는 기본적으로 init이 가장먼저 실행된다. init.rc 라는 이름의 파일에는 init이 해야할 작업들이 기록되어 있다. 파일시스템 마운팅, 폴더 권한설정, 캐시폴더 삭제, 시작프로그램 동작 등이 기록되어 있다. 우선 데몬을 올린다. 데몬은 init에 의해 리눅스와 같이 시작되었다가 리눅스가 종료될 때 없어지는 프로그램으로서 데몬을 작성하는 규격에 따라 만들어져야 한다. Zygote가 Dalvik을 초기화 한다. C 밑에 있는 기본라이브러리들은 런타임을 통해 실행되고 상위 서비스들은 Dalvik을 통해 실행된다. 이러한 과정들을 위한 설정은 해당하는 config 파일을 수정하면 된다. 어떤 동작들을 바꾸고 싶으면 기본적으로 init.rc를 바꾸면 되고 Zygote를 바꾸고 싶으면 그 설정파일을 바꾸면 된다. 그리고 시스템서버, 서페이스매니저, 오디오매니저들이 올라간다. 그 다음에는 시스템 서비스들이 활성화 된다. 이들은 서비스이므로 서비스매니저에 등록된다.
Bootup Sequence - Zygote
Zygote가 실행되면 시스템 서비스가 활성화 된다. 응용프로그램에서는 android.process.* 을 가지고 접근할 수있다. Zygote와 시스템서버간에는 IPC 소켓으로( 127.0.0.x ) 통신을 한다.
< 부팅 완료 후 각 프로세스들의 상태 >
Android Internals Reference
http://code.google.com/intl/ko/android/
http://groups.google.com/group/android-internals
http://www.android-internals.org/
http://groups.google.com/groups/profile?enc_user=_EKOshMAAADzFnauhYxa0ga8JtF8CI5fWMj6vob75xS36mXc24h6ww
http://groups.google.com/groups/profile?enc_user=lYDbNxEAAAD8uJiqPP7Wd-bc9b1O3waCkdEasx1kiYTQavV7mdW13Q
이 경우 해결하기 위한 방법은 아래 2가지가 있음.
1. android.jar에서 필요로 하는 class들이 없는 경우 full source빌드후 생성된 class파일을 강제로 android.jar파일에 추가한뒤 이클립스에서 빌드하면 됨.
2. http://source.android.com/using-eclipse 에 따르는 방법.
http://andrwj.blogspot.com/2009/05/howto-cupcake-kernel-2627-on-virtua.html
HOWTO: Cupcake (kernel 2.6.27) on VirtualBox 2.2.2
Cupcake (kernel 2.6.27) on VirtualBox 2.2.2
2009.5.19 REV#002
Andrew J. Kim<andrwj@gmail.com>
$ sudo su
# apt-get install ssh flex bison gperf libsdl-dev libesd0-devlibwxgtk2.6-dev build-essential zip curl valgrind sun-java6-jdk git-core gnupg zlib1g-dev libncurses5-dev
# curl http://android.git.kernel.org/repo > /usr/local/bin/repo
# chmod +x /usr/local/bin/repo
# mkdir -p /home/aj/eeePC
# cd /home/aj/eeePC
# repo init -u git://android.git.kernel.org/platform/manifest.git -b cupcake
# repo sync
# cd .repo
# vim local_manifest.xml
# repo sync
x86 patch
# cd /home/aj/
# mkdir android.patch
# cd android.patch
(download all patches from http://code.google.com/p/patch-hosting-for-android-x86-support/downloads/list)
# vim frameworks_v2.patch (insert at first row)
index 30da83e..4d9a11a 100644
--- a/core/java/android/view/RawInputEvent.java
+++ a/core/java/android/view/RawInputEvent.java
# cd /home/aj/eeePC
# vim patch.sh
for patch in `pwd`/android.patch/*.patch ; do
project=`awk '/^project /{print $2}' $patch`
if [[ "$project" == "" ]]; then
echo "not found"
else
(cd $project && patch -p1 < $patch)
fi
done
# chmod +x patch.sh
# ./patch.sh
# vim vendor/asus/eee_701/eee_701.mk
(modify as .. )
$(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk)
SquashFS kernel patch
# cd /home/aj/
(download squashfs from http://nchc.dl.sourceforge.net/sourceforge/squashfs/squashfs3.4.tar.gz)
# tar xvfz squashfs4.0.tar.gz
# cd eeePC/
# patch -p1 < /home/aj/squashfs4.0/kernel-patches/linux-2.6.27-rc4/squashfs3.4-patch
AUFS kernel patch (DOT NOT apply)
참조사이트: http://aufs.sourceforge.net/
# cd /home/aj/
# git clone http://git.c3sl.ufpr.br/pub/scm/aufs/aufs2-standalone.git aufs2-standalone.git
# cd /home/aj/eeePC/kernel
# patch -p1 < /home/aj/aufs2-standalone.git/aufs2-standalone.patch
# vim fs/Makefile (#126 line, add)
kernel config
# cd /home/aj/eeePC
# cp vendor/asus/eee_701/kernel.config kernel/.config
# cd kernel
# make menuconfig
building Android ...
# cd /home/aj/eeePC/
# TAGET_ARCH=x86 TARGET_PRODUCT=eee_701 DISABLE_DEXPREOPT=true make -j2 droid
# cd /home/aj/eeePC/out/target/product/eee_701/
# /home/aj/eeePC/vendor/asus/eee_701/make_boot_img.sh
# VBoxManage convertfromraw --format VDI installed.img eee701.vdi
Screenshot
playToEnd() function in CodecTest.java .
public static boolean playToEnd(String filePath){
Log.v(TAG, "shortMediaStop - " + filePath);
//This test is only for the short media file
int duration = 200000;
int updateDuration = 0;
int currentPosition = 0;
boolean isPlaying = false;
MediaPlayer mp = new MediaPlayer();
try{
Thread.sleep(5000);
mp.setDataSource(filePath);
Log.v(TAG, "start playback");
mp.prepare();
//duration = mp.getDuration();
mp.start();
Thread.sleep(50000);
}catch (Exception e){}
isPlaying = mp.isPlaying();
currentPosition = mp.getCurrentPosition();
//updateDuration = mp.getDuration();
Log.v(TAG, "seekToEnd currentPosition= " + currentPosition + " isPlaying = " + isPlaying);
mp.stop();
mp.release();
//Log.v(TAG, "duration = " + duration);
//Log.v(TAG, "Update duration = " + updateDuration);
if (currentPosition > duration || isPlaying)
return false;
else
return true;
}
public static boolean seektoBeforeStart(String filePath){
Log.v(TAG, "seektoBeforeStart - " + filePath);
//This test is only for the short media file
int duration = 0;
int currentPosition = 0;
MediaPlayer mp = new MediaPlayer();
try{
mp.setDataSource(filePath);
mp.prepare();
duration = mp.getDuration();
mp.seekTo(duration - 10000);
mp.start();
currentPosition=mp.getCurrentPosition();
mp.stop();
mp.release();
}catch (Exception e){}
if (currentPosition < duration/2)
return false;
else
return true;
}
switch (Media) {
case LOCAL_VIDEO:
/*
* TODO: Set the path variable to a local media file path.
*/
//path = "sdcard/[PV] YUI - SUMMER SONG.avi"; // failed
//path = "sdcard/2008-01-11 02_01_00.3gp"; // ok
//path = "sdcard/FighterPilot_H264_720_480_30fps_4.1Mbps_AAC256Q100.mp4"; // fail
//path = "sdcard/leekunho_goal6.mp4"; // ok : frame skip
//path = "sdcard/Qpang.avi"; // fail
path = "sdcard/[M35_700]sample.avi"; // fail
if (path == "") {
// Tell the user to provide a media file URL.
Toast
.makeText(
MediaPlayerDemo_Video.this,
"Please edit MediaPlayerDemo_Video Activity, "
+ "and set the path variable to your media file path."
+ " Your media file must be stored on sdcard.",
Toast.LENGTH_LONG).show();
}
break;
case STREAM_VIDEO:
/*
* TODO: Set path variable to progressive streamable mp4 or
* 3gpp format URL. Http protocol should be used.
* Mediaplayer can only play "progressive streamable
* contents" which basically means: 1. the movie atom has to
* precede all the media data atoms. 2. The clip has to be
* reasonably interleaved.
*
*/
path = "";
if (path == "") {
// Tell the user to provide a media file URL.
Toast
.makeText(
MediaPlayerDemo_Video.this,
"Please edit MediaPlayerDemo_Video Activity,"
+ " and set the path variable to your media file URL.",
Toast.LENGTH_LONG).show();
}
break;
}
// Create a new media player and set the listeners
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(path);
mMediaPlayer.setDisplay(holder);
mMediaPlayer.prepare();
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
MediaPlayer
-> setDataSource(path) : URI로 content의 path가 전달 -> MediaPlayer service로부터 해당 path로 IMediaPlayer생성 -> 생성된 IMediaPlayer내부에 유지
-> prepare()
-> prepareAsync_I()
-> setAudioStreamType() : 생성된 IMediaPlayer의 setAudioStreamType()임
in IMediaPlayer.cpp
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
data.writeInt32(type);
remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply);
return reply.readInt32();
}
in IMediaPlayer.cpp
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
remote()->transact(PREPARE_ASYNC, data, &reply);
return reply.readInt32();
}
if (mPrepareSync) {
mSignal.wait(mLock); // wait for prepare done
mPrepareSync = false;
}
-> start()
아래의 사이트에 접속하여 Cross-compiler 를 설치한다.
http://www.codesourcery.com/gnu_toolchains/arm/download.html
2. 간단한 helloandroid.c 를 작성한다.
#include <stdio.h>3. Cross Compile을 통해 ARM GNU/Linux 용 Application을 만든다.
int main(int argc, char** argv)
{
printf("Hello Android !n");
return 0;
}
> arm-none-linux-gnueabi-gcc -static helloandroid.c -o helloandroid4. Android Device에 해당 애플리케이션을 Upload 한 후, 실행한다. > adb push helloandroid data/helloandroid
(주의: -static option을 필요 사용할 것.)
> adb shell
# chmod 755 data/helloandroid
# data/helloandroid
Hello Android ! <- 실행 결과
#
1.1버전과 1.5버전을 모두 지원하고 google api도 분리하였다.
따라서 3가지 AVD가 존재하며 eclipse plugin을 사용하려면 AVD를 모두 생성해주어야 한다.
> android list avds
Available Android Virtual Devices:
> android list targets
Available Android targets:
id: 1
Name: Android 1.1
Type: Platform
API level: 2
Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
id: 2
Name: Android 1.5
Type: Platform
API level: 3
Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
id: 3
Name: Google APIs
Type: Add-On
Vendor: Google Inc.
Description: Android + Google APIs
Based on Android 1.5 (API level 3)
Libraries:
* com.google.android.maps (maps.jar)
API for Google Maps
Skins: QVGA-P, HVGA-L, HVGA (default), QVGA-L, HVGA-P
> android create avd --name sdk1.1 --target 1
> android create avd --name sdk1.5 --target 2
> android create avd --name sdk1.5map --target 3
> emulator @sdk1.5
Reference : http://www.taosoftware.co.jp/blog/2009/04/android_sdk15_emulator.html
1. 안드로이드 SDK 설치.
먼저 아래의 URL에서 안드로이드 SDK를 다운로드 한 후, 원하는 디렉토리에 설치(압축해제) 합니다.
http://code.google.com/android/download.html
2008년 11월 현재시점에서 배포되고 있는 안드로이드 SDK는 다음과 같습니다.
Platform |
Package |
Size |
MD5 Checksum |
Windows | android-sdk-windows-1.1_r1.zip | 86038515 bytes | 8c4b9080b430025370689e03d20842f3 |
Mac OS X (intel) | android-sdk-mac_x86-1.1_r1.zip | 79046151 bytes | 8c4b9080b430025370689e03d20842f3 |
Linux (i386) | android-sdk-linux_x86-1.1_r1.zip | 79345522 bytes | 8c4b9080b430025370689e03d20842f3 |
2. Java Development Kit (JDK) 설치
아래의 URL에서 JDK 5 또는 JDK 6 을 설치합니다.
http://java.sun.com/javase/downloads/index.jsp
위의 2009년 1월 20일 현재 배포되고 있는 Java SE Development Kit (JDK) 6 Update 11을 설치하시면 됩니다.
(주의사항 : 안드로이드 개발을 위해서는 JRE(Java Runtime Environment) 만 설치해서는 안되니,
필히 JDK를 설치하시기 바랍니다.)
3. 이클립스(Eclipse) 설치
아래의 URL에서 Eclipse Classic 3.4.1 (151MB) 다운로드 하여 설치합니다.
http://www.eclipse.org/downloads/
4. 안드로이드 이클립스 플러그인 Android Development Tools (ADT) 설치
- 이클립스상의 메뉴에서 Help > Software Update 를 선택합니다.
- Software Update Dialog 창의 탭에서 Available Software를 선택합니다.
- Add Site 를 클릭하신 후, https://dl-ssl.google.com/android/eclipse/ 를 입력하고 OK를 클릭합니다.
(만약, Error 메시지가 발생한다면, http://dl-ssl.google.com/android/eclipse/ 를 입력하고 OK를 클릭)
- 리스트 목록중 https://dl-ssl.google.com/android/eclipse/ 하위의 Developer Tools Check 하신 후,
Developer Tool 하위의 Android Development Tools와 Android Editor Check 도 확인하신 후,
Install 을 클릭합니다. (인스톨 과정에서 약관에 동의하신 후, Finish를 클릭합니다)
- 이클립스가 다시 실행되고 나면, 메뉴의 Window > Preferences를 선택합니다.
- Preferences Dialog 창의 왼쪽 탭에서 Android를 선택한 후,
SDK Location에 위에서 설치(압축해제)한 안드로이드 SDK의 위치를 지정한 후 Apply를 Click합니다.
5. 간단한 안드로이드 예제 애플리케이션 작성 및 실행
- 이클립스상의 메뉴에서 File > New > Android Project 를 선택합니다.
- New Android Project Dialog 창에서 아래와 같이 항목을 기입합니다.
Project name : HelloAndroid
Package name : org.kandroid.sample
Activity name : HelloAndroid
Application name : HelloAndroid
- Ctrl-F11 key를 누른 후, Run-As Dialog 창이 뜨면 Android Application을 선택한 후, OK를 클릭합니다.
( 또는 위에서 생성된 프로젝트, 즉 HelloAndroid에서 마우스 우측버튼을 누른 후,
Run-As에서 Android Application을 선택하여도 됩니다.
또한, Run-As에서 Run Configurations를 선택한 후, 다양한 실행관련 설정을 하셔도 됩니다.)
- 이제 안드로이드 에뮬레이터상에서 HelloAndroid라는 애플리케이션의 실행을 확인하실 수 있을 겁니다.
6. Eclipse에 SVN 플러그인 설치
인터넷에 존재하는 많은 안드로이드 애플리케이션 소스들이 svn 상에 존재하는 경우가 많습니다.
이를 효과적으로 활용하기 위해선, svn 플러그인을 설치하는 것이 바람직합니다.
- 이클립스상의 메뉴에서 Help > Software Update 를 선택합니다.
- Software Update Dialog 창의 탭에서 Available Software를 선택합니다.
- Add Site 를 클릭하신 후, http://subclipse.tigris.org/update_1.0.x 를 입력한 후 OK를 클릭합니다.
- 리스트 목록중 http://subclipse.tigris.org/update_1.0.x 하위의 Subclipse Plugin을 Check 하신 후,
Subclipse Plugin 하위의 목록중 상위버전 하나만을 Check 하신 후,
Install 을 클릭합니다. (인스톨 과정에서 약관에 동의하신 후, Finish를 클릭합니다)
- 이클립스가 다시 실행됩니다.
- 이클립스상의 메뉴에서 Window > Open Perspective > Others를 클릭합니다.
- Open Perspective Dialog 창에서 SVN Repository Exploring 을 선택합니다.
- SVN Repository 와 SVN Annotate Tab 하단이 아이콘 중 SVN+(Add SVN Repository)을 클릭하신 후,
새로운 SVN Repository URL을 등록하셔서 사용할 수 있습니다.