스터디 5주차

5 minute read

바인더 (Binder)

바인더란?

안드로이드에서 바인더는 각각 독립된 프로세서들을 연결해 주는 역할을 한다. 리눅스에서 시스템의 기능을 이용하기 위해서 시스템 콜(System Call)을 사용하여 시스템에서 제공하는 프로세서, 파일 시스템 기능을 이용하도록 제공하고 있다. 하지만 안드로이드에서는 각 독립적으로 운영되는 프로세스, 특히 서비스의 기능을 이용할 수 있도록 제공하는 것이 바인더의 핵심이라고 하겠다. 응용 프로그램 개발자의 입장에서는 서비스를 제공하는 서비스 프로세서와 어떠한 식으로 연결하여 응용 프로그램이 운영 되는지 이해하기 위해 바인더에 대한 내용을 알아야 하고, 안드로이드 시스템을 개발하는 시스템 개발자의 입장에서는 기존 서비스의 변경이나 기능 추가 또는 새로운 서비스를 구성하기 위해 어떠한 표준 인터페이스를 통해 서비스를 구현해야 하는지 알아야 하기 때문에 바인더에 대해 이해를 하고 있어야 한다. 바인더에 대한 개념을 이해하기 위해서는 먼저 IPC의 개념에 대해 이해를 하고 있어야 한다.

IPC란? (Inter Process Communication)

IPC

기존 UNIX 계열에서 독립된 두 프로세서간의 통신에는 시그널(Signal), 파이프(Pipe), 메시지 큐(Message Queue), 세마포어(Semaphore), 메모리 맵드 파일(Memory Mapped File)과 같은 방법이 사용되었다. 각각 방법의 장단점과 사용 방법은 차이가 있지만 프로세서간의 데이터를 전달하고 통신하기 위해서 고안된 방법들이다. 그림은 대표적인 IPC의 예를 보여준다. 프로세스 A에서 프로세스 B로 데이터를 전송할 때 공유 메모리를 사용하여 필요한 정보를 전달하는 간단한 동작 예를 그림으로 보여주고 있다.

대표적인 IPC

1) 메시지 큐(Message Queue) 프로세서 간 주고 받는 메시지를 커널에 복사하고 읽어가는 방식이다. IPC 내의 메시지를 하나의 구조체 형태로 통째로 주고 받을 수 있어서 구현하기에 편리하다. 여러 가지 이벤트를 하나로 관리 사용하기에 편리한 구조다.

2) 공유 메모리(Shared Memory) 프로세스간에 공유 메모리를 지정하여, 이 영역에 복사하고 읽어가는 방식이다.

3) UDS(Unix Domain Socket) 기존 소켓 API와 유사하게 사용할 수 있다. 또한 여러 가지 이벤트를 하나로 사용하기에 편리한 구조이다. IPC는 각 프로세스간 어떠한 식으로 데이터를 전송하고 데이터를 받을지에 대한 약속일 뿐이다. 따라서 시스템 레벨에서 별도로 관리하지는 않는다. 각각의 프로세서가 정해진 방법으로 통신을 할 수 있도록 구현을 해야 한다.

다시 바인더란?

바인더의 역사는 BeOS라는 운영체제로부터 시작된다. 이제는 잊혀진 운영체제 및 컴퓨터 시스템이었지만 나름대로 신선한 충격을 주었던 운영체제다. BeOS에서 시작된 바인더의 개념은 Palm을 거쳐 안드로이드에 탑재가 된다. 바인더의 주 목적은 컴포넌트 기반 시스템 레벨 디자인을 지원할 수 있도록 설계된 오픈 소스 솔루션이다. 즉, 운영체제 혹은 시스템에서 제공해 주는 기능을 각각의 컴포넌트 혹은 모듈 형태로 만들고 이것을 운영할 수 있도록 만들어 주는 것이 바인더의 가장 큰 목적이다.

바인더의 특징

바인더의 가장 큰 특징은 객체지향(Object-oriented) 운영체제 환경을 제공한다는 것이다. 프로세스간의 리소스 관리를 지원하고, 응용 프로그램에 중심을 두기보다는 시스템 지향적이다. 새로운 컴포넌트 기반 시스템 레벨의 개발을 지원하고 있다. 다양한 기본서비스를 위한 컴포넌트/오브젝트를 가지고 있다. 하지만 바인더 자체로는 특정한 쓰레드(Thread) 모델을 지원하지 않는다. 바인더는 상용 수준의 시스템 레벨 서비스를 구현하는데 넓게 사용되어 왔다. 소형 모바일 장치 혹은 전용 하드웨어에서 실행하도록 설계된 플랫폼이다. 모바일 장치 세계는 데스크탑 보다 하드웨어의 기능에 있어 훨씬 다양한 분야에 사용이 된다.(크기, 배터리 수명 등)

바인더는 하드웨어를 이용하는 방법에 있어 더 많은 유연성을 가지고 시스템 설계를 할 수 있도록 도움을 준다. 특히, 메모리 보호기능과 프로세스간의 통신은 하이 레벨 운영체제에서는 상당한 오버헤드이기 때문에 바인더는 프로세스 구성방식에 묶여 있지 않는 시스템을 설계할 수 있도록 한다. 바인더는 프로세스가 실행되는 동안 특정한 속도/크기/안정성/보완성 등의 상충관계를 만들 수 있도록 다양한 부분을 할당할 수 있는 구조로 되어 있다.

Android의 모든 시스템 기능은 서버 프로세스로 제공되기 때문에 프로세스 사이에 최적화된 통신 방법이 필요하고 그 고민의 결과가 바인더이다. 바인더는 모든 프로세스가 공유하는 커널 메모리를 참조하게 함으로써 메모리 복사 오버헤드를 최소화한다. 뿐만 아니라 C++을 이용해 작성된 RPC(Remote Procedure Call) 프레임워크를 제공하여 생산성이 높다.

안드로이드 바인더를 이용한 서비스 구조

바인더2

바인더 드라이버 - 안드로이드 IPC 시스템의 핵심이다. 서비스 프로바이더와 서비스 유저 사이의 데이터를 전달하는 역할을 한다. 즉 바인더 드라이버의 역할은 각 프로세스가 매핑해 놓은 메모리 주소와 커널 공간의 메모리 주소를 변환하여 참조해 사용할 수 있도록 하는 것이다.

서비스 프로바이더 - 안드로이드 시스템에서 서비스를 제공하는 서비스 역할을 한다. 바인더 드라이버로부터 받은 데이터를 파싱하여 처리하는 역할을 한다.

서비스 매니저 - 특별한 서비스 프로바이더이다. 다른 서비스 프로바이더의 서비스를 관장한다.

서비스 유저 - 서비스 프로바이더의 기능을 호출하는 응용 프로그램이나 서비스다. 바인더의 핵심은 IPC 방법을 통하여 다른 프로세서, 즉 서비스 프로바이더의 기능을 호출하는 것이 목적이다.

바인더는 시스템적인 관점에서는 IPC지만 전체적인 동작 흐름은 서비스 프로바이더에 있는 기능(혹은 함수)를 원격 호출하고 그 결과를 리턴 받는 RPC(Remote Proce dure Call)과 같은 동작을 하게 된다. 즉, 서비스로 만들어진 여러 프로세서의 기능을 원활하게 이용할 수 있도록 만든 것이 바인더의 목적이라고 하겠다.

Binder Driver

바인더는 리눅스 커널에서의 드라이버 디렉토리 아래 2개의 파일로 구성되었다. Linux에서 사용하는 표준 방법인 ioctl 시스템 함수를 이용해 바인더 드라이버를 사용할 수 있다. 이와 같은 일련의 메커니즘을 바인더 IPC라고 한다. 리눅스

drivers/staging/android/binder.h drivers/staging/android/binder.c

링크 : binder.h, binder.c (커널용이다)

바인더 드라이버는 misc 디바이스 형태로 등록이 된다. “/dev/binder”로 시스템에 등록이 되어 나타난다. 통상 major 10, minor는 MISC_DYNAMIC_MINOR로 등록을 한다. 등록이 될 경우 proc 파일 시스템을 이용해서 정보를 확인할 수 있고 동작 상태에 대한 로그를 볼 수 있다. 바인더 문제에 대한 1차적인 분석은 /proc/bin der를 통하여 할 수 있다.

사용자 영역에서 바인더를 제어하는 방법

  • 바인더는 리눅스 시스템에서 운용되는 하나의 드라이버기 때문에 표준 스트림 인터페이스를 사용하여 제어를 하게 된다. 따라서 mmap(), poll(), ioctl() 등의 시스템 콜(system call)을 이용하여 바인더 드라이버를 오픈 하고 ioctl()을 통하여 제어하게 된다.

  • 바인더 드라이버에 대한 ioctl 중 BINDER_WRITE_READ를 통하여 호출하는 프로세서로부터 바인더 드라이버까지 필요한 정보를 전달하게 된다. 바인더의 동작에는 바인더 드라이버로부터의 리턴 값, 드라이버로 명령을 내려 줘야 할 경우가 있는데 binder.h에는 다음과 같은 enum형들이 존재한다.

참고 : 바인더 드라이버내의 중요 정보를 담고 있는 구조체

struct binder_proc - 바인더를 사용하는 프로세스관련 구조체
struct binder_thread - drivers/staging/android/binder.c에 정의되어 있음 이 구조체의 멤버 중 rb_node 스트럭쳐는 include/linux/rbtree.h에 선언되어 있음. 스케줄링 관련 변수임
struct binder_write_read - drivers/staging/android/binder.h에 정의되어 있음 binder device driver로의 BINDER_WRITE_READ ioctl의 인자로 사용되는 구조체임.
struct binder_transaction - 프로세스간 binder transaction에 사용되는 구조체
struct binder_transaction_data - binder transaction의 BR_XXX, BC_XXX관련에 사용되는 ioctl의 인자

//ServiceManger에 대한 내용도 많으나 나중에 정리하기로 함.

안드로이드 프레임 워크에서의 바인더의 동작

바인더3

utils 라이브러리는 Android의 Binder 관련 핵심이다. 이 핵심부분은 컴파일 된 후 libutils.so로 구성되며 안드로이드 시스템에서의 public library로 사용된다.

그림은 안드로이드 시스템에서 어떻게 서비스가 동작되고 사용되는지 보여주는 그림이다.

  • 서비스 매니저는 바인더에서 컨텍스트 매니저(Context Manager)로 등록된다.
  • Service B는 처음 안드로이드 시스템이 시작될 때 서비스 매니저를 통하여 서비스로써 등록이 된다.
  • App A는 Service B에 있는 foo()라는 함수를 호출하는 것이 목적이다. 즉, App A의 입장에서는 단순히 Service B에 있는 foo()라는 함수를 호출하는 것이지만, 시스템 내부에서는 바인더의 복잡한 동작이 이루어지게 된다.
  • 즉, App A에서 Service B에 있는 foo()라는 함수를 호출하는 것은 App A에서 Service B의 foo() 함수를 RPC(Remote Procedure Call)하는 것이지만 실제 안드로이드 시스템 내부에서는 바인더 기능을 사용해서 IPC가 이루어지는 것이다.
  • IPC의 모든 내용들은 서비스 매니저와 바인더 드라이버를 통하여 이루어지게 된다.

바인더 동작의 내부 구조이다.

바인더4

Libutil.so를 사용하여 바인더 드라이버를 통하여 통신이 이루어지고, 전체적인 관장은 서비스 매니저를 통해 이루어지게 된다.

두 개의 프로세스, 프로세스 1은 서비스의 기능을 사용하는 응용 프로그램 프로세스이고, 프로제스 2는 실제 서비스를 제공하는 서비스로 구성된다. 프로세스 1에서 호출하는 모든 기능들은 BnABC 형태의 함수로 프로세스 2에 구현이 되어 있고, 이 서비스를 호출하는 프로세스 1에서는 BpABC 형태로 구성된 함수를 호출하게 된다. 여기서 두 BpABC, BnABC 형태의 함수는 Proxy, Native 라는 이름으로 불리며, 서비스를 이용하는 응용 프로그램에서 마치 함수처럼 호출하여 서비스내의 기능을 이용할 수 있도록 하는 역할을 한다.


코드분석

(android / platform / frameworks / base / master / . / core / java / android / os / Binder.java)

링크 나중에보자 봐도 이해가 안간다

출처 : https://www.oss.kr/info_techtip/show/32d5f561-b998-496c-a328-a58a5555e2c6 , https://d2.naver.com/helloworld/47656 , http://blog.daum.net/tlos6733/121

Categories:

Updated: