AIDL 백엔드

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

AIDL 백엔드는 스텁 코드 생성의 대상입니다. AIDL 파일을 사용할 때 항상 특정 런타임과 함께 특정 언어로 파일을 사용합니다. 컨텍스트에 따라 다른 AIDL 백엔드를 사용해야 합니다.

AIDL에는 다음과 같은 백엔드가 있습니다.

백엔드 언어 API 표면 시스템 구축
자바 자바 SDK/SystemApi(안정적*) 모두
NDK C++ libbinder_ndk(안정적*) 보조 인터페이스
CPP C++ libbinder(불안정) 모두
libbinder_rs(불안정) 보조 인터페이스
  • 이러한 API 표면은 안정적이지만 서비스 관리용 API와 같은 많은 API는 내부 플랫폼용으로 예약되어 있으며 앱에서는 사용할 수 없습니다. 앱에서 AIDL을 사용하는 방법에 대한 자세한 내용은 개발자 문서 를 참조하십시오.
  • Rust 백엔드는 Android 12에서 도입되었습니다. NDK 백엔드는 Android 10부터 사용할 수 있습니다.
  • Rust 크레이트는 libbinder_ndk 위에 구축됩니다. APEX는 시스템 측의 다른 사람들과 동일한 방식으로 바인더 상자를 사용합니다. Rust 부분은 APEX에 번들로 포함되어 배송됩니다. 시스템 파티션의 libbinder_ndk.so 에 따라 다릅니다.

시스템 구축

백엔드에 따라 AIDL을 스텁 코드로 컴파일하는 두 가지 방법이 있습니다. 빌드 시스템에 대한 자세한 내용은 Soong Module Reference 를 참조하십시오.

코어 빌드 시스템

모든 cc_ 또는 java_ Android.bp 모듈(또는 Android.mk 에 해당하는 모듈)에서 .aidl 파일을 소스 파일로 지정할 수 있습니다. 이 경우 AIDL의 Java/CPP 백엔드(NDK 백엔드가 아님)가 사용되며 해당 AIDL 파일을 사용하는 클래스가 모듈에 자동으로 추가됩니다. 빌드 시스템에 해당 모듈의 AIDL 파일에 대한 루트 경로를 알려주는 local_include_dirs 와 같은 옵션은 이러한 모듈에서 aidl: 그룹으로 지정할 수 있습니다. Rust 백엔드는 Rust에서만 사용할 수 있습니다. rust_ 모듈은 AIDL 파일이 소스 파일로 지정되지 않는다는 점에서 다르게 처리됩니다. 대신, aidl_interface 모듈은 링크될 수 있는 <aidl_interface name>-rust rustlib 를 생성합니다. 자세한 내용은 Rust AIDL 예제 를 참조하세요.

보조 인터페이스

안정적인 AIDL 을 참조하십시오. 이 빌드 시스템에 사용되는 유형은 구조화되어야 합니다. 즉, AIDL로 직접 표현됩니다. 즉, 맞춤형 소포를 사용할 수 없습니다.

유형

형식에 대한 참조 구현으로 aidl 컴파일러를 고려할 수 있습니다. 인터페이스를 생성할 때 aidl --lang=<backend> ... 를 호출하여 결과 인터페이스 파일을 확인합니다. aidl_interface 모듈을 사용하면 out/soong/.intermediates/<path to module>/ 에서 출력을 볼 수 있습니다.

자바/AIDL 유형 C++ 유형 NDK 유형 녹 유형
부울 부울 부울 부울
바이트 정수8_t 정수8_t i8
char16_t char16_t u16
정수 int32_t int32_t i32
int64_t int64_t i64
뜨다 뜨다 뜨다 f32
더블 더블 더블 f64
안드로이드::문자열16 표준::문자열
android.os.Parcelable android::소포 가능 해당 없음 해당 없음
아이바인더 안드로이드::IBinder ndk::SpAIBinder 바인더::SpIBinder
티[] 표준::벡터<T> 표준::벡터<T> In: &[T]
아웃: Vec<T>
바이트[] 표준::벡터<uint8_t> 표준::벡터<int8_t> 1 입력: &[u8]
아웃: Vec<u8>
목록<T> 표준::벡터<T> 2 표준::벡터<T> 3 In: &[T] 4
아웃: Vec<T>
파일 설명자 android::base::unique_fd 해당 없음 바인더::소포::ParcelFileDescriptor
ParcelFileDescriptor 안드로이드::os::ParcelFileDescriptor ndk::ScopedFileDescriptor 바인더::소포::ParcelFileDescriptor
인터페이스 유형(T) 안드로이드::sp<T> std::shared_ptr<T> 바인더 :: 강한
소포 가능 유형(T)
유니온 타입(T) 5
T[N] 6 표준::배열<T, N> 표준::배열<T, N> [티; N]

1. Android 12 이상에서 바이트 배열은 호환성을 위해 int8_t 대신 uint8_t를 사용합니다.

2. C++ 백엔드는 List<T> 를 지원합니다. 여기서 TString , IBinder , ParcelFileDescriptor 또는 parcelable 중 하나입니다. Android 13 이상에서 T 는 배열을 제외한 모든 비기본 유형(인터페이스 유형 포함)일 수 있습니다. AOSP는 모든 백엔드에서 작동하기 때문에 T[] 와 같은 배열 유형을 사용할 것을 권장합니다.

3. NDK 백엔드는 List<T> 를 지원합니다. 여기서 TString , ParcelFileDescriptor 또는 parcelable 중 하나입니다. Android 13 이상에서 T 는 배열을 제외한 모든 비기본 유형일 수 있습니다.

4. 유형은 입력(인수)인지 출력(반환 값)인지에 따라 Rust 코드에서 다르게 전달됩니다.

5. Union 유형은 Android 12 이상에서 지원됩니다.

6. Android 13 이상에서는 고정 크기 배열이 지원됩니다. 고정 크기 배열은 여러 차원을 가질 수 있습니다(예: int[3][4] ). Java 백엔드에서 고정 크기 배열은 배열 유형으로 표시됩니다.

방향성(in/out/inout)

함수에 대한 인수 유형을 지정할 때 in , out 또는 inout 으로 지정할 수 있습니다. 이것은 IPC 호출에 대해 전달되는 방향 정보를 제어합니다. in 은 기본 방향이며 호출자에서 호출 수신자에게 데이터가 전달됨을 나타냅니다. out 은 데이터가 호출자에서 호출자에게 전달됨을 의미합니다. inout 은 이 둘의 조합입니다. 그러나 Android 팀은 인수 지정자 inout 사용을 피할 것을 권장합니다. 버전이 지정된 인터페이스 및 이전 호출 수신자와 함께 inout 을 사용하는 경우 호출자에게만 존재하는 추가 필드는 기본값으로 재설정됩니다. Rust와 관련하여 일반적인 inout 유형은 &mut Vec<T> 를 수신하고 list inout 유형은 &mut Vec<T> 를 수신합니다.

UTF8/UTF16

CPP 백엔드를 사용하면 문자열이 utf-8인지 utf-16인지 선택할 수 있습니다. 문자열을 AIDL에서 @utf8InCpp String 문자열로 선언하면 자동으로 utf-8로 변환됩니다. NDK 및 Rust 백엔드는 항상 utf-8 문자열을 사용합니다. utf8InCpp 주석에 대한 자세한 내용은 AIDL 의 주석을 참조하십시오.

Null 허용 여부

Java 백엔드에서 null일 수 있는 유형에 @nullable 로 주석을 달아 CPP 및 NDK 백엔드에 null 값을 노출할 수 있습니다. Rust 백엔드에서 이러한 @nullable 유형은 Option<T> 로 노출됩니다. 기본 서버는 기본적으로 null 값을 거부합니다. 이에 대한 유일한 예외는 NDK 읽기 및 CPP/NDK 쓰기에 대해 항상 null일 수 있는 interfaceIBinder 유형입니다. nullable 주석에 대한 자세한 내용은 AIDL의 주석 을 참조하세요.

사용자 정의 Parcelables

코어 빌드 시스템의 C++ 및 Java 백엔드에서 대상 백엔드(C++ 또는 Java)에서 수동으로 구현되는 소포 가능을 선언할 수 있습니다.

    package my.package;
    parcelable Foo;

또는 C++ 헤더 선언 사용:

    package my.package;
    parcelable Foo cpp_header "my/package/Foo.h";

그런 다음 AIDL 파일의 유형으로 이 parcelable을 사용할 수 있지만 AIDL에 의해 생성되지는 않습니다.

Rust는 맞춤형 소포를 지원하지 않습니다.

기본값

구조화된 Parcelable은 이러한 유형의 프리미티브, String 및 배열에 대한 필드별 기본값을 선언할 수 있습니다.

    parcelable Foo {
      int numField = 42;
      String stringField = "string value";
      char charValue = 'a';
      ...
    }

Java 백엔드에서 기본값이 누락된 경우 필드는 기본 유형의 경우 0 값으로 초기화되고 기본이 아닌 유형의 경우 null 로 초기화됩니다.

다른 백엔드에서는 기본값이 정의되지 않은 경우 필드가 기본 초기화 값으로 초기화됩니다. 예를 들어 C++ 백엔드에서 String 필드는 빈 문자열로 초기화되고 List<T> 필드는 빈 vector<T> 로 초기화됩니다. @nullable 필드는 null 값 필드로 초기화됩니다.

오류 처리

Android OS는 오류를 보고할 때 사용할 서비스에 대한 기본 제공 오류 유형을 제공합니다. 이들은 바인더에서 사용되며 바인더 인터페이스를 구현하는 모든 서비스에서 사용할 수 있습니다. 그들의 사용은 AIDL 정의에 잘 설명되어 있으며 사용자 정의 상태 또는 반환 유형이 필요하지 않습니다.

오류가 있는 출력 매개변수

AIDL 함수가 오류를 보고할 때 함수는 출력 매개변수를 초기화하거나 수정하지 않을 수 있습니다. 특히, 트랜잭션 자체를 처리하는 동안 발생하는 것과는 반대로 unparceling하는 동안 오류가 발생하는 경우 출력 매개변수가 수정될 수 있습니다. 일반적으로 AIDL 함수에서 오류가 발생하면 모든 inoutout 매개변수와 반환 값(일부 백엔드에서 out 매개변수처럼 작동함)은 무기한 상태에 있는 것으로 간주해야 합니다.

사용할 오류 값

기본 제공 오류 값의 대부분은 모든 AIDL 인터페이스에서 사용할 수 있지만 일부는 특별한 방식으로 처리됩니다. 예를 들어 EX_UNSUPPORTED_OPERATIONEX_ILLEGAL_ARGUMENT 는 오류 조건을 설명할 때 사용하는 것이 좋지만 EX_TRANSACTION_FAILED 는 기본 인프라에서 특수하게 처리되므로 사용해서는 안 됩니다. 이러한 기본 제공 값에 대한 자세한 내용은 백엔드별 정의를 확인하세요.

AIDL 인터페이스에 기본 제공 오류 유형에서 다루지 않는 추가 오류 값이 필요한 경우 사용자가 정의한 서비스별 오류 값을 포함할 수 있는 특별한 서비스별 기본 제공 오류를 사용할 수 있습니다. . 이러한 서비스별 오류는 일반적으로 AIDL 인터페이스에서 const int 또는 int 지원 enum 으로 정의되며 바인더에 의해 구문 분석되지 않습니다.

Java에서 오류는 android.os.RemoteException 과 같은 예외에 매핑됩니다. 서비스별 예외의 경우 Java는 사용자 정의 오류와 함께 android.os.ServiceSpecificException 을 사용합니다.

Android의 네이티브 코드는 예외를 사용하지 않습니다. CPP 백엔드는 android::binder::Status 를 사용합니다. NDK 백엔드는 ndk::ScopedAStatus 를 사용합니다. AIDL에 의해 생성된 모든 메서드는 메서드의 상태를 나타내는 이들 중 하나를 반환합니다. Rust 백엔드는 NDK와 동일한 예외 코드 값을 사용하지만 사용자에게 전달하기 전에 기본 Rust 오류( StatusCode , ExceptionCode )로 변환합니다. 서비스별 오류의 경우 반환된 Status 또는 ScopedAStatus 는 사용자 정의 오류와 함께 EX_SERVICE_SPECIFIC 를 사용합니다.

기본 제공 오류 유형은 다음 파일에서 찾을 수 있습니다.

백엔드 정의
자바 android/os/Parcel.java
CPP binder/Status.h
NDK android/binder_status.h
android/binder_status.h

다양한 백엔드 사용

이 지침은 Android 플랫폼 코드에만 해당됩니다. 이 예에서는 정의된 유형인 my.package.IFoo 를 사용합니다. Rust 백엔드를 사용하는 방법에 대한 지침은 Android Rust Patterns 페이지에서 Rust AIDL 예제 를 참조하세요.

유형 가져오기

정의된 유형이 인터페이스, Parcelable 또는 Union인지 여부에 관계없이 Java에서 가져올 수 있습니다.

import my.package.IFoo;

또는 CPP 백엔드에서:

#include <my/package/IFoo.h>

또는 NDK 백엔드에서(추가 aidl 네임스페이스 참고):

#include <aidl/my/package/IFoo.h>

또는 Rust 백엔드에서:

use my_package::aidl::my::package::IFoo;

Java에서 중첩 유형을 가져올 수 있지만 CPP/NDK 백엔드에서는 루트 유형에 대한 헤더를 포함해야 합니다. 예를 들어, my/package/IFoo.aidl ( IFoo 는 파일의 루트 유형)에 정의된 중첩 유형 Bar 를 가져올 때 CPP 백엔드에 대해 <my/package/IFoo.h> (또는 <aidl/my/package/IFoo.h> NDK 백엔드).

서비스 구현

서비스를 구현하려면 기본 스텁 클래스에서 상속해야 합니다. 이 클래스는 바인더 드라이버에서 명령을 읽고 구현한 메서드를 실행합니다. 다음과 같은 AIDL 파일이 있다고 상상해보십시오.

    package my.package;
    interface IFoo {
        int doFoo();
    }

Java에서는 다음 클래스에서 확장해야 합니다.

    import my.package.IFoo;
    public class MyFoo extends IFoo.Stub {
        @Override
        int doFoo() { ... }
    }

CPP 백엔드에서:

    #include <my/package/BnFoo.h>
    class MyFoo : public my::package::BnFoo {
        android::binder::Status doFoo(int32_t* out) override;
    }

NDK 백엔드에서(추가 aidl 네임스페이스 참고):

    #include <aidl/my/package/BnFoo.h>
    class MyFoo : public aidl::my::package::BnFoo {
        ndk::ScopedAStatus doFoo(int32_t* out) override;
    }

Rust 백엔드에서:

    use aidl_interface_name::aidl::my::package::IFoo::{BnFoo, IFoo};
    use binder;

    /// This struct is defined to implement IRemoteService AIDL interface.
    pub struct MyFoo;

    impl Interface for MyFoo {}

    impl IFoo for MyFoo {
        fn doFoo(&self) -> binder::Result<()> {
           ...
           Ok(())
        }
    }

서비스 등록 및 받기

플랫폼 Android의 서비스는 일반적으로 servicemanager 프로세스에 등록됩니다. 아래 API 외에도 일부 API는 서비스를 확인합니다(서비스를 사용할 수 없는 경우 즉시 반환됨). 정확한 내용은 해당 servicemanager 인터페이스를 확인하십시오. 이러한 작업은 플랫폼 Android에 대해 컴파일할 때만 수행할 수 있습니다.

자바:

    import android.os.ServiceManager;
    // registering
    ServiceManager.addService("service-name", myService);
    // getting
    myService = IFoo.Stub.asInterface(ServiceManager.getService("service-name"));
    // waiting until service comes up (new in Android 11)
    myService = IFoo.Stub.asInterface(ServiceManager.waitForService("service-name"));
    // waiting for declared (VINTF) service to come up (new in Android 11)
    myService = IFoo.Stub.asInterface(ServiceManager.waitForDeclaredService("service-name"));

CPP 백엔드에서:

    #include <binder/IServiceManager.h>
    // registering
    defaultServiceManager()->addService(String16("service-name"), myService);
    // getting
    status_t err = getService<IFoo>(String16("service-name"), &myService);
    // waiting until service comes up (new in Android 11)
    myService = waitForService<IFoo>(String16("service-name"));
    // waiting for declared (VINTF) service to come up (new in Android 11)
    myService = waitForDeclaredService<IFoo>(String16("service-name"));

NDK 백엔드에서(추가 aidl 네임스페이스 참고):

    #include <android/binder_manager.h>
    // registering
    status_t err = AServiceManager_addService(myService->asBinder().get(), "service-name");
    // getting
    myService = IFoo::fromBinder(SpAIBinder(AServiceManager_getService("service-name")));
    // is a service declared in the VINTF manifest
    // VINTF services have the type in the interface instance name.
    bool isDeclared = AServiceManager_isDeclared("android.hardware.light.ILights/default");
    // wait until a service is available (if isDeclared or you know it's available)
    myService = IFoo::fromBinder(SpAIBinder(AServiceManager_waitForService("service-name")));

Rust 백엔드에서:

use myfoo::MyFoo;
use binder;
use aidl_interface_name::aidl::my::package::IFoo::BnFoo;

fn main() {
    binder::ProcessState::start_thread_pool();
    // [...]
    let my_service = MyFoo;
    let my_service_binder = BnFoo::new_binder(
        my_service,
        BinderFeatures::default(),
    );
    binder::add_service("myservice", my_service_binder).expect("Failed to register service?");
    // Does not return - spawn or perform any work you mean to do before this call.
    binder::ProcessState::join_thread_pool()
}

바인더를 호스팅하는 서비스가 종료될 때 알림을 받도록 요청할 수 있습니다. 이는 콜백 프록시 누출을 방지하거나 오류 복구를 지원하는 데 도움이 될 수 있습니다. 바인더 프록시 개체에서 이러한 호출을 수행합니다.

  • 자바에서는 android.os.IBinder::linkToDeath 를 사용합니다.
  • CPP 백엔드에서 android::IBinder::linkToDeath 를 사용합니다.
  • NDK 백엔드에서 AIBinder_linkToDeath 를 사용합니다.
  • Rust 백엔드에서 DeathRecipient 객체를 만든 다음 my_binder.link_to_death(&mut my_death_recipient) 를 호출하세요. DeathRecipient 가 콜백을 소유하기 때문에 알림을 받고 싶은 한 해당 객체를 활성 상태로 유지해야 합니다.

발신자 정보

커널 바인더 호출을 수신하면 여러 API에서 호출자 정보를 사용할 수 있습니다. PID(또는 프로세스 ID)는 트랜잭션을 보내는 프로세스의 Linux 프로세스 ID를 나타냅니다. UID(또는 사용자 ID)는 Linux 사용자 ID를 나타냅니다. 단방향 호출을 수신할 때 호출 PID는 0입니다. 바인더 트랜잭션 컨텍스트 외부에 있을 때 이러한 함수는 현재 프로세스의 PID 및 UID를 반환합니다.

자바 백엔드에서:

    ... = Binder.getCallingPid();
    ... = Binder.getCallingUid();

CPP 백엔드에서:

    ... = IPCThreadState::self()->getCallingPid();
    ... = IPCThreadState::self()->getCallingUid();

NDK 백엔드에서:

    ... = AIBinder_getCallingPid();
    ... = AIBinder_getCallingUid();

Rust 백엔드에서 인터페이스를 구현할 때 다음을 지정하십시오(기본값으로 허용하는 대신):

    ... = ThreadState::get_calling_pid();
    ... = ThreadState::get_calling_uid();

서비스용 버그 보고서 및 디버깅 API

버그 보고서가 실행되면(예: adb bugreport 사용) 다양한 문제를 디버깅하는 데 도움이 되도록 시스템 전체에서 정보를 수집합니다. AIDL 서비스의 경우 버그 보고서는 서비스 관리자에 등록된 모든 서비스에서 바이너리 dumpsys 를 사용하여 정보를 버그 보고서에 덤프합니다. 명령줄에서 dumpsys 를 사용하여 dumpsys SERVICE [ARGS] 로 서비스에서 정보를 가져올 수도 있습니다. C++ 및 Java 백엔드에서 addService 에 대한 추가 인수를 사용하여 서비스가 덤프되는 순서를 제어할 수 있습니다. 또한 dumpsys --pid SERVICE 를 사용하여 디버깅하는 동안 서비스의 PID를 가져올 수 있습니다.

서비스에 사용자 지정 출력을 추가하려면 AIDL 파일에 정의된 다른 IPC 메서드를 구현하는 것처럼 서버 개체의 dump 메서드를 재정의할 수 있습니다. 이 때 앱 권한 android.permission.DUMP 로 덤핑을 제한하거나 특정 UID로 덤핑을 제한해야 합니다.

자바 백엔드에서:

    @Override
    protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
        @Nullable String[] args) {...}

CPP 백엔드에서:

    status_t dump(int, const android::android::Vector<android::String16>&) override;

NDK 백엔드에서:

    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;

Rust 백엔드에서 인터페이스를 구현할 때 다음을 지정하십시오(기본값으로 허용하는 대신):

    fn dump(&self, mut file: &File, args: &[&CStr]) -> binder::Result<()>

동적으로 인터페이스 설명자 가져오기

인터페이스 설명자는 인터페이스의 유형을 식별합니다. 이것은 디버깅할 때나 알 수 없는 바인더가 있는 경우에 유용합니다.

Java에서는 다음과 같은 코드로 인터페이스 설명자를 얻을 수 있습니다.

    service = /* get ahold of service object */
    ... = service.asBinder().getInterfaceDescriptor();

CPP 백엔드에서:

    service = /* get ahold of service object */
    ... = IInterface::asBinder(service)->getInterfaceDescriptor();

NDK 및 Rust 백엔드는 이 기능을 지원하지 않습니다.

정적으로 인터페이스 설명자 가져오기

때때로(예: @VintfStability 서비스를 등록할 때) 인터페이스 설명자가 정적으로 무엇인지 알아야 합니다. Java에서는 다음과 같은 코드를 추가하여 설명자를 얻을 수 있습니다.

    import my.package.IFoo;
    ... IFoo.DESCRIPTOR

CPP 백엔드에서:

    #include <my/package/BnFoo.h>
    ... my::package::BnFoo::descriptor

NDK 백엔드에서(추가 aidl 네임스페이스 참고):

    #include <aidl/my/package/BnFoo.h>
    ... aidl::my::package::BnFoo::descriptor

Rust 백엔드에서:

    aidl::my::package::BnFoo::get_descriptor()

열거 범위

네이티브 백엔드에서는 열거형이 취할 수 있는 가능한 값을 반복할 수 있습니다. 코드 크기 고려 사항으로 인해 현재 Java에서는 지원되지 않습니다.

AIDL에 정의된 enum MyEnum 에 대해 다음과 같이 iteration이 제공된다.

CPP 백엔드에서:

    ::android::enum_range<MyEnum>()

NDK 백엔드에서:

   ::ndk::enum_range<MyEnum>()

Rust 백엔드에서:

    MyEnum::enum_range()

스레드 관리

프로세스의 모든 libbinder 인스턴스는 하나의 스레드 풀을 유지합니다. 대부분의 사용 사례에서 이것은 모든 백엔드에서 공유되는 정확히 하나의 스레드 풀이어야 합니다. 이에 대한 유일한 예외는 공급업체 코드가 /dev/vndbinder 와 통신하기 위해 libbinder 의 다른 복사본을 로드할 수 있는 경우입니다. 이것은 별도의 바인더 노드에 있으므로 스레드 풀은 공유되지 않습니다.

Java 백엔드의 경우 스레드 풀은 크기만 증가할 수 있습니다(이미 시작되었으므로).

    BinderInternal.setMaxThreads(<new larger value>);

CPP 백엔드의 경우 다음 작업을 사용할 수 있습니다.

    // set max threadpool count (default is 15)
    status_t err = ProcessState::self()->setThreadPoolMaxThreadCount(numThreads);
    // create threadpool
    ProcessState::self()->startThreadPool();
    // add current thread to threadpool (adds thread to max thread count)
    IPCThreadState::self()->joinThreadPool();

마찬가지로 NDK 백엔드에서:

    bool success = ABinderProcess_setThreadPoolMaxThreadCount(numThreads);
    ABinderProcess_startThreadPool();
    ABinderProcess_joinThreadPool();

Rust 백엔드에서:

    binder::ProcessState::start_thread_pool();
    binder::add_service(“myservice”, my_service_binder).expect(“Failed to register service?”);
    binder::ProcessState::join_thread_pool();

예약된 이름

C++, Java 및 Rust는 일부 이름을 키워드로 또는 언어별 사용을 위해 예약합니다. AIDL은 언어 규칙에 따라 제한을 적용하지 않지만 예약된 이름과 일치하는 필드 또는 유형 이름을 사용하면 C++ 또는 Java에 대한 컴파일 실패가 발생할 수 있습니다. Rust의 경우 필드 또는 유형은 r# 접두사를 사용하여 액세스할 수 있는 "원시 식별자" 구문을 사용하여 이름이 바뀝니다.

인체공학적 바인딩이나 완전한 컴파일 실패를 피하기 위해 가능한 경우 AIDL 정의에서 예약된 이름을 사용하지 않는 것이 좋습니다.

AIDL 정의에 이미 예약된 이름이 있는 경우 프로토콜 호환을 유지하면서 필드 이름을 안전하게 바꿀 수 있습니다. 빌드를 계속하려면 코드를 업데이트해야 할 수도 있지만 이미 빌드된 프로그램은 계속해서 상호 운용됩니다.

피해야 할 이름: * C++ 키워드 * Java 키워드 * Rust 키워드