스터디 5주차 / 6장
06 안드로이드 서비스 개요
안드로이드에서 서비스는 UI 없이 주기적으로 특정한 일을 수행하는 백그라운드 프로세스.
사용자와의 상호작용 없이 다양한 데이터를 백그라운드에서 처리하는 애플리케이션을 작성할 때 활용.
안드로이드 프레임워크 또한 애플리케이션 개발에 필요한 중요 API를 시스템 서비스 형태로 지원.
6.1 예제 프로그램: 안드로이드 서비스 동작 이해
안드로이드 SDK를 내려 받으면 Samples 폴더에 애플리케이션 프로그램 작성에 필요한 다양한 샘플 코드가 있음.
ApiDemo 샘플 코드는 다양한 안드로이드 API 사용법을 설명하기 위한 간단한 애플리케이션 묶음으로 구성된 프로그램.
ApiDemo 샘플 예제의 Alarm Service 애플리케이션 실행
6.2 안드로이드 서비스 분류
시스템 서비스는 프레임워크에서 기본 제공. 애플리케이션 서비스는 애플리케이션 개발자가 Service 클래스를 상속해서 구현.
6.3 안드로이드 애플리케이션 서비스
애플리케이션 서비스
란, 안드로이드 SDK의 Service 클래스를 확장한 클래스의 인스턴스로 UI 없이 주기적으로 특정한 일을 수행하는 백그라운드 프로세스. 안드로이드 애플리케이션 컴포넌트의 일종.
애플리케이션 개발자의 서비스 이용 방법
-
서비스 시작/종료: 특정 기능을 수행하는 서비스를 백그라운드로 실행/종료.
-
바인딩을 통한 서비스 원격 제어: 서비스 클라이언트가 서비스에 바인딩을 하게 되면 클라이언트는 바인딩이 유지되는 동안 서비스가 제공하는 인터페이스를 통해 서비스의 각종 기능 제어 가능.
* 바인딩: 서비스를 원격제어할 수 있게 서비스에 연결하는 것. 서비스가 제공하는 메서드 자유롭게 이용 가능.
애플리케이션이 서비스를 생성하려면 API 사용. 단순히 백그라운드에서 특정 동작을 하는 서비스를 실행하기만 하면 된다면 startService()
, 서비스에 바인딩해서 서비스가 제공하는 인터페이스를 통해 서비스를 제어하고 싶다면 bindService()
.
startService()는 서비스 시작/종료가 목적, bindService()는 서비스 원격 제어가 목적.
안드로이드 애플리케이션 서비스 생명주기
-
onCreate()
: 서비스가 처음 생성될 때 호출. 일반적으로 서비스를 초기화하는 코드 포함. -
onDestroy()
: 서비스가 종료되기 직전에 호출. 이 때 서비스가 사용한 리소스 모두 해제 해야함. -
onStartCommand(Intent, int, int)
: 오직 startService()에 의해 시작. startService()의 첫 번째 인자로 넘어온 인텐트가 이 메서드의 첫 번째 인자로 그대로 전달. 인텐트에는 주로 실행할 서비스에 대한 정보 포함. -
onBind()
: bindService()에 의해 시작. 클라이언트가 서비스에 바인딩하려고 할 때 호출. onBind() 콜백에서는 바인딩할 클라이언트를 위해 해당 서비스와 연결 가능한 객체 제공. 이 객체 통하여 서비스 원격 제어.
애플리케이션 서비스의 분류
안드로이드 애플리케이션 서비스는 서비스와 이를 생성한 서비스 클라이언트(보통 액티비티)가 동일한 프로세스에서 동작하고 있는지에 대한 여부를 기준으로 로컬 서비스 와 리모트 서비스 로 구분.
로컬 서비스
는 생성된 서비스가 자신과 동일한 프로세스에서 실행. 로컬 서비스는 자신을 생성한 애플리케이션 내에서만 사용 가능. 애플리케이션 종료 시 함꼐 종료.
리모트 서비스
는 자신을 생성한 액티비티와는 별개의 독립적인 프로세스 위에서 동작. 메인 애플리케이션 종료하더라도 계속 동작.
로컬 서비스 바인딩 은 클라이언트 프로그램이 바인딩할 로컬 서비스의 레퍼런스만 얻으면 되지만, 리모트 서비스 바인딩 은 IPC 매커니즘 중 바인더 IPC를 사용해야 함.
예제: ApiDemos의 Local Service Binding
Local Service Binding 예제는 크게 서비스를 나타내는 LocalService.java
와 서비스를 이용하는 액티비티인 LocalServiceActivies.java
로 구성.
LocalServiceActivies.java 파일에는 Controller와 Binding 두 개의 액티비티가 내부 클래스로 정의되어 있음. Binding 액티비티가 Local Service Binding 나타냄.
로컬 서비스의 바인딩 절차
(1) 액티비티에서 Bind Service 버튼을 클릭하면 doBindService()
가 호출되며, 이 메서드에서 내부적으로 bindService() API를 사용해서 LocalService 바인딩 시도. LocalServiceActivies.java에서 이루어짐.
bindService(Intent, ServiceConnection, int)
: 첫 번째 인자는 LocalService 실행을 위한 인텐트. 두 번쨰 인자는 서비스 클라이언트 측에서 서비스와의 바인딩 연결을 처리할 객체. 세 번째 인자는 플래그. 코드에서 세 번째 인자로 쓰인Context.BIND_AUTO_CREATE
는 바인딩할 서비스가 없는 경우 자동으로 서비스를 생성하게 하는 플래그. 즉, 바인딩에 앞서 LocalService 생성.
(2) 바인딩할 서비스가 생성되었으므로 안드로이드는 바인딩 처리를 위해 서비스의 onBind()
콜백 메서드를 호출하여 액티비티가 LocalService 자신과 연결할 수 있게 Binder 클래스를 확장한 LocalBinder 객체를 반환. LocalService.java에서 이루어짐.
(3) 안드로이드 프레임워크가 서비스 클라이언트 측(Binding 액티비티)의 onServiceConnected(ComponentName, IBinder)
메서드를 호출하여, LocalBinder 객체의 getService() 메서드를 호출 해서 바인딩하려고 했던 LocalService 객체의 레퍼런스 값을 구함. LocalServiceActivies.java에서 이루어짐.
(4) 구한 LocalService 객체의 레퍼런스 값을 액티비티의 mBoundService
멤버 필드에 저장하면서 서비스 바인딩 마무리.
예제: ApiDemos의 Remote Service Binding
ISecondary.aidl
은 프로세스 ID를 반환하는 getPid() 메서드가 포함된 ISecondary 인터페이스를 정의. 따라서 RemoteService를 이용하는 클라이언트 프로그램은 ISecondary 인터페이스를 통해 RemoteService가 제공하는 getPid() 함수를 이용할 수 있게 됨.
ISecondary.java
의 역할은 서비스 클라이언트와 리모트 서비스 간의 ISecondary 인터페이스에 기반한 바인더 IPC 연결을 설정하는 것.
리모트 서비스의 바인딩 절차
(1) Binding 액티비티: RemoteService와의 연결 요청.
-
로컬 서비스와 마찬가지로
bindService()
API 이용하여 서비스에 바인딩 시도. RemoteService.java에서 이루어짐. -
RemoteService 서비스가
com.example.android.apis.app.ISecondary
액션을 처리.
(2) RemoteService 서비스: 실제 서비스 메서드 기능 구현 및 서비스와 통신하기 위한 바인더 객체 제공.
/* RemoteService 서비스에 포함된 onBind() 콜백 메서드의 주요 코드
in RemoteService.java */
private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() {
public int getPid() {
return Process.myPid();
}
};
public IBinder onBind(Intent intent) {
if(ISecondary.class.getName().equals(intent.getAction())) {
return mSecondaryBinder;
}
}
-
서비스가 생성되고 나면 onCreate() 메서드와 onBind() 메서드 차례로 호출. onBind() 메서드로 바인더 IPC를 처리할 서비스 바인더 객체인
mSecondaryBinder
생성 후 시스템에 반환. -
서비스 바인더 객체는 자동으로 생성된 ISecondary.java의 ISecondary.Stub 클래스를 통해 생성. 이 때 ISecondary 인터페이스에 정의된 getPid() 메서드의 실제 코드 구현해야 함.
(3) Binding 액티비티: 서비스와 바인더 IPC를 수행하기 위한 프록시 객체 생성.
/* Binding 액티비티가 ISecondary.Stub.Proxy 서비스 프록시 객체 생성 in RemoteService.java */
private ServiceConnection mSecondaryConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// service 객체를 ISecondary.Stub.asInterface() 함수의 인자로 전달해서 호출.
// 이로써 RemoteService 서비스와 바인딩될 서비스 프록시 객체 생성.
mSecondaryService = ISecondary.Stub.asInterface(service);
}
};
- onBind() 콜백 메서드를 통해 바인딩 준비 끝나면, 연결 객체의 onServiceConnected() 콜백 메서드 호출.
(4) Binding 액티비티: 서비스 프록시 객체를 이용해서 RemoteService 서비스의 getPid() 서비스 프록시 메서드를 호출.
- 구한 서비스 프로세스를 Process.killProcess() 메서드 통하여 강제 종료.
(5) 바인더 IPC: 서비스 프록시 객체(ISecondary.Stub.Proxy)에서 서비스 바인더 객체(ISecond.Stub)로 바인더 IPC 데이터 전달.
(6) RemoteService: RemoteService 서비스의 getPid() 스텁 메서드 호출.
- 바인더 IPC 데이터를 수신한 ISecondary.Stub 서비스 바인더객체가 실제 getPid() 스텁 메서드를 호출함으로써 서비스의 프로세스 ID를 액티비티에 반환.
로컬 서비스와 리모트 서비스 생성
로컬 서비스와 리모트 서비스는 매니페스트 파일에서 구별하여 생성.
리모트 서비스 생성을 위해서는
6.4 안드로이드 시스템 서비스
안드로이드의 시스템 서비스는 디바이스 제어, 위치 정보 제공, 알람 설정 및 통지 메시지 표시 등과 같이 시스템의 가장 기본적인 핵심 기능들을 제공.
안드로이드 프레임워크에서 애플리케이션 프레임워크 레이어(코어 플랫폼 서비스 & 하드웨어 서비스) 및 라이브러리 레이어(네이티브 시스템 서비스)에 각각 존재.
시스템 서비스의 분류
네이티브 시스템 서비스
는 라이브러리 레이어에서 동작. C++ 작성. 주요 서비스는 Audio Flinger, Surface Flinger.
-
Audio Flinger 서비스 : 안드로이드 애플리케이션의 오디오 데이터를 믹싱해서 오디오 출력장치로 내보내는 역할.
-
Surface Flinger 서비스 : 다양한 애플리케이션에서 사용중인 Surface로 조합해 프레임 버퍼 장치로 렌더링.
자바 시스템 서비스
는 안드로이드 부팅 시 SystemServer라는 시스템 프로세스에 의해 일괄적으로 실행. 코어 플랫폼 서비스와 하드웨어 서비스로 나뉨.
-
코어 플랫폼 서비스 : 안드로이드 프레임워크가 동작하는 데 필수적인 서비스. 주요 서비스는 Activity Manager Service, Window Manager Service, Package Manager Service.
-
하드웨어 서비스 : 저수준 하드웨어 제어를 위한 API를 제공하는 서비스. 주요 서비스는 Alarm Manager Service, Location Service 등.
프레임워크 내부에서나 안드로이드 애플리케이션에서 자바 시스템 서비스를 이용하려면 각 서비스와 통신 가능한 Local Manager 객체 필요.
6.5 시스템 서비스의 실행
시스템 서비스는 애플리케이션 서비스와 달리 서비스를 직접 실행할 필요가 없이 getSystemService()
를 이용해서 바로 이용 가능.
시스템 서비스는 안드로이드가 부팅할 때 Media Server
와 System Server
라는 두 시스템 프로세스에 의해 실행.
-
Media Server : Surface Flinger를 제외한 네이티브 서비스 실행.
-
System Server : Zygote에 의해 맨 처음 생성되는 자바 기반의 프로세스. Surface Flinger를 비롯한 모든 자바 시스템 서비스 실행.
부팅 시 안드로이드 시스템 서비스의 생성 과정
미디어 서버(Media Server)의 실행 코드
(1) 미디어 서버는 init 프로세스에 의해 실행.
(2) 미디어 서버에 포함된 main() 함수에서 각 네이티브 서비스에 대한 인스턴스를 생성하고 초기화하는 작업을 수행.
시스템 서비스는 프레임워크 내에서 다른 모듈과 통신할 때 바인더 IPC 사용.
시스템 서비스와 같은 서비스 제공자는 안드로이드의 일반 애플리케이션과 같은 서비스 이용자가 자신의 서비스를 이용할 수 있게 해당 서비스 제공자의 정보를 컨텍스트 매니저
에 등록.
(3) 각 시스템 서비스별 초기화.
// Audio Flinger 초기화 코드
// frameworks/base/libs/audio?inger/AudioFlinger.cpp
voi AudioFlinger::instantiate() {
defaultServiceManager()->addService(
String16("media.audio_?inger"), new AudioFlinger());
}
// MediaPlayerService, CameraService, AudioPolicyService 도 동일한 방식으로 초기화.
-
new 연산자를 통해 서비스 인스턴스를 생성 후, addService() 함수를 이용해서 컨텍스트 매니저에게 각 서비스를 등록.
-
defaultServiceManager()
함수는 컨텍스트 매니저와 바인더 통신을 하는 일종의 프록시 객체인 서비스 매니저 반환. -
컨텍스트 매니저의 기능을 이용하려면 서비스 매니저 이용해야함.
미디어 서버 프로세스의 시스템 서비스 실행 과정
시스템 서버(System Server)의 실행코드
(1) Zygote 프로세스로부터 생성
(2) android_servers 라이브러리 로드
-
main() 메서드의 기능은
android_servers 라이브러리
를 로드하고 JNI를 통해 system_init() 네이티브 함수를 호출하는init1()
메서드를 호출하는 것. -
system_init()
: Surface Flinger 네이티브 시스템 서비스를 초기화 및 실행. -
Surface Flinger
서비스를 실행하고 나면 runtime->callStatic(“com/android/server/SystemServer”, “init2”)를 호출해서 SystemServer 클래스의 init2() 호출.
(3) 자바 시스템 서비스 초기화 및 등록
-
호출된
init2()
메서드는 Entropy 서비스부터 AppWidget 서비스까지 안드로이드의 모든 자바 시스템 서비스를 생성하고 초기화. -
init2() 메서드에서는 안드로이드의 모든 자바 시스템 서비스를 실행하는 자바 스레드인
ServerThread
를 생성 후 실행. -
실행된 자바 시스템 서비스를 ServiceManager 클래스의 addService() 정적 메서드를 이용해서 컨텍스트 매니저에 등록.
시스템 서버 프로세스의 시스템 서비스 실행 과정
6.6 안드로이드 서비스 프레임워크와 바인더 드라이버 개요 및 용어 정리
안드로이드 시스템 서비스의 동작 원리는 서비스 사용자가 미리 약속된 인터페이스에 따라 시스템 서비스에서 제공하는 함수를 원격으로 호출해서 해당 기능을 이용하는 것.
안드로이드는 복잡한 RPC 매커니즘을 개발자들이 쉽게 이용할 수 있게 만들기 위해 잘 설계된 서비스 프레임워크와 바인더 드라이버 제공.
-
컨텍스트 매니저
: 시스템 서비스를 관리하는 안드로이드 시스템 프로세스. -
서비스
: 서비스 인터페이스에 정의된 기능을 섭스 스텁 함수로 구현해서 실제 서비스의 기능을 제공하는 모듈. -
RPC 수행 시 데이터 마샬링을 수행하는 객체는
서비스 프록시
, 데이터 언마샬링을 수행하는 객체는서비스 스텁
. -
바인더 IPC
: 안드로이드에서 바인더 드라이버를 통한 프로세스 간의 데이터 전달 방식.
안드로이드 시스템 서비스 동작 구조