Android 커널 ABI 모니터링

Android 11 이상에서 제공되는 Application Binary Interface(ABI) 모니터링 도구를 사용하여 Android 커널의 커널 내 ABI를 안정화할 수 있습니다. 이 도구는 기존 커널 바이너리(vmlinux + 모듈)에서 ABI 표현을 수집하고 비교합니다. 이러한 ABI 표현은 .stg 파일 및 기호 목록입니다. 표현이 뷰를 제공하는 인터페이스를 커널 모듈 인터페이스(KMI)라고 합니다. 도구를 사용하여 KMI 변경사항을 추적하고 완화할 수 있습니다.

ABI 모니터링 도구는 AOSP에서 개발했으며, STG(Android 13 및 이전 버전에서는 libabigail)를 사용하여 표현을 생성하고 비교합니다.

이 페이지에서는 도구와 ABI 표현 수집 및 분석 프로세스, 이러한 표현을 사용하여 커널 내 ABI에 안정성을 제공하는 방법을 설명합니다. Android 커널의 변경사항 기여에 관한 정보도 제공합니다.

절차

커널의 ABI 분석에는 여러 단계가 필요하며, 이러한 단계는 대부분 자동화할 수 있습니다.

  1. 커널 및 ABI 표현을 빌드합니다.
  2. 빌드와 참조 간의 ABI 차이를 분석합니다.
  3. ABI 표현을 업데이트합니다(필요한 경우).
  4. 기호 목록을 사용합니다.

다음 안내는 지원되는 도구 모음(예: 사전 빌드된 Clang 도구 모음)을 사용하여 빌드할 수 있는 커널에 모두 적용됩니다. repo manifests는 모든 Android 일반 커널 브랜치와 여러 기기별 커널에 사용할 수 있으며 분석을 위해 커널 배포를 빌드할 때 올바른 도구 모음이 사용되도록 합니다.

기호 목록

KMI에는 커널의 기호가 모두 포함되어 있지 않거나 30,000개 이상의 내보낸 기호도 모두 포함되어 있지 않습니다. 대신 모듈에서 사용할 수 있는 기호는 커널 트리의 루트에 공개적으로 유지되는 기호 목록 파일 세트에 명시적으로 나열됩니다. 모든 기호 목록 파일에 있는 모든 기호의 공용체는 안정된 상태로 유지되는 KMI 기호 세트를 정의합니다. 기호 목록 파일의 예는 abi_gki_aarch64_db845c로, DragonBoard 845c에 필요한 기호를 선언합니다.

기호 목록에 나열된 기호와 관련 구조 및 정의만 KMI의 일부로 간주됩니다. 필요한 기호가 없다면 기호 목록에 변경사항을 게시할 수 있습니다. 새 인터페이스가 기호 목록에 있고 따라서 KMI 설명의 일부가 된 이후에 이 인터페이스는 안정적인 상태로 유지되므로 브랜치가 고정된 후 기호 목록에서 제거되거나 수정되어서는 안 됩니다.

각 Android 일반 커널(ACK) KMI 커널 브랜치에는 고유한 기호 목록 세트가 있습니다. 서로 다른 KMI 커널 브랜치 간에 ABI 안정성을 제공하려고 시도하지 않습니다. 예를 들어 android12-5.10용 KMI와 android13-5.10용 KMI는 완전히 별개입니다.

ABI 도구는 KMI 기호 목록을 사용하여 안정성을 위해 모니터링해야 하는 인터페이스를 제한합니다. 기본 기호 목록에는 GKI 커널 모듈에 필요한 기호가 포함되어 있습니다. 공급업체는 사용하는 인터페이스가 ABI 호환성을 유지하도록 추가 기호 목록을 제출하고 업데이트해야 합니다. 예를 들어 android13-5.15 기호 목록의 목록을 보려면 https://android.googlesource.com/kernel/common/+/refs/heads/android13-5.15/android를 참고하세요.

기호 목록에는 특정 공급업체나 기기에 필요한 것으로 보고된 기호가 포함되어 있습니다. 도구에서 사용하는 전체 목록은 모든 KMI 기호 목록 파일의 공용체입니다. ABI 도구는 함수 서명, 중첩 데이터 구조 등 각 기호의 세부정보를 결정합니다.

KMI가 고정되면 기존 KMI 인터페이스는 변경할 수 없습니다(안정적임). 그러나 추가 시 기존 ABI의 안정성에 영향을 미치지 않는 한 공급업체는 언제든지 KMI에 기호를 추가해도 됩니다. 새로 추가된 기호는 KMI 기호 목록에 인용되는 즉시 안정적으로 유지됩니다. 기호는 해당 기호의 종속 항목과 함께 제공된 기기가 없다고 확인되지 않는 한 커널 목록에서 삭제해서는 안 됩니다.

기호 목록을 사용하는 방법의 안내에 따라 기기의 KMI 기호 목록을 생성할 수 있습니다. 많은 파트너가 ACK당 기호 목록 하나를 제출하지만 이는 엄격하게 적용되는 요구사항은 아닙니다. 유지보수에 도움이 된다면 여러 기호 목록을 제출해도 됩니다.

KMI 확장

KMI 기호 및 관련 구조는 안정적인 상태로 유지되지만(고정된 KMI가 있는 커널의 안정적인 인터페이스를 중단시키는 변경사항은 허용되지 않음) GKI 커널은 확장 프로그램에 개방된 상태로 유지되므로 올해 후반기에 제공되는 기기는 KMI가 고정되기 전에 모든 종속 항목을 정의할 필요가 없습니다. KMI를 확장하려면 KMI가 고정되었더라도 내보낸 새 커널 함수나 기존 커널 함수의 경우 KMI에 새 기호를 추가하면 됩니다. 새 커널 패치는 KMI를 중단하지 않는 경우 허용됩니다.

KMI 중단 정보

커널에는 소스가 있고 바이너리는 이러한 소스를 기반으로 빌드됩니다. ABI 모니터링 커널 브랜치에는 현재 GKI ABI를 나타내는 abi.xml이 포함되어 있습니다. 바이너리가 빌드되면(커널 바이너리, vmlinux, Image, 커널 모듈) 바이너리에서 abi.xml 파일을 추출할 수 있습니다. 커널 소스를 변경하면 바이너리가 변경될 수 있고 추출된 abi.xml(변경사항을 적용하고 커널을 빌드한 후 추출된 파일)도 변경될 수 있습니다. AbiAnalyzer 분석 도구는 abi.xml 파일 두 개를 의미론적으로 비교하고 문제가 발견되면 변경사항에 린트-1 라벨을 설정합니다.

ABI 중단 처리

예를 들어 다음 패치는 매우 명백한 ABI 중단을 보여줍니다.

 diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
  index 5ed8f6292a53..f2ecb34c7645 100644
  --- a/include/linux/mm_types.h
  +++ b/include/linux/mm_types.h
  @@ -339,6 +339,7 @@ struct core_state {
   struct kioctx_table;
   struct mm_struct {
      struct {
  +       int dummy;
          struct vm_area_struct *mmap;            /* list of VMAs */
          struct rb_root mm_rb;
          u64 vmacache_seqnum;                   /* per-thread vmacache */

이 패치가 적용된 상태에서 빌드 ABI를 실행하면 도구가 0이 아닌 오류 코드와 함께 종료되고 다음과 같은 ABI 차이가 보고됩니다.

 Leaf changes summary: 1 artifact changed
  Changed leaf types summary: 1 leaf type changed
  Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
  Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable

  'struct mm_struct at mm_types.h:372:1' changed:
    type size changed from 6848 to 6912 (in bits)
    there are data member changes:
  [...]

빌드 시간에 ABI 차이 감지

오류가 발생하는 가장 일반적인 이유는 드라이버가 기호 목록에 없는 커널의 새 기호를 사용하는 경우입니다.

기호가 기호 목록(android/abi_gki_aarch64)에 포함되지 않은 경우 먼저 EXPORT_SYMBOL_GPL(symbol_name)를 사용하여 내보낸 기호인지 확인한 후 ABI XML 표현 및 기호 목록을 업데이트해야 합니다. 예를 들어 다음 변경사항은 기호 목록과 ABI XML 표현을 업데이트하는 작업이 포함된 android-12-5.10 브랜치에 새로운 증분 FS 기능을 추가합니다.

  • 기능 변경 예는 aosp/1345659에서 확인할 수 있습니다.
  • 기호 목록 예는 aosp/1346742에서 확인할 수 있습니다.
  • ABI XML 변경 예는 aosp/1349377에서 확인할 수 있습니다.

기호를 내보냈지만(개발자가 내보내거나 이전에 내보냄) 다른 드라이버에서 현재 기호를 사용하고 있지 않다면 다음과 같은 빌드 오류가 발생할 수도 있습니다.

Comparing the KMI and the symbol lists:
+ build/abi/compare_to_symbol_list out/$BRANCH/common/Module.symvers out/$BRANCH/common/abi_symbollist.raw
ERROR: Differences between ksymtab and symbol list detected!
Symbols missing from ksymtab:
Symbols missing from symbol list:
 - simple_strtoull

이 문제를 해결하려면 커널과 ACK에서 모두 KMI 기호 목록을 업데이트하세요(ABI 표현 업데이트 참고). ACK에서 ABI XML 및 기호 목록을 업데이트하는 예는 aosp/1367601을 참고하세요.

커널 ABI 중단 해결

ABI를 변경하지 않도록 코드를 리팩터링하거나 ABI 표현을 업데이트하여 커널 ABI 중단을 처리할 수 있습니다. 다음 차트를 사용하여 상황에 가장 적합한 접근 방식을 결정하세요.

ABI 중단 흐름 차트

그림 1. ABI 중단 해결

코드를 리팩터링하여 ABI 변경 방지

기존 ABI를 수정하지 않도록 최선을 다하세요. 대부분의 경우 코드를 리팩터링하여 ABI에 영향을 주는 변경사항을 삭제할 수 있습니다.

  • 구조체 필드 변경사항을 리팩터링합니다. 변경사항으로 인해 디버그 기능의 ABI가 수정되는 경우 필드 주위에 #ifdef를 추가하고(구조체 및 소스 참조에서) #ifdef에 사용된 CONFIG가 프로덕션 defconfig 및 gki_defconfig에 사용 중지되어 있는지 확인합니다. ABI를 중단하지 않고 디버그 구성을 구조체에 추가하는 방법에 관한 예는 이 패치 세트를 참고하세요.

  • 핵심 커널을 변경하지 않도록 기능을 리팩터링합니다. 파트너 모듈을 지원하기 위해 새로운 기능을 ACK에 추가해야 하는 경우 커널 ABI를 수정하지 않도록 변경사항의 ABI 부분을 리팩터링해 보세요. 커널 ABI를 변경하지 않고 기존 커널 ABI를 사용하여 기능을 추가하는 방법에 관한 예는 aosp/1312213을 참고하세요.

Android Gerrit에서 중단된 ABI 수정

의도적으로 커널 ABI를 중단하지 않았다면 ABI 모니터링 도구에서 제공하는 안내에 따라 조사해야 합니다. 가장 일반적인 중단 원인은 추가되거나 삭제된 함수, 변경된 데이터 구조 또는 앞서 언급된 것 중 하나로 이어지는 구성 옵션을 추가하여 발생된 ABI 변경입니다. 먼저 도구에서 발견한 문제를 해결합니다.

ABI 결과를 로컬에서 재현할 수 있습니다. 커널 및 ABI 표현 빌드를 참고하세요.

린트-1 라벨 정보

고정되거나 완료된 KMI가 포함된 브랜치에 변경사항을 업로드하는 경우 호환되지 않는 방식으로 안정적인 ABI에 영향을 미치지 않도록 변경사항은 ABIAnalyzer를 통과해야 합니다. 이 과정에서 ABIAnalyzer는 빌드(일반 빌드를 실행한 후 일부 ABI 추출 및 비교 단계를 실행하는 확장 빌드) 중에 생성된 ABI 보고서를 찾습니다. ABIAnalyzer가 비어 있지 않은 보고서를 발견하면 린트-1 라벨을 설정하고 해결될 때까지(패치 세트가 린트+1 라벨을 수신할 때까지) 변경사항 제출이 차단됩니다.

커널 ABI 업데이트

ABI를 수정해야 하는 경우, 코드 변경사항과 ABI 표현, 기호 목록을 ACK에 적용해야 합니다. 린트에서 -1을 삭제하고 GKI 호환성을 손상하지 않도록 하려면 다음 단계를 따르세요.

  1. 코드 변경사항을 ACK에 업로드합니다.

  2. 패치 세트의 코드 검토 +2를 받을 때까지 기다립니다.

  3. 참조 ABI 표현을 업데이트합니다.

  4. 코드 변경사항과 ABI 업데이트 변경사항을 병합합니다.

ACK에 ABI 코드 변경사항 업로드

ACK ABI 업데이트는 변경사항의 유형에 따라 다릅니다.

  • ABI 변경사항이 CTS나 VTS 테스트에 영향을 미치는 기능과 관련이 있는 경우 일반적으로 변경사항을 있는 그대로 ACK로 선별할 수 있습니다. 예를 들면 다음과 같습니다.

  • ABI 변경사항이 ACK와 공유할 수 있는 기능에 관한 것이면 이 변경사항을 ACK로 있는 그대로 선별할 수 있습니다. 예를 들어 다음 변경사항은 CTS나 VTS 테스트에는 필요하지 않지만 ACK와 공유하는 것은 괜찮습니다.

  • ABI 변경에서 ACK에 포함할 필요가 없는 새로운 기능을 도입하면 다음 섹션에 설명된 대로 스텁을 사용하여 기호를 ACK에 도입할 수 있습니다.

ACK에 스텁 사용

스텁은 성능 및 전원 변경사항 등 ACK에 도움이 되지 않는 핵심 커널 변경사항에만 필요해야 합니다. 다음 목록은 GKI의 ACK에서 스텁 및 부분 선별의 예를 자세히 설명합니다.

  • 핵심 격리 기능 스텁(aosp/1284493). ACK의 이 기능은 필요하지 않지만 기호는 모듈에서 이러한 기호를 사용하려면 ACK에 있어야 합니다.

  • 공급업체 모듈의 자리표시자 기호(aosp/1288860)

  • 프로세스별 mm 이벤트 추적 기능의 ABI 전용 선별(aosp/1288454). 원래 패치는 ACK로 선별한 다음 task_structmm_event_count의 ABI 차이를 해결하는 데 필요한 변경사항만 포함하도록 다듬었습니다. 이 패치는 또한 최종 멤버를 포함하도록 mm_event_type enum을 업데이트합니다.

  • 새로운 ABI 필드 추가 이상이 필요한 열 구조체 ABI 변경사항의 일부 선별

    • 패치 aosp/1255544를 통해 파트너 커널과 ACK 간의 ABI 차이를 해결했습니다.

    • 패치 aosp/1291018을 통해 이전 패치의 GKI 테스트 중에 발견된 기능 문제를 수정했습니다. 수정에는 여러 열 영역을 단일 센서에 등록하기 위한 센서 매개변수 구조체 초기화가 포함되었습니다.

  • CONFIG_NL80211_TESTMODE ABI가 변경되었습니다(aosp/1344321). 이 패치를 통해 ABI에 필요한 구조체 변경사항을 추가하고 추가 필드로 인해 기능상의 차이가 발생하지 않도록 했습니다. 따라서 파트너가 프로덕션 커널에 CONFIG_NL80211_TESTMODE를 포함하고 GKI 규정 준수를 계속 유지할 수 있습니다.

런타임에 KMI 적용

GKI 커널은 내보낸 기호(예: EXPORT_SYMBOL_GPL()을 사용하여 내보낸 기호)를 기호 목록에 나열된 기호로 제한하는 TRIM_UNUSED_KSYMS=yUNUSED_KSYMS_WHITELIST=<union of all symbol lists> 구성 옵션을 사용합니다. 다른 모든 기호는 내보내지지 않으며 내보내지 않은 기호가 필요한 모듈을 로드하는 것은 거부됩니다. 이 제한은 빌드 시간에 적용되며 누락된 항목은 신고됩니다.

개발을 위해 기호 자르기가 포함되지 않은 GKI 커널 빌드를 사용할 수 있습니다(즉, 일반적으로 내보낸 모든 기호를 사용할 수 있음). 이러한 빌드를 찾으려면 ci.android.com에서 kernel_debug_aarch64 빌드를 찾으세요.

모듈 버전 관리를 사용하여 KMI 적용

일반 커널 이미지(GKI) 커널은 런타임 시 KMI 규정 준수를 시행하는 추가 조치로 모듈 버전 관리(CONFIG_MODVERSIONS)를 사용합니다. 모듈 버전 관리에서는 모듈의 예상 KMI가 vmlinux KMI와 일치하지 않으면 모듈 로드 시간에 주기적 중복 검사(CRC) 불일치 오류가 발생할 수 있습니다. 예를 들어 다음은 module_layout() 기호의 CRC 불일치로 인해 모듈 로드 시간에 발생하는 일반적인 오류입니다.

init: Loading module /lib/modules/kernel/.../XXX.ko with args ""
XXX: disagrees about version of symbol module_layout
init: Failed to insmod '/lib/modules/kernel/.../XXX.ko' with args ''

모듈 버전 관리 사용

모듈 버전 관리는 다음과 같은 이유로 유용합니다.

  • 모듈 버전 관리에서는 데이터 구조 공개 상태의 변경사항을 포착합니다. 모듈이 불투명한 데이터 구조, 즉 KMI의 일부가 아닌 데이터 구조를 변경하는 경우 향후 구조가 변경되면 모듈이 중단됩니다.

    예를 들어 struct devicefwnode 필드를 고려해 보세요. 이 필드는 모듈이 device->fw_node의 필드를 변경하거나 크기를 가정할 수 없도록 모듈에 불투명해야 합니다(MUST).

    그러나 모듈에 <linux/fwnode.h>가 포함되어 있으면(직접 또는 간접적으로) struct devicefwnode 필드는 더 이상 모듈에 불투명하지 않습니다. 그러면 모듈은 device->fwnode->devdevice->fwnode->ops를 변경할 수 있습니다. 이 시나리오는 다음과 같이 설명된 여러 가지 이유로 문제가 있습니다.

    • 코어 커널 코드의 내부 데이터 구조에 관한 가정이 중단될 수 있습니다.

    • 향후 커널 업데이트에서 struct fwnode_handle(fwnode의 데이터 유형)을 변경하면 모듈이 더 이상 새 커널과 호환되지 않습니다. 또한 abidiff는 어떤 차이점도 표시하지 않습니다. 모듈이 바이너리 표현을 검사하는 것만으로는 캡처할 수 없는 방식으로 내부 데이터 구조를 직접 조작하여 KMI를 중단하기 때문입니다.

  • 현재 모듈은 호환되지 않는 새 커널에서 나중에 로드될 때 KMI 호환되지 않는 것으로 간주됩니다. 모듈 버전 관리는 커널과 KMI 호환되지 않는 모듈을 실수로 로드하지 않도록 런타임 검사를 추가합니다. 이러한 검사는 디버그하기 어려운 런타임 문제와 KMI에서 감지되지 않는 비호환성으로 인해 발생할 수 있는 커널 비정상 종료를 방지합니다.

  • abidiff에는 CONFIG_MODVERSIONS가 포착할 수 있는 복잡한 특정 사례의 ABI 차이를 식별하는 데 제한이 있습니다.

모듈 버전 관리를 사용 설정하면 이러한 문제가 모두 방지됩니다.

기기를 부팅하지 않고 CRC 불일치 확인

abidiff는 커널 간의 CRC 불일치를 비교하고 보고합니다. 이 도구를 사용하면 다른 ABI 차이와 동시에 일치하지 않는 CRC를 포착할 수 있습니다.

또한 CONFIG_MODVERSIONS가 사용 설정된 전체 커널 빌드는 일반적인 빌드 프로세스의 일부로 Module.symvers 파일을 생성합니다. 이 파일에는 커널(vmlinux)과 모듈에서 내보낸 기호마다 한 줄이 있습니다. 각 줄은 CRC 값, 기호 이름, 기호 네임스페이스, 기호를 내보내는 vmlinux 또는 모듈 이름, 내보내기 유형(예: EXPORT_SYMBOL, EXPORT_SYMBOL_GPL)으로 구성됩니다.

GKI 빌드와 개발자 빌드 간의 Module.symvers 파일을 비교하여 vmlinux에서 내보낸 기호의 CRC 차이를 확인할 수 있습니다. vmlinux에서 내보낸 기호에 CRC 값 차이가 있고 그리고 기기에 로드하는 모듈 중 하나에서 이 기호를 사용하는 경우 모듈은 로드되지 않습니다.

빌드 아티팩트가 모두 있지는 않고 GKI 커널과 개발자 커널의 vmlinux 파일은 있다면 두 커널에서 모두 다음 명령어를 실행하여 특정 기호의 CRC 값을 비교할 수 있습니다. 그런 다음 출력을 비교합니다.

nm <path to vmlinux>/vmlinux | grep __crc_<symbol name>

예를 들어 다음 명령어는 module_layout 기호의 CRC 값을 확인합니다.

nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout

CRC 불일치 해결

모듈을 로드할 때 CRC 불일치를 해결하려면 다음 단계를 따르세요.

  1. 다음 명령어와 같이 --kbuild_symtypes 옵션을 사용하여 GKI 커널과 기기 커널을 빌드합니다.

    tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
    

    이 명령어는 각 .o 파일의 .symtypes 파일을 생성합니다. 자세한 내용은 Kleaf의 KBUILD_SYMTYPES를 참고하세요.

    Android 13 및 이전 버전의 경우 다음 명령어와 같이 커널을 빌드하는 데 사용하는 명령어 앞에 KBUILD_SYMTYPES=1을 추가하여 GKI 커널과 기기 커널을 빌드합니다.

    KBUILD_SYMTYPES=1 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
    

    build_abi.sh,를 사용하면 KBUILD_SYMTYPES=1 플래그가 이미 암시적으로 설정됩니다.

  2. 다음 명령어를 사용하여 CRC 불일치가 발생한 기호가 내보내진 .c 파일을 찾습니다.

    cd common && git grep EXPORT_SYMBOL.*module_layout
    kernel/module.c:EXPORT_SYMBOL(module_layout);
    
  3. .c 파일에는 GKI의 상응하는 .symtypes 파일과 기기 커널 빌드 아티팩트가 있습니다. 다음 명령어를 사용하여 .c 파일을 찾습니다.

    cd out/$BRANCH/common && ls -1 kernel/module.*
    kernel/module.o
    kernel/module.o.symversions
    kernel/module.symtypes
    

    .c 파일의 특성은 다음과 같습니다.

    • .c 파일의 형식은 기호당 한 줄(매우 길 수 있음)입니다.

    • 줄 시작 부분에 있는 [s|u|e|etc]#은 기호가 [struct|union|enum|etc] 데이터 유형임을 나타냅니다. 예를 들면 다음과 같습니다.

      t#bool typedef _Bool bool
      
    • 줄 시작 부분에 접두사 #이 없으면 기호가 함수임을 나타냅니다. 예를 들면 다음과 같습니다.

      find_module s#module * find_module ( const char * )
      
  4. 두 파일을 비교하여 차이점을 모두 수정합니다.

사례 1: 데이터 유형 공개 상태로 인한 차이

한 커널은 기호 또는 데이터 유형을 모듈에 불투명하게 유지하고 다른 커널은 그러지 않는다면 두 커널의 .symtypes 파일 사이에 차이가 나타납니다. 커널 중 하나의 .symtypes 파일에는 기호에 관한 UNKNOWN이 있고 다른 커널의 .symtypes 파일에는 기호 또는 데이터 유형의 확장된 뷰가 있습니다.

예를 들어 커널의 include/linux/device.h 파일에 다음 줄을 추가하면 CRC 불일치가 발생하고 그중 하나는 module_layout()용입니다.

 #include <linux/fwnode.h>

이 기호의 module.symtypes를 비교하면 다음과 같은 차이가 표시됩니다.

 $ diff -u <GKI>/kernel/module.symtypes <your kernel>/kernel/module.symtypes
  --- <GKI>/kernel/module.symtypes
  +++ <your kernel>/kernel/module.symtypes
  @@ -334,12 +334,15 @@
  ...
  -s#fwnode_handle struct fwnode_handle { UNKNOWN }
  +s#fwnode_reference_args struct fwnode_reference_args { s#fwnode_handle * fwnode ; unsigned int nargs ; t#u64 args [ 8 ] ; }
  ...

개발자의 커널에는 UNKNOWN 값이 있고 GKI 커널에는 기호의 확장된 뷰가 있다면(가능성이 매우 낮음) 최신 Android 일반 커널을 개발자의 커널에 병합하여 최신 GKI 커널 기반을 사용하도록 합니다.

대부분의 경우 GKI 커널의 값은 UNKNOWN이지만 개발자 커널의 변경사항으로 인해 개발자의 커널에는 기호에 관한 내부 세부정보가 있습니다. 커널의 파일 중 하나가 GKI 커널에 없는 #include를 추가했기 때문입니다.

차이의 원인이 되는 #include를 식별하려면 다음 단계를 따르세요.

  1. 이러한 차이가 있는 기호 또는 데이터 유형을 정의하는 헤더 파일을 엽니다. 예를 들어 struct fwnode_handleinclude/linux/fwnode.h를 수정합니다.

  2. 헤더 파일 상단에 다음 코드를 추가합니다.

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. CRC 불일치가 있는 모듈의 .c 파일에서 #include 줄 앞에 다음을 첫 번째 줄로 추가합니다.

    #define CRC_CATCH 1
    
  4. 모듈을 컴파일합니다. 결과 빌드 시간 오류는 이 CRC 불일치를 일으킨 헤더 파일 #include의 체인을 보여줍니다. 예를 들면 다음과 같습니다.

    In file included from .../drivers/clk/XXX.c:16:`
    In file included from .../include/linux/of_device.h:5:
    In file included from .../include/linux/cpu.h:17:
    In file included from .../include/linux/node.h:18:
    .../include/linux/device.h:16:2: error: "Included from here"
    #error "Included from here"
    

    #include 체인의 링크 중 하나는 개발자 커널의 변경사항으로 인한 것입니다. GKI 커널에는 없는 변경사항입니다.

  5. 변경사항을 식별하고 커널에서 되돌리거나 ACK에 업로드하여 병합되도록 합니다.

사례 2: 데이터 유형 변경으로 인한 차이

기호 또는 데이터 유형의 CRC 불일치가 공개 상태의 차이로 인한 것이 아니라면 데이터 유형 자체의 실제 변경(추가, 삭제, 변경)으로 인한 것입니다. 일반적으로 abidiff는 이를 포착하지만 알려진 감지 간격으로 인해 놓친다면 MODVERSIONS 메커니즘에서 이를 포착할 수 있습니다.

예를 들어 커널에서 다음과 같이 변경하면 여러 CRC 불일치가 발생합니다. 많은 기호가 이 유형의 변경으로 인해 간접적으로 영향을 받기 때문입니다.

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
  --- a/include/linux/iommu.h
  +++ b/include/linux/iommu.h
  @@ -259,7 +259,7 @@ struct iommu_ops {
     void (*iotlb_sync)(struct iommu_domain *domain);
     phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);
     phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
  -        dma_addr_t iova);
  +        dma_addr_t iova, unsigned long trans_flag);
     int (*add_device)(struct device *dev);
     void (*remove_device)(struct device *dev);
     struct iommu_group *(*device_group)(struct device *dev);

한 가지 CRC 불일치는 devm_of_platform_populate()입니다.

이 기호의 .symtypes 파일을 비교하면 다음과 같을 수 있습니다.

 $ diff -u <GKI>/drivers/of/platform.symtypes <your kernel>/drivers/of/platform.symtypes
  --- <GKI>/drivers/of/platform.symtypes
  +++ <your kernel>/drivers/of/platform.symtypes
  @@ -399,7 +399,7 @@
  ...
  -s#iommu_ops struct iommu_ops { ... ; t#phy
  s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t ) ; int
    ( * add_device ) ( s#device * ) ; ...
  +s#iommu_ops struct iommu_ops { ... ; t#phy
  s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t , unsigned long ) ; int ( * add_device ) ( s#device * ) ; ...

변경된 유형을 식별하려면 다음 단계를 따르세요.

  1. 소스 코드(일반적으로 .h 파일)에서 기호의 정의를 찾습니다.

    • 개발자의 커널과 GKI 커널 간의 간단한 기호 차이는 다음 명령어를 실행하여 커밋을 찾습니다.
    git blame
    
    • 삭제된 기호(기호가 트리에서 삭제되고 다른 트리에서도 삭제하려는 경우)의 경우 줄을 삭제한 변경사항을 찾아야 합니다. 줄이 삭제된 트리에서 다음 명령어를 사용합니다.
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
    
  2. 반환된 커밋 목록을 검토하여 변경사항 또는 삭제를 찾습니다. 첫 번째 커밋이 찾고 있는 것일 수 있습니다. 찾고 있는 커밋이 아니라면 커밋을 찾을 때까지 목록을 살펴봅니다.

  3. 변경사항을 식별한 후에는 커널에서 되돌리거나 ACK에 업로드하여 병합되도록 합니다.