• 안드로이드 바인더
    • 바인더는 원래 IPC(Inter Process Communication) 도구이지만 안드로이드에서는 다른 프로세스에 있는 함수를 마치 현재 프로세스에 존재하는 함수처럼 사용할 수 있게 해주는 RPC(Remote Procedure Call)를 지원하는 데 주로 이용된다.

리눅스 메모리 공간과 바인더 드라이버

  • 안드로이드의 기반 커널인 리눅스 커널의 메모리 공간을 이해
  • 안드로이드 프로세스는 프로세스만의 고유한 가상 주소 공간에서 실행
  • 가상 주소 공간은 사용자 공간과 커널 공간으로 나뉜다
    • 사용자 코드와 관련 라이브러리는 사용자 공간의 코드 영역, 데이터 영역, 스택 영역에서 동작한다
    • 커널 공간에서 동작해야할 코드는 커널 공간의 각 영역에서 동작한다
  • 프로세스는 가ㅏㄱ자 독립된 주소 공간을 가지고 별개로 동작한다
    • 독립된 공간을 가지는 프로세스가 다른 프로세스에게 데이터를 전달하는 방법: 프로세스 간 공유가 가능한 커널 공간을 이용한다
    • 커널 입장에서 봤을 때 프로세스는 하나의 작업 단위일 뿐이고, 커널 공간에서 실행하는 태스크의 데이터와 코드는 서로 공유된다.
  • 예를 들어, 카메라로 찍은 사진을 화면에 보여주는 경우
    • 카메라를 구동하는 프로세스, 사진을 화면에 출력하는 프로세스가 있다
    • 카메라를 동작하는 프로세스가 사진을 찍은 후, 사진을 화면에 출력하기 위해서는 출력을 담당하는 프로세스를 거쳐야 한다
    • 커널 공간을 통해 화면 출력요청 메시지를 전달한다 -> 커널 공간을 이용해 두 프로세스 사이의 메시지를 주고 받는 IPC를 수행한다
    • 안드로이드에서는 단순히 메시지를 전달하는 IPC 개념이 아니라 상대방 프로세스에 존재하는 함수까지 호출할 수 있는 바인더라는 IPC 도구를 채택해 프로세스간의 RPC를 지원한다
    • 카메라의 경우, 카메라를 구동하는 프로세스가 화면 출력을 담당하는 프로세스의 화면 출력함수를 호출하여 사진을 출력한다.
  • 프로세스 간 통신을 제공하기 위해 커널 공간에서 동작하는 Binder IPC Driver라는 추상화된 드라이버를 이용한다
    • 커널 공간을 통한 데이터 전달 시 데이터의 신뢰성을 확보할 수 있다
    • 사용자 공간에서 접근할 수 없는 공간인 커널 공간을 이용해 데이터를 주고 받기 때문에 IPC 간의 보안 문제도 해결할 수 있다

안드로이드 바인더 모델: 바인더의 동작 원리

  • 바인더의 역할: Surface Filger의 동작

BinderIPC

  • 프로세스 A: 홈 스크린과 인디케이터 화면 출력, 서비스 클라이언트
  • 프로세스 B: 기기의 대기 모드 표시를 위한 잠금 화면을 생성, 서비스 클라이언트
  • 프로세스 C: Surface(화면)를 합성해서 프레임 버퍼(LCD 화면의 버퍼)로 데이터를 전송하는 Surface Flinger 서비스를 제공하는 서비스 서버
  • Surface Flinger는 프로세스 A와 B가 건네주는 그래픽 화면을 조합해서 LCD 화면에 출력하는 역할
  • 바인더는 각 프로세스 간에 수행되는 RPC를 중재하는 역할
  • 프로세스 A와 B는 바인더를 통해 Surface Flinger가 가진 LCD 출력 함수를 호출해서 그래픽을 출력한다

서비스 클라이언트가 바인더를 통해 서비스 서버의 함수를 호출하는 과정

BinderIPC

  • 서비스 클라이언트는 바인더 IPC 데이터(혹은 IPC 데이터)를 서비스 서버로 전달
  • 바인더 드라이버는 foo() 함수를 호출하기 위한 바인더 IPC 데이터를 서비스 클라이언트에서 서비스 서버로 전달하는 역할, 프로세스 간 통신의 중재자 역할
  • 바인더 IPC 데이터
    • 상대편 프로세스의 함수 호출 정보, 바인더 드라이버가 수행하는 IPC의 데이터 단위
    • 함수 호출과 관련된 내용(서비스에 해당하는 번호와 호출할 함수명), 바인더 프로토콜로 구성
    • 서비스 번호: 안드로이드에서 동작하는 서비스를 구분짓기 위함
    • 함수명: 서비스 서버에서 동작하는 서비스 가운데 서비스 클라이언트가 호출할 함수를 찾기 위함
    • 바인더 프로토콜: 바인더 드라이버와 바인더를 이용하는 프로세스 간의 IPC 데이터를 처리하는 규약
  • 바인더 IPC 데이터는 구조체 형태, 구조체 변수가 위의 구성요소를 나타낸다
    • 핸들: 서비스를 구별하는 번호
    • RPC 코드: 서비스에서 호출할 함수
    • RPC 데이터: 함수의 인자, RPC 코드가 가리키는 함수에 전달할 인자 값
    • 바인더 프로토콜: IPC 데이터 처리 방법

바인더 IPC 데이터의 전달: 바인더 드라이버로 IPC 데이터 전달

  • 바인더 드라이버는 시스템 콜을 통해 접근 가능하다
    (1) 바인더를 통해 RPC를 시도하는 애플리케이션은 open() 시스템 콜을 통해 바인더 드라이버의 파일 디스크립터를 얻는다
    (2) mmap() 시스템 콜을 통해 커널 내에서 IPC 데이터를 수신하기 위한 공유 공간을 확보한다
    (3) ioctl() 함수의 인자로 바인더 드라이버에 IPC 데이터를 전달한다

바인더 IPC 데이터의 흐름: 바인더 IPC 데이터가 서비스 클라이언트에서 서비스 서버로 전달되기까지 과정

  • 서비스 클라이언트에서 서비스 서버의 foo() 함수를 호출하기 위해 RPC를 시도할 때 바인더 IPC 데이터의 전달 과정

BinderIPC

  • 서비스 클라이언트가 서비스를 사용하기 위한 추상 계층
    • 서비스 클라이언트는 하위 계층에서 제공하는 동작을 통해 서비스 계층에서 RPC를 수행
    • 서비스 계층 아래에 있는 계층에서는 서비스 계층의 RPC를 지원하기 위한 바인더 IPC 데이터를 생성
  • 서비스 계층
    • 특정 기능 수행하는 서비스의 함수가 존재하는 계층
    • 서비스 클라이언트는 서비스의 함수를 가상으로 호출, 서비스 서버는 서비스 클라이언트가 요청한 서비스의 함수를 실제로 호출
  • RPC 계층
    • 서비스 클라이언트는 이 계층에서 서비스의 함수를 호출하기 위한 RPC 코드와 RPC 데이터를 생성
    • 서비스 서버는 전달받은 RPC 코드를 토대로 함수를 찾고 RPC 데이터 전달
  • IPC 계층
    • RPC 코드와 RPC 데이터를 바인더 드라이버에 전달하기 위한 바인더 IPC 데이터로 캡슐화한다
  • 바인더 드라이버 계층
    • 바인더 IPC 데이터를 통해 서비스를 가진 서비스 서버를 찾은 후 IPC 데이터를 전달
    • 바인더 드라이버는 IPC 데이터에서 바인더 프로토콜을 파악하여 데이터 전달 여부를 결정


바인더 프로토콜

  • 바인더 프로토콜
    • 바인더 드라이버는 IPC 데이터에서 바인더 프로토콜을 파악하여 데이터 전달 여부를 결정
    • 바인더 IPC 데이터에 포함
    • 바인더 프로토콜 전달 방향
      • IPC 계층에서 바인더 드라이버로 전달: Binder Command Protocol(BC_)
      • 바인더 드라이버에서 IPC 계층으로 전달: Binder Return Protocol(BR_)
    • 데이터를 송신하는 측과 수신하는 측에서 모두 알고 있는 규약
      • 바인더 IPC를 이용하는 프로세스와 바인더 드라이버는 헤더 파일에 바인더 프로토콜을 정의

BinderIPC

  • IPC 데이터를 전달할 때 사용하는 바인더 프로토콜: BC_TRANSACTION, BR_TRANSACTION
    • 서비스 클라이언트는 BC_TRANSACTION 프로토콜을 통해 바인더 드라이버에 IPC 데이터 전달을 명령
    • 바인더 드라이버는 전달받은 IPC 데이터를 토대로 바인더 프로토콜이 BC_TRANSACTION이면 IPC 데이터의 핸들을 통해 서비스 서버를 찾는다
    • 이후 바인더 드라이버는 바인더 프로토콜을 BR_TRANSACTION으로 변경하고, 이를 IPC 데이터에 실어서 서비스 서버로 전달
    • 서비서 서버는 전달받은 바인더 프로토콜이 BR_TRANSACTION인지 체크한 후, IPC 데이터를 분석해서 서비스 사용자가 요청한 함수를 호출

RPC 코드와 RPC 데이터

  • RPC 코드: 서비스 클라이언트가 서비스 서버에 존재하는 서비스의 함수를 사용하기 위해 각 함수에 해당하는 식별자를 바인더 IPC 데이터에 담아 전달
  • RPC 데이터: 함수의 인자를 IPC 데이터에 담아 전달
  • 서비스 서버가 가진 서비스의 함수를 호출하려면 서비스 클라이언트에서는 반드시 서비스 서버가 가진 RPC 코드를 알아야 한다

BinderIPC

  • Audio Flinger 서비스를 사용하는 MP3 애플리케이션의 경우
    • 음악 재생 중 볼륨 조정이 필요한 경우, 하드웨어 볼륨 조정을 담당하는 Audio Flinger 서비스를 가진 서비스 서버에게 요청
    • 볼륨 조정을 하는 함수를 의미하는 SET_MASTER_VOLUME RPC 코드와 원하는 볼륨값인 RPC 데이터를 IPC 데이터에 담아 서비스 서버에 보낸다
    • 서비스 서버는 전달받은 IPC 데이터에서 RPC 코드를 파악하고, RPC 코드가 SET_MASTER_VOLUME일 경우 Audio Flinger에서 setMasterVolume() 함수를 호출
    • 이를 통해 MP3 애플리케이션은 볼륨을 조정할 수 있다

바인더 어드레싱

  • 컨텍스트 매니저(Context Manager): 다양한 서비스를 모두 목록화해서 관리하는 프로세스
    • 서비스마다 핸들이라는 번호 값을 할당: 핸들은 바인더 IPC의 목적지 주소로 사용된다
    • 서비스의 추가/검색 등의 관리 기능을 수행한다
    • 컨텍스트 매니저의 핸들 값은 0이다
  • 바인더 드라이버는 IPC 데이터의 핸들을 가지고 서비스 서버를 찾는다: 바인더 어드레싱(Binder Addressing)
  • 바인더 어드레싱을 위해 서비스 서버는 자신이 가진 서비스에 대한 접근 정보를 컨텍스트 매니저에 등록해야한다
    • 서비스 등록 과정에서 서비스 서버는 ADD_SERVICE(RPC 코드), 등록할 서비스 이름(RPC 데이터), 핸들을 0으로 지정한 IPC 데이터를 바인더 드라이버에 전달

BinderIPC

  • 서비스 서버가 자신의 서비스를 컨텍스트 매니저에게 등록할 때의 바인더 어드레싱 과정
    • 바인더 드라이버는 먼저 핸들 0에 해당하는 바인더 노드를 찾는다
      (바인더 노드는 서비스마다 하나씩 존재하는 바인더 드라이버 내 자료구조이다. 프로세스마다 바인더 노드들을 리스트로 가진다)
    • 핸들 0에 해당하는 바인더 노드는 컨텍스트 매니저이므로 서비스 서버는 IPC 데이터를 컨텍스트 매니저에게 전달한다
    • 바인더 드라이버는 서비스 서버에 서비스 A에 해당하는 바인더 노드를 하나 생성
    • 컨텍스트 매니저가 생성된 바인더 노드를 알 수 있게 바인더 노드 참조 데이터를 생성해 해당 노드를 연결
    • 참조 데이터는 생성된 순서대로 번호가 매겨진다
    • 이 번호는 IPC 데이터에 담겨 컨텍스트 매니저로 전달된다
    • 컨텍스트 매니저는 IPC 데이터에 들어 있는 서비스 이름과 바인더 노드의 번호를 서비스 리스트에 등록한다
    • 컨텍스트 매니저의 서비스 목록, 바인더 드라이버의 바인더 노드, 서비스 서버의 서비스가 연결된다

서비스 클라이언트가 서비스를 검색하는 과정

BinderIPC

  • 서비스 클라이언트가 서비스를 검색하는 과정: 서비스 클라이언트가 서비스를 검색할 때의 바인더 어드레싱
    • 서비스 클라이언트는 GET_SERVICE라는 RPC 코드와 요청할 서비스 이름(RPC 데이터), 핸들을 0으로 지정한 IPC 데이터를 바인더 드라이버를 통해 컨텍스트 매니저에게 전달
    • 컨텍스트 매니저는 서비스 이름에 해당하는 서비스 번호를 찾은 다음 이를 바인더 드라이버에 전달
    • 바인더 드라이버는 서비스 목록 번호에 해당하는 참조 데이터를 찾는다
    • 서비스 클라이언트 쪽에서 참조 데이터를 생성해 컨텍스트 매니저의 참조 데이터가 가리키는 바인더 노드를 연결한다
      (연결된 바인더 노드는 서비스 서버가 자신의 서비스를 위해 생성했던 바인더 노드이다)
    • 바인더 드라이버는 생성한 참조 데이터를 생성된 순서대로 번호를 매겨 서비스 클라이언트에게 알려준다
    • 서비스 클라이언트는 이 번호를 핸들로 지정하여 서비스 서버의 바인더 노드를 찾는다

바인더 어드레싱을 통해 서비스를 사용하는 과정

BinderIPC

  • 서비스 클라이언트는 참조 데이터의 번호를 핸들에 저장
  • 사용할 서비스의 함수에 해당하는 RPC 코드와 RPC 데이터를 IPC 데이터에 담아 서비스 서버로 전달하여 서비스 A가 가진 함수를 호출