스터디 8주차 week08
실제 자바 시스템 서비스 코드인 액티비티 매니저 서비스를 통해 자바 시스템 서비스가 안드로이드 프레임워크 내에 어떻게 동작하는지에 대해 구체적으로 알아본다.
11.1 액티비티 매니저 서비스
액티비티 매니저 서비스는 자바 시스템 서비스의 일종인 코어 플랫폼 서비스.
안드로이드 애플리케이션 컴포넌트인 액티비티, 서비스, 브로드캐스트 리시버 등을 생성하고, 이들의 생명주기를 관리.
액티비티 매니저 서비스가 안드로이드의 애플리케이션 서비스를 어떻게 생성하고 해당 서비스의 생명주기를 어떻게 제어하는지, 그리고 이를 위해 애플리케이션 서비스의 실행을 요청한 애플리케이션 프로세스와 액티비티 매니저 서비스가 어떻게 상호작용하는지 알아보자. - Remote Service Controller 애플리케이션 예제
-
RemoteService는 애플리케이션과 독립된 프로세스에서 동작하는 리모트 애플리케이션 서비스.
-
애플리케이션에서 서비스를 실행하는 경우 액티비티 매니저 서비스가 애플리케이션에서 요청한 RemoteService를 실행하는 역할을 한다.
-
startService()
API를 통해 애플리케이션 서비스 생성. -
애플리케이션으로부터 startService()를 통해 서비스 실행 요청을 받은 액티비티 매니저 서비스는 요청받은 서비스 클래스(RemoteService.class) 로드 전 Zygote에게 서비스를 실행시키기 위한
ActivityThread
생성을 요청. -
액티비티 매니저 서비스로부터 ActivityThread 실행을 요청받은 Zygote는 새로운 프로세스를 생성 후 그 위에 ActivityThread 클래스 로딩.
-
액티비티 매니저는 생성된 ActivityThread에게 RemoteService 서비스의 생성을 요청.
-
ActivityThread는 RemoteService 실행.
11.2 액티비티 매니저 서비스를 통한 서비스 생성코드 분석
액티비티가 startService() API 메서드를 호출할 경우 액티비티 매니저 서비스가 어떻게 애플리케이션 서비스를 생성하는지 소스코드를 바탕으로 살펴본다.
11.2.1 Controller 액티비티 - startService() 메서드 호출
‘Start Service’ 버튼을 누르면 mStartListener 이벤트 핸들러가 호출되고, 이는 REMOTE_SERVICE 액션을 지정한 암시적인 인텐트를 인자로 startService() API 메서드를 호출.
11.2.2 액티비티 매니저 서비스의 startService() 메서드 호출 과정(바인더 RPC 활용)
액티비티에서 호출한 startService() API는 서비스 생성 및 실행과 관련된 내용을 액티비티 매니저 서비스에 요청하는 기능만 수행할 뿐 실제 구현은 액티비티 매니저 서비스에 속한, 동일한 이름을 가진 startService()
스텁 메서드에 들어있다.
즉, 액티비티에서 호출한 startService() API는 자바 서비스 프레임워크 기반에서 바인더 RPC 형태로 액티비티 매니저 서비스에서 제공하는 startService() 스텁 메서드를 호출.
-
Controller 액티비티: ActivityManagerProxy 객체의 startService() 프록시 메서드를 호출.
-
ActivityManagerProxy 객체: 자바 서비스 프레임워크를 통해 ActivityManagerNative 객체에 START_SERVICE_TRANSACTION RPC 코드와 바인더 RPC 데이터 전송.
-
ActivityManagerNative 객체: ActivityManagerService에 포함된 startService() 스텁 메서드를 호출.
(1) Controller 액티비티
-
액티비티에서 startService() API를 호출하면 Activity 클래스가 상속하는
ContextWrapper
클래스의 startService() 호출. -
ContextWrapper는 Context 추상 클래스를 확장한 클래스로, 멤버 변수 mBase에 저장된 Context 객체를 래핑(wrapping)하는 역할.
-
현재 ContextWrapper 객체는 Controller 액티비티의 ContextImpl 객체를 래핑. 즉, ContextWrapper의 startService() 메서드는 ContextImpl 객체의 startService()를 호출.
-
ContextImpl 클래스는 startService() 메서드를 처리.
-
ContextImpl
은 Context 추상 클래스를 실제 구현한 클래스로서 애플리케이션 자체의 리소스 접근, 액티비티나 애플리케이션 서비스 실행, 인텐트 송수신 등의 역할을 수행. -
ActivityManagerNative.getDefalut()
함수는ActivityManagerProxy
객체를 반환. 이 객체는 액티비티 매니저 서비스가 제공하는 IActivityManager 서비스 인터페이스 기반의 메서드들을 바인더 RPC를 통해서 호출하는 역할. -
ActivityManagerNative.getDefalut().startService()
메서드는 ActivityManagerProxy 클래스의 startService() 프록시 메서드 호출. ActivityManagerProxy 클래스의 startService() 는 ActivityManagerService의 startService() 스텁 메서드를 원격으로 호출.
(2) ActivityManagerProxy 객체 - startService() 프록시 메서드 처리
-
mRemote.transact()
메서드는 자바 객체에서 바인더 RPC 데이터를 전송하는데 사용. -
ActivityManagerProxy 객체는 startService() 프록시 메서드의 인자로 전달된 caller, service, resolvedType에 들어 있는 값을 바인더 RPC 데이터를 저장하는 데 사용되는 Parcel 객체 변수인 data에 저장.
-
START_SERVICE_TRANSACTION 트랜잭션을 통해 저장한 data 값을 ActivityManagerNative 객체에 전달.
(3) ActivityManagerNative 객체 - startService() 스텁 메서드 호출
앞서 수신된 바인더 RPC 데이터는 ActivityManagerNative 객체의 onTransact()
메서드에서 처리.
ActivityManagerNative 객체는 전달받은 RPC 코드를 토대로 액티비티 매니저 서비스에서 호출할 스텁 메서드를 파악. 여기서는 startService() 스텁 메서드가 호출되어야 한다.
다음으로 startService() 스텁 메서드에 전달해야 할 인자를 구해서 startService() 스텁 메서드를 실제로 호출.
-
onTransact()
메서드의 역할은 ActivityManagerProxy의 startService() 프록시 메서드의 인자 값이 마샬링된 data 변수를 바인더 RPC를 통해 수신한 다음, data 변수를 언마샬링하고 각 데이터를 별도의 변수에 저장하는 것. -
그러고 나서 저장된 변수를 인자로 삼아 액티비티 매니저 서비스의 startService() 스텁 메서드를 호출.
11.2.3 액티비티 매니저 서비스 - startService() 스텁 메서드 실행
지금까지 액티비티가 액티비티 매니저 서비스에게 실행할 서비스의 정보를 전달하는 과정에 대해 설명했다면, 이제는 액티비티 매니저 서비스가 요청받은 서비스를 어떻게 실행하는지 살펴본다.
-
startServiceLocked() 메서드를 호출. 이 때 전달되는 첫 번째 인자인 caller에는 액티비티 매니저 서비스가 IAplicationThread 서비스 인터페이스 기반의 바인더 RPC를 통해 Controller 액티비티를 제어할 수 있도록 생성된
ApplicationThreadProxy
객체가 전달. -
그 다음으로는 생성한 서비스 정보를 지닌 인텐트가 포함된 service 인자를 비롯해서 서비스 생성을 요청한 프로세스의 pid와 uid 값을 추가로 전달.
-
startServiceLocked()
메서드의 주요 역할은 실행할 서비스와 관련된 ServiceRecord 값을 얻는 것. ServiceRecord는 안드로이드 애플리케이션 서비스에 대한 각종 정보가 담긴 클래스. -
startServiceLocked() 메서드는
retrieveServiceLocked()
메서드에 인텐트를 전달하여 서비스에 대한 정보를 얻는다. 이는 암시적인 인텐트를 처리하기에 가장 적합한 서비스를 찾고, 그 정보는 ServiceRecord에 기록된다.
-
bringUpServiceLocked()
메서드는 우선 인자로 전달된 ServiceRecord 객체를 참조해서 RemoteService가 실행될 프로세스 이름과 uid를 통해 ProcessRecord 객체가 이미 존재하는 지 검색.getProcessRecordLocked()
이용. -
ProcessRecord
는 현재 동작중인 특정 프로세스에 관한 대부분의 정보를 포함하고 있는 클래스. -
서비스를 실행할 프로세스가 생성되지 않아있기에 app 변수 값이 NULL 이므로
startProcessLocked()
메서드 실행. -
액티비티 매니저 서비스가 추후에 새로 생성된 프로세스에게 RemoteService의 실행을 요청하기 위해 mPendingServices 배열에 ServiceRecord 객체 저장. 액티비티 매니저는 이 객체를 통해 서비스를 실행할 수 있게 된다.
11.2.4 ActivityThread 클래스의 main() 메서드 실행
Zygote가 서비스 실행을 위해 액티비티 매니저 서비스가 요청한 ActivityThread 클래스를 새로운 프로세스 상에서 어떻게 실행하는지 알아본다.
-
main() 메서드의 동작을 간단히 살펴보면 우선 동일한 프로세스 내의 스레드 간 메시지 통신을 위해
Looper.prepareMainLooper()
메서드를 이용해서 메시지 큐를 생성.* 메시지 큐는 동일 프로세스 안에서 여러 스레드 간에 메시지를 전달하는데 사용.
-
메시지 큐를 생성한 다음
ActivityThread
객체 생성. 이 객체는 액티비티 매니저 서비스와의 상호작용을 통해 안드로이드 애프리케이션 프로세스의 메인 스레드 실행 및 액티비티 스케줄링 등을 수행.
ActivityThread가 생성되고 나면 이 객체의 attach()
메서드를 호출.
-
ActivityThread: ActivityManagerProxy 객체의 attachApplication() 프록시 메서드 호출.
-
ActivityManagerProxy 객체: ActivityManagerNative 객체에 ATTACH_APPLICATION_TRANSACTION RPC 코드와 바인더 RPC 데이터 전송.
-
ActivityManagerNative 객체: ActivityManagerService에 포함된 attachApplication() 스텁 메서드 호출.
(1) ActivityThread 객체 - attachApplication() 프록시 메서드 호출
attach() 메서드의 주요 기능은 ActivityThread와 액티비티 매니저 서비스 간에 IActivityManager 인터페이스 기반의 바인더 RPC를 위한 연결을 설정하는 것.
- mgr 변수: ActivityManagerProxy 객체.
(2) ActivityManagerProxy 객체
(3) ActivityManagerNative 객체 - attachApplication() 스텁 메서드 호출
- ActivityThread가 보낸 ATTACH_APPLICATION_TRANSACTION RPC 코드와 바인더 RPC 데이터는 ActivityManagerNative 객체의 onTransact() 메서드를 통해 처리. (
ApplicationThreadProxy
객체 생성)
정리하면 ActivityThread 객체는 attach() 메서드를 통해 액티비티 매니저 서비스가 자신을 제어할 수 있도록 바인더 RPC 연결을 설정.
11.2.5 액티비티 매니저 서비스 - attachApplication() 스텁 메서드 처리
액티비티 매니저 서비스가 바인더 RPC를 통해 ActivityThread에게 생성할 서비스 정보를 넘겨 실제 RemoteService를 실행하는 과정.
(1) 액티비티 매니저 서비스: scheduleCreateService() 프록시 메서드 호출.
- ProcessRecord와 ServiceRecord 값을 realStartServiceLocked() 메서드로 전달. 이 메서드가 내부적으로 app.thread.scheduleCreateService() 메서드를 호출.
(2) ActivityManagerProxy 객체: ActivityThread의 ActivityManagerNative 객체에 SCHEDULE_CREATE_SERVICE_TRANSACTION RPC 코드와 바인더 RPC 데이터 전송.
(3) ActivityManagerNative 객체: ApplicationCreateService의 ApplicationThread 객체에 포함된 scheduleCreateService() 스텁 메서드 호출.
(4) ApplicationThread 객체: ApplicationCreateService의 ActivityThread에 메시지큐를 이용해 CREATE_SERVICE 메시지 전달.
(5) ActivityThread 객체: RemoteService 서비스 생성 및 서비스 생명주기에 따른 onCreate() 호출.
11.3 정리
(1) Controller 액티비티는 RemoteService 서비스를 실행하기 위해 startService API를 통해 액티비티 매니저 서비스에 RemoteService 서비스 실행을 요청.
(2) 요청받은 서비스가 리모트 서비스인 겨우 액티비티 매니저 서비스는 Zygote에게 서비스를 별도의 독립 프로세스로 실행시키기 위해 ActivityThread 생성을 요청.
(3) Zygote에 의해 생성된 ActivityThread는 attachApplication() 프록시 메서드를 통해 액티비티 매니저 서비스에게 자신을 등록. 이를 통해 액티비티 매니저 서비스는 생성된 ActivityThread를 제어 가능.
(4) 액티비티 매니저 서비스는 (1)에서 요청받은 RemoteService 생성을 ActivityThread에 요청.
(5) ActivityThread는 요청했던 RemoteService 서비스의 인스턴스를 생성한 다음 이 서비스의 onCreate() 콜백 함수를 호출.