바인더 IPC 사용

이 페이지에서는 Android 8의 바인더 드라이버 변경사항을 설명하고 바인더 IPC 사용에 관한 세부정보를 제공하며 필수 SELinux 정책을 나열합니다.

바인더 드라이버 변경사항

이제 Android 8부터 Android 프레임워크와 HAL은 바인더를 사용하여 서로 통신합니다. 이러한 통신은 바인더 트래픽을 매우 증가시키므로 Android 8에는 바인더 IPC를 빠르게 유지하도록 고안된 여러 개선사항이 포함됩니다. SoC 공급업체와 OEM은 커널/일반 프로젝트의 android-4.4 및 android-4.9 이상 분기에서 직접 병합해야 합니다.

여러 바인더 도메인(컨텍스트)

Common-4.4 이상(업스트림 포함)

Android 8에서는 프레임워크(기기 독립형)와 공급업체(기기 귀속형) 코드 간의 바인더 트래픽을 명확히 분할하기 위해 바인더 컨텍스트의 개념을 도입했습니다. 각 바인더 컨텍스트에는 자체 기기 노드와 자체 컨텍스트(서비스) 관리자가 있습니다. 컨텍스트 관리자는 컨텍스트가 속한 기기 노드를 통해서만 액세스할 수 있으며, 특정 컨텍스트를 통해 바인더 노드를 전달하는 경우 다른 프로세스에서만 동일한 컨텍스트를 통해 액세스하여 도메인을 서로 완전히 격리할 수 있습니다. 사용에 관한 자세한 내용은 vndbindervndservicemanager를 참조하세요.

분산-수집

Common-4.4 이상(업스트림 포함)

이전 Android 릴리스에서는 모든 바인더 호출 데이터가 3번 복사되었습니다.

  • 호출 프로세스에서 Parcel로 직렬화하기 위해 한 번
  • 커널 드라이버에서 Parcel을 타겟 프로세스로 복사하기 위해 한 번
  • 타겟 프로세스에서 Parcel의 직렬화를 해제하기 위해 한 번

Android 8에서는 분산-수집 최적화를 사용하여 복사본 수를 3개에서 1개로 줄입니다. 먼저 Parcel 데이터를 직렬화하지 않아 데이터의 원래 구조와 메모리 레이아웃이 그대로 유지되며 드라이버는 데이터를 즉시 타겟 프로세스에 복사합니다. 데이터가 타겟 프로세스를 거친 이후에도 구조와 메모리 레이아웃이 동일하여 다른 사본이 없어도 데이터를 읽을 수 있습니다.

세분화된 잠금

Common-4.4 이상(업스트림 포함)

이전 Android 릴리스에서는 바인더 드라이버를 통해 전역 잠금을 사용하여 중요한 데이터 구조에 대한 동시 액세스를 방지했습니다. 잠금에 대한 경합은 거의 없었지만, 우선순위가 낮은 스레드가 잠금을 획득한 후 선점되면 동일한 잠금을 획득해야 하는 우선순위가 더 높은 스레드가 심각하게 지연될 수 있었습니다. 이로 인해 플랫폼에 버벅거림이 발생했습니다.

이 문제를 해결하기 위한 첫 번째 조치는 전역 잠금을 유지하면서 선점을 중지하는 것이었습니다. 하지만 이러한 방법은 정확한 해결책이라기보다는 편법이었으며 결국 업스트림에서 거부되어 폐기되었습니다. 2017년 1월부터 Pixel 기기에서 구동되고 있는 버전에서의 후속 조치는 잠금 기능을 더 세분화하는 데 중점을 두었습니다. 이러한 변경사항은 대부분 공개되었지만, 후속 버전에서는 훨씬 더 개선되었습니다.

Google에서는 세분화된 잠금 구현 방식의 사소한 문제를 파악한 후 다른 잠금 아키텍처를 활용하여 개선된 솔루션을 고안하고 이에 따른 변경사항을 모든 일반 커널 분기에 적용했습니다. Google에서는 수많은 기기에서 이 구현 방식을 지속적으로 테스트하고 있습니다. 조치가 필요한 문제가 발견되지 않았으므로 Android 8을 탑재하여 출시되는 기기에는 이 구현 방식을 권장합니다.

실시간 우선순위 상속

Common-4.4 및 Common-4.9(업스트림 포함 예정)

바인더 드라이버는 항상 세분화된 우선순위 상속을 지원해 왔습니다. Android에서 실시간 우선순위에 따라 실행되는 프로세스가 증가하면서 실시간 스레드가 바인더를 호출하는 경우 해당 호출을 처리하는 프로세스의 스레드도 실시간 우선순위에 따라 실행되는 경우가 있습니다. 이러한 사용 사례를 지원하기 위해 이제 Android 8에서는 바인더 드라이버를 통해 실시간 우선순위 상속을 구현합니다.

트랜잭션 수준의 우선순위 상속과 더불어 노드 우선순위 상속을 통해 노드(바인더 서비스 객체)는 노드에서 실행되어야 하는 호출의 최소 우선순위를 지정할 수 있습니다. Android의 이전 버전에서 이미 세분화된 값을 사용하는 노드 우선순위 상속을 지원했지만, Android 8에서는 실시간 예약 정책 노드 상속을 지원합니다.

사용자 공간 변경사항

Android 8에는 일반 커널에서 현재 바인더 드라이버로 작업하는 데 필요한 모든 사용자 공간 변경사항이 포함되어 있습니다. 단 한가지 예외로, /dev/binder에서 실시간 우선순위 상속을 사용 중지하는 원래의 구현 방식은 ioctl을 사용하였습니다. 후속 개발에서는 우선순위 상속 제어를 더 세분화된 방식으로 전환했습니다. 즉 컨텍스트별이 아닌 바인더별 모드입니다. 따라서, ioctl은 Android 일반 분기가 아닌 일반 커널에 적용됩니다.

이 변경사항으로 인해 실시간 우선순위 상속은 기본적으로 모든 노드에서 사용 중지됩니다. Android 성능팀은 hwbinder 도메인의 모든 노드에서 실시간 우선순위 상속을 사용하는 것이 유용하다는 점을 발견했습니다. 이러한 효과를 얻으려면 사용자 공간에서 이 변경사항을 선택하세요.

일반 커널용 SHA

바인더 드라이버에 필요한 변경사항을 가져오려면 적절한 SHA에 동기화합니다.

  • Common-3.18
    cc8b90c121de ANDROID: binder: 복원 시 prio 권한을 확인하지 않습니다.
  • Common-4.4
    76b376eac7a2 ANDROID: binder: 복원 시 prio 권한을 확인하지 않습니다.
  • Common-4.9
    ecd972d4f9b5 ANDROID: binder: 복원 시 prio 권한을 확인하지 않습니다.

바인더 IPC 사용

이전에는 공급업체 프로세스에서 바인더 프로세스 간 통신(IPC)을 사용하여 통신했습니다. Android 8에서는 /dev/binder 기기 노드가 프레임워크 프로세스만 허용하므로 공급업체 프로세스는 해당 노드에 액세스할 수 없습니다. 공급업체 프로세스는 /dev/hwbinder에 액세스할 수 있지만, HIDL을 사용하기 위해서는 AIDL 인터페이스를 변환해야 합니다. 공급업체 프로세스 간에 AIDL 인터페이스를 계속 사용하려는 공급업체를 위해 Android는 아래에 설명된 대로 바인더 IPC를 지원합니다.

vndbinder

Android 8은 공급업체 서비스용으로 /dev/binder 대신 /dev/vndbinder를 사용하여 액세스할 수 있는 새 바인더 도메인을 지원합니다. /dev/vndbinder가 추가됨에 따라 이제 Android에는 다음과 같은 세 개의 IPC 도메인이 있습니다.

IPC 도메인 설명
/dev/binder AIDL 인터페이스를 사용하는 프레임워크/앱 프로세스 간 IPC
/dev/hwbinder HIDL 인터페이스를 사용하는 프레임워크/공급업체 프로세스 간 IPC
HIDL 인터페이스를 사용하는 공급업체 프로세스 간 IPC
/dev/vndbinder AIDL 인터페이스를 사용하는 공급업체/공급업체 프로세스 간 IPC

/dev/vndbinder를 표시하려면 커널 구성 항목 CONFIG_ANDROID_BINDER_DEVICES"binder,hwbinder,vndbinder"로 설정하세요. 이것이 Android 일반 커널 트리의 기본값입니다.

일반적으로 공급업체 프로세스는 바인더 드라이버를 직접 열지 않고 libbinder 사용자 공간 라이브러리에 대한 링크를 통해 바인더 드라이버를 엽니다. ::android::ProcessState()에 메서드를 추가하면 libbinder용 바인더 드라이버를 선택하게 됩니다. 공급업체 프로세스는 일반적으로 ProcessState, IPCThreadState 또는 어떠한 바인더를 호출하기 전에 이 메서드를 호출해야 합니다. 사용하려면 공급업체 프로세스(클라이언트 및 서버)의 main() 뒤에 다음과 같은 내용을 넣어 호출합니다.

ProcessState::initWithDriver("/dev/vndbinder");

vndservicemanager

이전에는 바인더 서비스가 servicemanager를 통해 등록되어 다른 프로세스에 의해 검색될 수 있었습니다. Android 8에서 servicemanager는 이제 프레임워크 프로세스와 앱 프로세스에서만 사용되며 공급업체 프로세스에서는 더 이상 액세스할 수 없습니다.

하지만 공급업체 서비스에서는 이제 /dev/binder 대신 /dev/vndbinder를 사용하는 servicemanager의 새 인스턴스인 vndservicemanager를 사용하며 이는 servicemanager 프레임워크와 동일한 소스에서 구축되었습니다. 공급업체 프로세스는 변경 없이도 vndservicemanager와 통신할 수 있습니다. 공급업체 프로세스가 /dev/vndbinder를 열면, 서비스 조회가 자동으로 vndservicemanager로 이동합니다.

vndservicemanager 바이너리는 Android의 기본 기기 makefile에 포함되어 있습니다.

SELinux 정책

바인더 기능을 사용하여 서로 통신하려는 공급업체 프로세스에 필요한 사항은 다음과 같습니다.

  1. /dev/vndbinder 액세스 권한
  2. 바인더를 통해 vndservicemanager{transfer, call}을 연동
  3. 공급업체 바인더 인터페이스를 통해 공급업체 도메인 B를 호출하려는 공급업체 도메인 A의 binder_call(A, B)
  4. vndservicemanager{add, find} 서비스 관련 권한

요구사항 1~2를 충족하려면 다음과 같이 vndbinder_use() 매크로를 사용합니다.

vndbinder_use(some_vendor_process_domain);

요구사항 3을 충족하기 위해 바인더를 통해 통신해야 하는 공급업체 프로세스 A와 B의 binder_call(A, B)을 그대로 유지할 수 있으며 이름을 변경할 필요는 없습니다.

요구사항 4를 충족하려면 서비스 이름, 서비스 라벨 및 규칙을 처리하는 방식을 변경해야 합니다.

SELinux에 관한 자세한 내용은 Android의 보안이 강화된 Linux를 참조하세요. Android 8.0의 SELinux에 관한 자세한 내용은 Android 8.0의 SELinux를 참조하세요.

서비스 이름

이전에는 공급업체 프로세스에서 service_contexts 파일에 서비스 이름을 등록하고 해당 파일에 액세스하기 위한 상응하는 규칙을 추가했습니다. 다음은 device/google/marlin/sepolicy에 있는 service_contexts 파일의 예시입니다.

    AtCmdFwd                              u:object_r:atfwd_service:s0
    cneservice                            u:object_r:cne_service:s0
    qti.ims.connectionmanagerservice      u:object_r:imscm_service:s0
    rcs                                   u:object_r:radio_service:s0
    uce                                   u:object_r:uce_service:s0
    vendor.qcom.PeripheralManager         u:object_r:per_mgr_service:s0
    

Android 8에서 vndservicemanagervndservice_contexts 파일을 대신 로드합니다. 기존 service_contexts 파일에 이미 포함되어 있으며 vndservicemanager로 이전할 공급업체 서비스는 새 vndservice_contexts 파일에 추가되어야 합니다.

서비스 라벨

이전에는 u:object_r:atfwd_service:s0과 같은 서비스 라벨이 service.te 파일에서 정의되었습니다. 예를 들면 다음과 같습니다.

type atfwd_service,      service_manager_type;

Android 8에서는 유형을 vndservice_manager_type으로 변경하고 규칙을 vndservice.te 파일로 이동해야 합니다. 예를 들면 다음과 같습니다.

type atfwd_service,      vndservice_manager_type;

Servicemanager 규칙

이전에는 servicemanager에서 서비스를 추가하거나 찾을 수 있도록 규칙을 통해 도메인에 액세스 권한을 부여했습니다. 예를 들면 다음과 같습니다.

    allow atfwd atfwd_service:service_manager find;
    allow some_vendor_app atfwd_service:service_manager add;
    

Android 8에서 이러한 규칙은 그대로 유지되며 동일한 클래스를 사용할 수 있습니다. 예를 들면 다음과 같습니다.

    allow atfwd atfwd_service:service_manager find;
    allow some_vendor_app atfwd_service:service_manager add;