인터페이스 및 패키지

HIDL은 객체 지향 언어에서 동작을 정의하는 데 사용되는 추상 형식인 인터페이스를 기반으로 합니다. 각 인터페이스는 패키지의 일부입니다.

패키지

패키지 이름은 package.subpackage와 같은 하위 수준을 가질 수 있습니다. 게시된 HIDL 패키지의 루트 디렉터리는 hardware/interfaces 또는 vendor/vendorName입니다(예: Pixel 기기의 경우 vendor/google). 패키지 이름은 루트 디렉터리 아래에 하나 이상의 하위 디렉터리를 형성하며, 패키지를 정의하는 모든 파일은 동일한 디렉터리에 있습니다. 예를 들어 package android.hardware.example.extension.light@2.0hardware/interfaces/example/extension/light/2.0 아래에서 찾을 수 있습니다.

다음 표에는 패키지 접두사 및 위치가 나와 있습니다.

패키지 접두사 위치 인터페이스 유형
android.hardware.* hardware/interfaces/* HAL
android.frameworks.* frameworks/hardware/interfaces/* 프레임워크 관련
android.system.* system/hardware/interfaces/* 시스템 관련
android.hidl.* system/libhidl/transport/* 코어

패키지 디렉터리에는 .hal 확장자가 포함된 파일이 있습니다. 모든 파일에는 파일이 속한 패키지와 버전의 이름을 지정하는 package 구문이 포함되어야 합니다. types.hal 파일이 있는 경우 이 파일은 인터페이스를 정의하지 않고, 대신 패키지의 모든 인터페이스에 액세스할 수 있는 데이터 형식을 정의합니다.

인터페이스 정의

types.hal을 제외하고 다른 모든 .hal 파일은 인터페이스를 정의합니다. 인터페이스는 일반적으로 다음과 같이 정의됩니다.

    interface IBar extends IFoo { // IFoo is another interface
        // embedded types
        struct MyStruct {/*...*/};

        // interface methods
        create(int32_t id) generates (MyStruct s);
        close();
    };
    

명시적인 extends 선언이 없는 인터페이스는 암시적으로 android.hidl.base@1.0::IBase에서 확장됩니다(자바의 java.lang.Object와 유사). 암시적으로 가져온 IBase 인터페이스는 여러 예약된 메서드를 선언하는데, 이러한 메서드는 사용자 정의 인터페이스에서 다시 선언되지 않고 선언될 수 없으며 다른 방식으로 사용되지 않고 사용될 수도 없습니다. 이러한 메서드는 다음과 같습니다.

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

가져오기

import 구문은 다른 패키지의 패키지 인터페이스와 형식에 액세스하는 HIDL 메커니즘입니다. import 구문은 다음 두 항목과 관련이 있습니다.

  • 가져오기의 주체가 되는 항목은 패키지 또는 인터페이스일 수 있으며
  • 가져오기의 대상이 되는 항목도 패키지 또는 인터페이스일 수 있습니다.

가져오기의 주체가 되는 항목은 import 구문의 위치에 의해 결정됩니다. 구문이 패키지의 types.hal 내에 있으면 가져오는 것을 전체 패키지에서 볼 수 있습니다. 이것이 패키지 수준 가져오기입니다. 구문이 인터페이스 파일 내에 있으면 가져오기의 주체가 되는 항목은 인터페이스 자체인데 왜냐하면 이것이 인터페이스 수준 가져오기이기 때문입니다.

가져오기의 대상이 되는 항목은 import 키워드 다음에 나오는 값에 의해 결정됩니다. 값이 정규화된 이름일 필요는 없습니다. 구성요소가 생략되면 현재 패키지의 정보로 자동으로 채워집니다. 정규화된 값의 경우 다음 가져오기 사례가 지원됩니다.

  • 전체 패키지 가져오기: 값이 패키지 이름 및 버전(아래에 구문 설명)이면 전체 패키지를 가져오기의 주체가 되는 항목으로 가져옵니다.
  • 부분 가져오기: 값이 다음과 같은 경우입니다.
    • 값이 인터페이스인 경우, 패키지의 types.hal와 해당 인터페이스를 가져오기의 주체가 되는 항목으로 가져옵니다.
    • 값이 types.hal에 정의된 UDT인 경우 UDT만 가져오기의 주체가 되는 항목으로 가져옵니다. types.hal의 다른 형식은 가져올 수 없습니다.
  • 형식만 가져오기: 값이 위에 설명된 부분 가져오기의 구문을 사용하지만, 인터페이스 이름 대신 types 키워드를 사용하는 경우 지정된 패키지의 types.hal에 있는 UDT만 가져옵니다.

가져오기의 주체가 되는 항목은 다음 조합에 액세스할 수 있습니다.

  • types.hal에 정의된, 가져오기의 대상이 되는 패키지의 공통 UDT
  • 가져오기의 대상이 되는 패키지의 인터페이스(전체 패키지 가져오기의 경우) 또는 호출하거나 핸들을 전달하거나 상속을 목적으로 하는 지정된 인터페이스(일부 가져오기의 경우)

import 구문은 정규화된 형식 이름으로 된 구문을 사용하여 가져올 패키지 또는 인터페이스의 이름과 버전을 제공합니다.

    import android.hardware.nfc@1.0;            // import a whole package
    import android.hardware.example@1.0::IQuux; // import an interface and types.hal
    import android.hardware.example@1.0::types; // import just types.hal
    

인터페이스 상속

인터페이스는 이전에 정의된 인터페이스의 확장일 수 있습니다. 확장은 다음 세 가지 유형 중 하나일 수 있습니다.

  • 인터페이스가 API를 변경하지 않은 상태로 수용하여 다른 인터페이스에 기능을 추가할 수 있습니다.
  • 패키지가 API를 변경하지 않은 상태로 수용하여 다른 패키지에 기능을 추가할 수 있습니다.
  • 인터페이스가 패키지 또는 특정 인터페이스에서 형식을 가져올 수 있습니다.

인터페이스는 하나의 다른 인터페이스만 확장할 수 있습니다(다중 상속 불가). 부 버전 번호가 0이 아닌 패키지의 각 인터페이스는 패키지의 이전 버전에서 인터페이스를 확장해야 합니다. 예를 들어 derivative 패키지의 버전 4.0에서 IBar 인터페이스는 original 패키지 1.2 버전의 IFoo 인터페이스를 기반으로 하고(확장하며), original 패키지의 버전 1.3이 생성되는 경우 IBar 버전 4.1은 IFoo 버전 1.3을 확장할 수 없습니다. 대신 IBar 버전 4.1은 IFoo 버전 1.2와 연동된 IBar 버전 4.0을 확장해야 합니다. 원하는 경우 IBar 버전 5.0은 IFoo 버전 1.3을 확장할 수 있습니다.

인터페이스 확장 프로그램은 생성된 코드에 라이브러리 종속성 또는 교차 HAL이 포함된다는 것을 암시하지 않으며, 단순히 HIDL 수준에서 데이터 구조 및 메서드 정의를 가져옵니다. HAL의 모든 메서드는 해당 HAL에 구현되어야 합니다.

공급업체 확장 프로그램

공급업체 확장 프로그램은 확장된 핵심 인터페이스를 나타내는 기본 객체의 서브클래스로 구현되는 경우도 있습니다. 동일한 객체가 기본 HAL 이름 및 버전 아래, 그리고 확장 프로그램의 공급업체 HAL 이름 및 버전 아래에 등록됩니다.

버전 관리

패키지는 버전이 지정되며, 인터페이스는 해당 패키지 버전을 갖습니다. 버전은 .의 두 정수로 표현됩니다.

  • 버전은 이전 버전과 호환되지 않습니다. 주 버전 번호가 증가하면 부 버전 번호는 0으로 재설정됩니다.
  • 버전은 이전 버전과 호환됩니다. 부 버전 번호의 증가는 최신 버전이 이전 버전과 완전히 호환됨을 나타냅니다. 새 데이터 구조 및 메서드를 추가할 수 있지만, 기존 데이터 구조나 메서드 서명은 변경할 수 없습니다.

여러 개의 HAL 주 버전 또는 부 버전이 한 기기에 동시에 존재할 수 있습니다. 그러나 이전 부 버전 인터페이스에서 작동하는 클라이언트 코드는 동일한 인터페이스의 이후 부 버전에서도 작동하므로 부 버전이 주 버전보다 우선해야 합니다. 버전 관리 및 공급업체 확장 프로그램에 관한 자세한 내용은 HIDL 버전 관리를 참조하세요.

인터페이스 레이아웃 요약

이 섹션에서는 HIDL 인터페이스 패키지(예: hardware/interfaces)를 관리하는 방법을 요약하고 HIDL 섹션 전반에서 제공한 정보를 통합합니다. 읽기 전에 HIDL 버전 관리, hidl-gen을 사용한 해싱의 해싱 개념, 일반적인 HIDL 작업의 세부정보 및 다음 정의를 숙지하세요.

용어 정의
ABI(Application Binary Interface) 필요한 애플리케이션 프로그래밍 인터페이스 + 바이너리 링크입니다.
정규화된 이름(fqName) hidl 유형을 구분할 이름입니다. 예: android.hardware.foo@1.0::IFoo
패키지 HIDL 인터페이스 및 유형이 포함된 패키지입니다. 예: android.hardware.foo@1.0
패키지 루트 HIDL 인터페이스를 포함하는 루트 패키지입니다. 예: android.hardware HIDL 인터페이스가 android.hardware.foo@1.0 패키지 루트에 있습니다.
패키지 루트 경로 패키지 루트가 매핑되는 Android 소스 트리의 위치입니다.

자세한 정의는 HIDL 용어를 참조하세요.

모든 파일은 패키지 루트 매핑과 정규화된 이름에서 찾을 수 있습니다.

패키지 루트는 hidl-gen-r android.hardware:hardware/interfaces 인수로 지정됩니다. 예를 들어 패키지가 vendor.awesome.foo@1.0::IFoo이고 hidl-gen-r vendor.awesome:some/device/independent/path/interfaces로 전송되는 경우 인터페이스 파일은 $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal에 있어야 합니다.

실제로는 이름이 awesome인 공급업체나 OEM이 표준 인터페이스를 vendor.awesome에 넣는 것이 좋습니다. 패키지 경로를 선택한 후에는 패키지가 인터페이스의 ABI에 통합되므로 경로를 변경하면 안 됩니다.

패키지 경로 매핑은 고유해야 합니다.

예를 들어 -rsome.package:$PATH_A-rsome.package:$PATH_B가 있는 경우 일관된 인터페이스 디렉터리를 위해 $PATH_A$PATH_B와 동일해야 합니다. 이렇게 하면 인터페이스 버전 관리가 훨씬 더 쉬워집니다.

패키지 루트에는 버전 관리 파일이 있어야 합니다.

-r vendor.awesome:vendor/awesome/interfaces와 같이 패키지 경로를 생성하는 경우에는 $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt 파일도 생성해야 하며, 이 파일에는 hidl-gen-Lhash 옵션을 사용해 만든 인터페이스의 해시가 포함되어야 합니다. 이에 관한 내용은 hidl-gen을 사용한 해싱에서 광범위하게 다룹니다.

인터페이스는 기기와 독립된 위치에 배치됩니다.

실제로는 브랜치 간에 인터페이스를 공유하는 것이 좋습니다. 이를 통해 코드 재사용을 극대화하고 여러 기기 및 사용 사례에서 코드를 최대한 테스트할 수 있습니다.