• 자바 시스템 서비스가 안드로이드 프레임워크 내에서 어떻게 동작하는가

    액티비티 매니저 서비스

  • 액티비티 매니저 서비스: 자바 시스템 서비스이며, 안드로이드 애플리케이션 컴포넌트(액티비티, 서비스, 브로드캐스트 리시버 등)를 생성하고, 이들의 생명주기를 관리한다
  • 애플리케이션 서비스의 실행을 요청한 애플리케이션 프로세스와 액티비티 매니저 서비스가 어떻게 상호작용하는가
  • Remot Service Controller 예제 애플리케이션: ‘Start Service’ 버튼을 누르면 Remote Servcie가 시작되는 프로그램
    • 애플리케이션에서 서비스를 실행하면, 액티비티 매니저 서비스가 애플리케이션에서 요청한 서비스를 실행한다
  • 액티비티 매니저 서비스가 어떻게 RemoteService를 실행할까?
    • RemoteService는 애플리케이션과 독립된 프로세스에서 동작하는 리모트 애플리케이션 서비스이다. 따라서 서비스를 실행하기 위해서는 우선 새로운 프로세스를 실행해야한다.
    • 액티비티 매니저 서비스는 Zygote를 이용해 서비스를 실행할 프로세스를 생성한 후, 프로세스 상에서 애플리케이션이 요청한 RemoteService를 실행한다.
  • 구체적인 과정
    (1) startService() API를 통해 서비스 시작 요청(바인더 RPC 이용) (‘Start Service’버튼 누르고, ActivityManagerService에게)
    애플리케이션은 startService()나 bindService() API를 통해 애플리케이션 서비스를 생성한다.
    (2) ActivityThread 생성 요청 (Unix Domain Socket 이용) (AcitivityManagerService에서 Zygote로)
    애플리케이션으로부터 startService()를 통해 서비스 실행요청을 받은 액티비티 매니저 서비스는 요청받은 서비스 클래스를 실행하기 위한 ActivityThread 생성요청을 Zygote에게 한다.
    (ActivityThread: 모든 안드로이드 애플리케이션의 메인 스레드, 액티비티 및 서비스의 생성 및 스케줄링을 담당)
    (3) ActivityThread 생성 (Zygote에서 ActivityThread로)
    액티비티 매니저 서비스로부터 ActivityThread 실행을 요청받은 Zygote는 새로운 프로세스를 생성한 다음 그 위에 ActivityThread 클래스를 로딩한다
    (4) RemoteService 생성 요청 (바인더 RPC 이용) (ActivityManagerService에서 ActivityThread로)
    액티비티 매니저 서비스는 ActivityThread에게 RemoteService 서비스의 생성을 요청한다.
    (5) RemoteService 생성
    ActivityThread는 RemoteService를 실행한다.

액티비티 매니저 서비스를 통한 서비스 생성 코드 분석

  • 액티비티 매니저 서비스가 어떻게 애플리케이션 서비스를 생성하는가

    Controller 액티비티 - startService() 메서드 호출

  • ‘Start Service’ 버튼 -> 이벤트 핸들러 호출 -> intent를 인자로 startService() API 메서드를 호출
  • 안드로이드 애플리케이션 컴포넌트는 인텐트라는 메시지를 통해 활성화된다. 안드로이드에서는 인텐트를 이용해 실행하고자 하는 서비스의 클래스명을 명시적으로 지정해서 원하는 컴포넌트를 실행할 수 있다.

    액티비티 매니저 서비스의 startService() 메서드 호출 과정(바인더 RPC 활용)

  • startService() API가 실제 안드로이드 프레임워크에서 어떻게 처리되는가
  • startService() API: 액티비티에서 호출, 액티비티 매니저 서비스에게 서비스 생성 및 실행과 관련된 내용을 요청
  • 액티비티 매니저 서비스에 속한 startService() 스텁 메서드: 실제 구현
    => startService() API는 자바 서비스 프레임워크 기반에서 바인더 RPC 형태로 액티비티 매니저 서비스에서 제공하는 startService() 스텁 메서드를 호출
  • 위의 (1)번 과정 구체화
    1. Controller Activity - ActivityManagerProxy 객체의 startService() proxy method 호출
    2. ActivityManagerProxy 객체 - 자바 서비스 프레임워크를 통해 ActivityManagerNative 객체에 START_SERVICE_TRANSACTION RPC 코드와 바인더 RPC 데이터를 전송
    3. ActivityManagerNative 객체 - ActivityManagerService에 포함된 startService() 스텁 메서드를 호출
  • 주요 소스 코드의 흐름

    (1) Controller 액티비티

    (a) ContextWrapper 클래스 - ContextImpl 객체의 startService() 메서드 호출

  • 액티비티에서 startService() API 호출 -> Activity 클래스가 상속하는 ContextWrapper 클래스의 startService()가 호출
  • ContextWrapper: Context 추상 클래스를 확장한 클래스, 멤버 변수 mBase에 저장된 Context 객체를 wrapping하는 역할
  • ContextWrapper 객체는 Controller 액티비티의 ContextImpl 객체를 래핑
    => ContextWrapper의 startService() 메서드는 결국 ContextImpl 객체의 startService를 호출한다.
    (b) ContextImpl 클래스 - startService() 메서드 처리
  • ContextImpl: Context 추상 클래스를 실제 구현한 클래스, 애플리케이션 자체의 리소스 접근, 액티비티나 애플리케이션 서비스 실행, 인텐트 송수신 등의 역할을 수행

    ActivityManagerNative.getDefault().startService() 처리 과정

  • ActivityManagerNative.getDefault() 함수는 결국 ActivityManagerProxy 객체를 반환, 이 객체는 액티비티 매니저 서비스가 제공하는 IActivityManager 서비스 인터페이스 기반의 메서드들을 바인더 RPC를 통해서 호출하는 역할을 한다.
  • ActivityManagerProxy의 startService()는 결국 ActivityManagerService의 startService() 스텁 메서드를 원격으로 호출하는 역할을 수행한다. 두 startService() 메서드는 동일한 함수 원형을 사용한다.

(2) ActivityManagerProxy 객체

  • ActivityManagerProxy 객체의 startService() 프록시 메서드가 처리하는 내용
  • ActivityManagerProxy 객체는 ActivityManagerNative 객체에 바인더 RPC 데이터를 전송하는 것이다.

(3) ActivityManagerNative 객체

  • 수신된 바인더 RPC 데이터는 ActivityManagerNative 객체의 onTransact() 메서드에서 처리
  • RPC 코드를 토대로 액티비티 매니저 서비스에서 호출할 스텁 메서드를 파악
  • onTransact() 메서드의 역할
    • ActivityManagerProxy의 startService() 프록시 메서드의 인자 값이 마샬링된 data변수(Parcel 객체)를 바인더 RPC를 통해 수신한 다음, data 변수를 언마샬링하고 각 데이터를 별도의 변수에 저장한다.
  • 액티비티는 IActivityManager 서비스 인터페이스 기반의 바인더 RPC를 통해 액티비티 매니저 서비스에게 서비스 실행이나 인텐트 송수신 등의 기능 수행을 요청할 수 있다. 반대로 액티비티 매니저 서비스는 IApplicationThread 인터페이스 기반의 바인더 RPC를 통해 자신과 연결된 애플리케이션을 제어할 수 있다.

=> Controller 액티비티가 RPC 메커니즘을 통해 액티비티 매니저 서비스의 startService() 스텁 메서드를 자신의 로컬 메서드인 것처럼 호출한 것으로 생각할 수 있다.

액티비티 매니저 서비스 - startService() 스텁 메서드 실행

  • 액티비티 매니저 서비스가 요청받은 서비스를 어떻게 실행하는가: 액티비티 매니저 서비스가 startSerice()의 스텁 메서드를 어떻게 처리하는가
  • startService() 스텁 메서드는 startServiceLocked() 메서드를 호출
  • startServiceLocked() 메서드는 실행할 서비스와 관련된 ServiceRecord 값을 얻는다.
    (ServiceRecord는 안드로이드 애플리케이션 서비스에 대한 각종 정보가 담긴 클래스이다.)
  • 이를 위해 startServiceLocked() 메서드는 retrieveServiceLocked() 메서드에 인텐트를 전달해서 서비스에 대한 정보를 얻는다
  • ServiceRecord 객체를 bringUpServiceLocked() 메서드의 첫 번째 인자로 전달
    • ServiceRecord 객체를 참조해서 해당 서비스가 실행될 프로세스 이름과 uid를 통해 ProcessRecord 객체가 이미 존자하는지 검색( getProcessRecordLocked() )
    • ProcessRecord가 이미 존재하면 로컬 서비스의 경우와 같이 서비스가 실행될 프로세스가 이미 실행 중이므로 realStartServicLocked() 메서드를 통해 해당 프로세스와 동일한 영역 내에서 서비스를 실행시킨다.
    • 액티비티 매니저 서비스가 추후에 새로 생성된 프로세스에게 RemoteService의 실행을 요청하기 위해 mPendingServices 배열에 ServiceRecord 객체를 저장, 이후 코드에서 Zygote에 의해 ActivityThread가 새로 생성된 후에 mPendingServices 배열에 저장해 놓은 ServiceRecord 객체를 통해 서비스를 실행할 수 있다.
  • ActivityManagerService 클래스 코드에는 두 개의 startProcessLocked() 메서드가 존재
    (1) 7개 인자 가짐: 리모트 서비스를 실행하기 위해 새로 생성할 프로세스 정보를 포함하는 ProcessRecord 객체를 만들고, 이를 mProcessNames 큐에 삽입, 성공적으로 끝나면 두 번째 startProcessLocked() 메서드를 호출
    (2) Process 클래스의 start() 메서드를 통해 Zygote에게 android.app.ActivityThread 프로세스 생성을 요청, Zygote에 의해 생성된 프로세스의 pid와 ProcessRecord 객체를 mPidsSelfLocked 해시에 키/값 쌍으로 저장, 액티비티 매니저 서비스는 pid 값을 통해 이와 관련된 ProcessRecord 객체 값을 해시를 통해 얻을 수 있다.

ActivityThread 클래스의 main() 메서드 실행

  • Zygote가 서비스 실행을 위해 액티비티 매니저 서비스가 요청한 ActivityThread 클래스를 새로운 프로세스 상에서 어떻게 실행하는가
  • ActivityThread 실행을 요청받은 Zygote는 새로 생성한 프로세스에 ActivityThread 클래스를 로드한 다음, ActivityThread 클래스의 main() 메서드를 호출한다.
  • ActivityThread 클래스에 포함된 main() 메서드
    • 동일한 프로세스 내의 스레드 간 메시지 통신을 위해 Looper.prepareMainLooper() 메서드를 이용해서 메시지 큐를 생성
  • ActivityThread가 생성되고 나면 이 객체의 attach() 메서드가 호출, attach() 메서드의 실질적인 처리는 attachApplication() 스텁 메서드가 담당
  • ActivityThread는 attach() 메서드를 처리하기 위해 바인더 RPC를 이용해서 액티비티 매니저 서비스가 제공하는 attachApplication() 스텁 메서드를 호출해야 한다. ActivityThread 객체는 ActivityManagerProxy를 생성한 다음 바인더 RPC를 통해 액티비티 매니저 서비스에 접근해야한다. (ActivityManagerProxy 객체는 액티비티가 액티비티 매니저 서비스에게 특정 기능을 요청할 때 사용)
    1. ActiviyThread - ActivityManagerProxy 객체의 attachApplication() 프록시 메서드를 호출
    2. ActivityManaterProxy 객체 - ActivityManagerNative 객체에 ATTACH_APPLICATION_TRANSACTION RPC 코드와 바인더 RPC 데이터를 전송
    3. ActivityManagerNative 객체 - ActiviyManagerService에 포함된 attachApplication() 스텁 메서드 호출

=> 이 절의 목적은 ActivityThread와 액티비티 매니저 서비스 간의 상호작용을 위한 바인더 연결을 설정하는 것

(1) ActivityThread 객체

  • attach() 메서드: ActivityThread와 액티비티 매니저 서비스 간에 IActivityManager 인터페이스 기반의 바인더 RPC를 위한 연결을 설정한다
  • 바인더 RPC 연결이 설정되면 ActivityThread는 ActivityManagerProxy 객체를 통해 액티비티 매니저 서비스에게 특정 작업을 요청할 수 있다
    (2) ActivityManagerProxy 객체
  • ActivityManagerProxy 객체의 attachApplication() 프록시 메서드
    • ApplicationThread에 대한 바인더 객체를 마샬링해서 RPC 코드와 바인더 RPC 데이터를 ActivityManageNative 객체에 전달한다.
      (3) ActivityManagerNative 객체
  • RPC 코드와 바인더 RPC 데이터는 ActivityManagerNative 객체의 onTransact() 메서드를 통해 처리된다
  • 액티비티 매니저 서비스가 ActivityThread와 IApplicationThread 인터페이스 기반의 바인더 RPC 통신을 실행할 수 있게 ApplicationThreadNative.asInterface() 메서드를 통해 ApplicationThreadProxy 객체를 생성한다.

액티비티 매니저 서비스 - attachApplication() 스텁 메서드 처리

  • attachApplication() 스텁 메서드의 동작 과정(간단히)
    • Controller 액티비티가 startService() API를 통해 실행을 요청한 애플리케이션 서비스 생성을 ActivityThread에 명령하는 역할을 수행
    • Controller가 요청한 서비스의 실제 생성은 ActivityThread를 통해 이뤄지지만 이러한 작업을 제어하는 것은 액티비티 매니저 서비스의 attachApplication() 스텁 메서드이다
      => 액티비티 매니저 서비스는 IApplicationThread 인터페이스 기반의 바인더 RPC를 이용해서 안드로이드 애플리케이션 컴포넌트인 액티비티, 서비스 등을 생성하고 생명주기를 제어한다.
  • 액티비티 매니저 서비스가 바인더 RPC를 통해 ActivityThread에게 생성할 서비스 정보를 넘겨 실제 RemoteService를 실행
    1. 액티비티 매니저 서비스 - ActivityManagerProxy 객체의 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() 호출

(1) 액티비티 매니저 서비스 -scheduleCreateService() 프록시 메서드 호출

  • attachApplication() 스텁 메서드는 attachApplicationLocked() 메서드를 호출
    • 인자로 ApplicationThreadProxy 객체와 attachApplication() 스텁 메서드를 호출한 프로세스의 pid를 갖는다
  • attachApplicationLocked() 메서드
    • 해시 함수를 호출해서 ActivityThread pid를 키 값으로 대응하는 value 값인 ProcessRecord 객체를 얻는다
    • 액티비티 매니저 서비스는 ApplicationThreadProxy 객체를 이용해서 이 객체와 연결된 ActivityThread를 제어할 수 있다.
    • 액티비티 매니저 서비스는 안드로이드 시스템 내의 각종 ActivityThread 상에서 동작하는 애플리케이션 컴포넌트들을 제어해야하는 시스템 서비스이므로 제어하고자 하는 ActivityThread와 관련된 ApplicationThreadProxy 객체를 구하는 메커니즘이 필요, 프로세스의 각종 정보를 포함하는 ProcessRecord에 ApplicationThreadProxy 객체를 연결하면 액티비티 매니저 서비스는 제어하려는 애플리케이션의 pid를 구한 다음 이에 해당하는 ApplicationThreadProxy 객체를 구할 수 있다.
  • 액티비티 매니저 서비스가 요청된 애플리케이션 서비스를 실행하기 위해 서비스와 관련된 정보를 저장하는 ServiceRecord 구조체를 얻는 과정
    • bringUpServiceLocked() 메서드에서는 액티비티 매니저 서비스가 실행할 서비스의 ServiceRecord 객체를 mPendingServices 큐에 저장, mPendingServices.get() 메서드를 이용해 큐에 저장했던 RemoteService에 대한 ServiceRecord 객체를 얻는다. 구한 ProcessRecord와 ServiceRecord 값을 realStartServiceLocked() 메서드로 전달
    • app.thread.scheduleCreateService() 메서드 호출, app.thread에는 서비스 실행을 요청한 ActivityThread를 제어하기위한 ApplicationThreadProxy 객체가 저장돼 있다.
    • ApplicationThreadProxy의 scheduleCreateService() 메서드를 호출하는데, 이때 실행할 서비스에 대한 정보가 포함된 ServiceRecord 객체 등이 인자로 전달

(2) ApplicationThreadProxy 객체 - 바인더 RPC 데이터 전송

  • 생성할 서비스에 대한 정보를 포함한 ServiceInfo 객체를 RPC 코드와 바인더 RPC 데이터를 통해 ApplicationThreadNative 객체에 전달

(3) ApplicationThreadNative 객체 - scheduleCreateService() 스텁 메서드 호출

  • 수신한 바인더 RPC 데이터를 onTransact() 메서드에서 처리
  • ServiceRecord 객체와 ServiceInfo 객체를 언마샬링한 다음 각각 token, info 변수에 저장하고 ActivityThread의 scheduleCreateService() 스텁 메서드의 인자로 넘긴다.

(4) ApplicationThread 객체 - ActivityThread로 CREATE_SERVICE 메시지 전달

  • scheduleCreateService() 스텁 메서드는 인자로 전달된 ServiceRecord와 ServiceInfo 객체를 이용해 CreateServiceData라는 객체를 만든 다음 이를 ActivityThread 메시지 큐에 CREATE_SERVICE 메시지로 전달
    • ApplicationThread는 액티비티 매니저 서비스의 제어 명령을 바인더 RPC로 수신하기 위한 용도, 실제 액티비티 매니저 서비스로부터 요청받은 서비스를 실행하거나 생명주기를 관리하는 일은 ActivityThread가 처리. ApplicationThread와 ActivityThread의 경우 동일 프로세스 영역에서 동작하기 때문에 이 둘 사이의 통신은 메시키 큐가 사용

(5) ActivityThread 객체 - 서비스 생성 및 서비스의 onCreate() 메서드 호출

  • ActivityThread는 메시지 큐를 자체적으로 가지고 있고 ApplicationThread로부터 수신된 메시지는 handleMessage() 메시지 핸들러에서 처리된다.
  • 결국 ApplicationThread는 액티비티 매니저 서비스로부터 바인더 RPC 데이터를 통해 받은 명령을 메시지 큐를 통해 ActivityThread에 그대로 전달하는 역할을 한다.