HIDL

HAL 인터페이스 정의 언어 또는 HIDL은 HAL과 해당 사용자 간의 인터페이스를 지정하기 위한 IDL(인터페이스 설명 언어)입니다. HIDL을 사용하면 인터페이스 및 패키지로 수집되는 유형 및 메서드 호출을 지정할 수 있습니다. 보다 광범위하게는 HIDL은 독립적으로 컴파일될 수 있는 코드베이스 간의 통신을 위한 시스템입니다. Android 10부터 HIDL은 더 이상 사용되지 않으며 Android는 모든 곳에서 AIDL 을 사용하도록 마이그레이션하고 있습니다.

HIDL은 IPC(프로세스 간 통신)에 사용하기 위한 것입니다. HDL로 생성된 HALS는 바인더 IPC(프로세스 간 통신) 호출을 사용하여 다른 아키텍처 계층과 통신할 수 있다는 점에서 바인더화된 HAL이라고 합니다. 바인더화된 HAL은 이를 사용하는 클라이언트와 별도의 프로세스에서 실행됩니다. 프로세스에 연결해야 하는 라이브러리의 경우 통과 모드 도 사용할 수 있습니다(Java에서는 지원되지 않음).

HIDL은 패키지로 수집되는 인터페이스(클래스와 유사)로 구성된 데이터 구조 및 메서드 서명을 지정합니다. HIDL의 구문은 C++ 및 Java 프로그래머에게 익숙하지만 키워드 집합이 다릅니다. HIDL은 Java 스타일 주석도 사용합니다.

술어

이 섹션에서는 다음 HIDL 관련 용어를 사용합니다.

바인더화 바인더와 유사한 메커니즘을 통해 구현된 프로세스 간의 원격 프로시저 호출에 HIDL이 사용되고 있음을 나타냅니다. 통과 를 참조하십시오.
콜백, 비동기 HAL 사용자가 제공하고 HAL에 전달되고(HIDL 메서드 사용) HAL에서 호출하여 언제든지 데이터를 반환하는 인터페이스입니다.
콜백, 동기 서버의 HIDL 메서드 구현에서 클라이언트로 데이터를 반환합니다. void 또는 단일 기본 값을 반환하는 메서드에는 사용되지 않습니다.
고객 특정 인터페이스의 메소드를 호출하는 프로세스. HAL 또는 Android 프레임워크 프로세스는 한 인터페이스의 클라이언트이고 다른 인터페이스의 서버일 수 있습니다. 통과 를 참조하십시오.
연장하다 다른 인터페이스에 메서드 및/또는 형식을 추가하는 인터페이스를 나타냅니다. 인터페이스는 다른 인터페이스를 하나만 확장할 수 있습니다. 동일한 패키지 이름의 부 버전 증분 또는 이전 패키지를 기반으로 하는 새 패키지(예: 공급업체 확장)에 사용할 수 있습니다.
생성 클라이언트에 값을 반환하는 인터페이스 메서드를 나타냅니다. 하나의 기본이 아닌 값 또는 둘 이상의 값을 반환하기 위해 동기 콜백 함수가 생성됩니다.
상호 작용 메서드 및 유형의 컬렉션입니다. C++ 또는 Java의 클래스로 변환됩니다. 인터페이스의 모든 메소드는 동일한 방향으로 호출됩니다. 클라이언트 프로세스는 서버 프로세스에 의해 구현된 메소드를 호출합니다.
일방 통행 HIDL 메서드에 적용될 때 메서드가 값을 반환하지 않고 차단하지 않음을 나타냅니다.
패키지 버전을 공유하는 인터페이스 및 데이터 유형의 컬렉션입니다.
지나가 다 서버가 클라이언트에 의해 dlopen 된 공유 라이브러리인 HIDL 모드입니다. 통과 모드에서 클라이언트와 서버는 동일한 프로세스이지만 별도의 코드베이스입니다. 레거시 코드베이스를 HIDL 모델로 가져오는 데만 사용됩니다. 바인더화 도 참조하십시오.
섬기는 사람 인터페이스의 메서드를 구현하는 프로세스입니다. 통과 를 참조하십시오.
수송 서버와 클라이언트 간에 데이터를 이동하는 HIDL 인프라입니다.
버전 패키지 버전입니다. 메이저와 마이너의 두 정수로 구성됩니다. 마이너 버전 증분은 유형 및 메소드를 추가할 수 있지만 변경하지는 않습니다.

HIDL 디자인

HIDL의 목표는 HAL을 다시 빌드하지 않고도 Android 프레임워크를 교체할 수 있다는 것입니다. HAL은 공급업체 또는 SOC 제조업체에서 빌드하고 기기의 /vendor 파티션에 배치하여 HAL을 다시 컴파일하지 않고도 자체 파티션에서 Android 프레임워크를 OTA로 대체할 수 있습니다.

HIDL 설계는 다음과 같은 문제의 균형을 유지합니다.

  • 상호 운용성 . 다양한 아키텍처, 도구 체인 및 빌드 구성으로 컴파일할 수 있는 프로세스 간에 안정적으로 상호 운용 가능한 인터페이스를 만듭니다. HIDL 인터페이스는 버전이 지정되며 게시된 후에는 변경할 수 없습니다.
  • 효율성 . HIDL은 복사 작업의 수를 최소화하려고 합니다. HIDL 정의 데이터는 압축을 풀지 않고도 사용할 수 있는 C++ 표준 레이아웃 데이터 구조의 C++ 코드로 전달됩니다. HIDL은 또한 공유 메모리 인터페이스를 제공하며 RPC는 본질적으로 다소 느리기 때문에 HIDL은 RPC 호출을 사용하지 않고 데이터를 전송하는 두 가지 방법인 공유 메모리와 FMQ(Fast Message Queue)를 지원합니다.
  • 직관적인 . HIDL은 RPC용 매개변수만 사용 in 메모리 소유권 문제를 방지합니다( Android 인터페이스 정의 언어(AIDL) 참조). 메서드에서 효율적으로 반환할 수 없는 값은 콜백 함수를 통해 반환됩니다. 전송을 위해 데이터를 HIDL로 전달하거나 HIDL에서 데이터를 수신하지 않아도 데이터 소유권이 변경되지 않습니다. 소유권은 항상 호출 함수에 남아 있습니다. 데이터는 호출된 함수의 기간 동안만 지속되어야 하며 호출된 함수가 반환된 직후에 소멸될 수 있습니다.

통과 모드 사용

이전 버전의 Android를 실행하는 기기를 Android O로 업데이트하려면 바인더화 및 동일 프로세스(패스스루) 모드에서 HAL을 제공하는 새로운 HIDL 인터페이스에서 기존(및 레거시) HAL을 모두 래핑할 수 있습니다. 이 래핑은 HAL과 Android 프레임워크 모두에 투명합니다.

통과 모드는 C++ 클라이언트 및 구현에만 사용할 수 있습니다. 이전 버전의 Android를 실행하는 기기에는 Java로 작성된 HAL이 없으므로 Java HAL은 본질적으로 바인더화됩니다.

.hal 파일이 컴파일되면 .hal hidl-gen 은 바인더 통신에 사용되는 헤더 외에 추가 패스스루 헤더 파일 BsFoo.h 를 생성합니다. 이 헤더는 dlopen ed할 함수를 정의합니다. 통과 HAL은 호출되는 동일한 프로세스에서 실행되므로 대부분의 경우 통과 메서드는 직접 함수 호출(동일한 스레드)에 의해 호출됩니다. oneway 메서드는 HAL이 처리할 때까지 기다리지 않기 때문에 자체 스레드에서 실행됩니다(즉, 통과 모드에서 oneway 메서드를 사용하는 모든 HAL은 스레드로부터 안전해야 함).

IFoo.hal이 주어지면 IFoo.halBsFoo.h 생성 메서드를 래핑하여 추가 기능(예: oneway 트랜잭션을 다른 스레드에서 실행)을 제공합니다. 이 파일은 BpFoo.h 와 유사하지만 바인더를 사용하여 IPC 호출을 전달하는 대신 원하는 기능이 직접 호출됩니다. HAL의 향후 구현에서는 FooFast HAL 및 FooAccurate HAL과 같은 여러 구현을 제공할 수 있습니다 . 이러한 경우 각 추가 구현에 대한 파일이 생성됩니다(예: PTFooFast.cppPTFooAccurate.cpp ).

패스스루 HAL 바인더화

통과 모드를 지원하는 HAL 구현을 바인더화할 수 있습니다. HAL 인터페이스 abcd@MN::IFoo 가 주어지면 두 개의 패키지가 생성됩니다.

  • abcd@MN::IFoo-impl . HAL 구현을 포함하고 IFoo* HIDL_FETCH_IFoo(const char* name) 함수를 노출합니다. 레거시 장치에서 이 패키지는 dlopen 되고 구현은 HIDL_FETCH_IFoo 를 사용하여 인스턴스화됩니다. hidl-gen-Lc++-impl-Landroidbp-impl 을 사용하여 기본 코드를 생성할 수 있습니다.
  • abcd@MN::IFoo-service . 통과 HAL을 열고 자체를 바인더화된 서비스로 등록하여 동일한 HAL 구현을 통과 및 바인더화된 둘 다로 사용할 수 있도록 합니다.

IFoo 유형이 주어지면 sp<IFoo> IFoo::getService(string name, bool getStub) 를 호출하여 IFoo 인스턴스에 액세스할 수 있습니다. getStub 이 true인 경우 getService 는 통과 모드에서만 HAL을 열려고 시도합니다. getStub 이 false인 경우 getService 는 바인더화된 서비스를 찾으려고 시도합니다. 실패하면 통과 서비스를 찾으려고 시도합니다. getStub 매개변수는 defaultPassthroughServiceImplementation 을 제외하고는 절대 사용해서는 안 됩니다. (Android O로 실행되는 기기는 완전히 바인더화된 기기이므로 통과 모드에서 서비스를 여는 것은 허용되지 않습니다.)

HIDL 문법

설계상 HIDL 언어는 C와 유사하지만 C 전처리기를 사용하지 않습니다. 아래에 설명되지 않은 모든 구두점( =| 의 명백한 사용 제외)은 문법의 일부입니다.

참고: HIDL 코드 스타일에 대한 자세한 내용은 코드 스타일 가이드 를 참조하세요.

  • /** */ 는 문서 주석을 나타냅니다. 유형, 메서드, 필드 및 열거형 값 선언에만 적용할 수 있습니다.
  • /* */ 는 여러 줄 주석을 나타냅니다.
  • // 라인의 끝 부분에 대한 주석을 나타냅니다. // 를 제외하고 개행은 다른 공백과 동일합니다.
  • 아래 예제 문법에서 // 부터 줄 끝까지의 텍스트는 문법의 일부가 아니라 문법에 대한 주석입니다.
  • [empty] 는 용어가 비어있을 수 있음을 의미합니다.
  • ? 리터럴 또는 용어 뒤에 오는 것은 선택 사항임을 의미합니다.
  • ... 는 표시된 대로 구두점을 구분하는 0개 이상의 항목을 포함하는 시퀀스를 나타냅니다. HIDL에는 가변 인수가 없습니다.
  • 쉼표는 시퀀스 요소를 구분합니다.
  • 세미콜론은 마지막 요소를 포함하여 각 요소를 종료합니다.
  • 대문자는 비터미널입니다.
  • italicsinteger 또는 identifier (표준 C 구문 분석 규칙)와 같은 토큰 패밀리입니다.
  • constexpr 은 C 스타일 상수 표현식입니다(예: 1 + 11L << 3 ).
  • import_nameHIDL 버전 관리 에 설명된 대로 정규화된 패키지 또는 인터페이스 이름입니다.
  • 소문자 words 는 리터럴 토큰입니다.

예시:

ROOT =
    PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... }  // not for types.hal
  | PACKAGE IMPORTS ITEM ITEM...  // only for types.hal; no method definitions

ITEM =
    ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?;
  |  safe_union identifier { UFIELD; UFIELD; ...};
  |  struct identifier { SFIELD; SFIELD; ...};  // Note - no forward declarations
  |  union identifier { UFIELD; UFIELD; ...};
  |  enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar
  |  typedef TYPE identifier;

VERSION = integer.integer;

PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION;

PREAMBLE = interface identifier EXTENDS

EXTENDS = <empty> | extends import_name  // must be interface, not package

GENERATES = generates (FIELD, FIELD ...)

// allows the Binder interface to be used as a type
// (similar to typedef'ing the final identifier)
IMPORTS =
   [empty]
  |  IMPORTS import import_name;

TYPE =
  uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t |
 float | double | bool | string
|  identifier  // must be defined as a typedef, struct, union, enum or import
               // including those defined later in the file
|  memory
|  pointer
|  vec<TYPE>
|  bitfield<TYPE>  // TYPE is user-defined enum
|  fmq_sync<TYPE>
|  fmq_unsync<TYPE>
|  TYPE[SIZE]

FIELD =
   TYPE identifier

UFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...};
  |  struct identifier { FIELD; FIELD; ...};
  |  union identifier { FIELD; FIELD; ...};
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SIZE =  // Must be greater than zero
     constexpr

ANNOTATIONS =
     [empty]
  |  ANNOTATIONS ANNOTATION

ANNOTATION =
  |  @identifier
  |  @identifier(VALUE)
  |  @identifier(ANNO_ENTRY, ANNO_ENTRY  ...)

ANNO_ENTRY =
     identifier=VALUE

VALUE =
     "any text including \" and other escapes"
  |  constexpr
  |  {VALUE, VALUE ...}  // only in annotations

ENUM_ENTRY =
     identifier
  |  identifier = constexpr