GKI용 커널 코드 개발

GKI(Generic Kernel Image)는 업스트림 Linux 커널과 긴밀하게 정렬하여 커널 조각화를 줄입니다. 그러나 일부 패치를 업스트림으로 수락할 수 없는 타당한 이유가 있고 충족해야 하는 제품 일정이 있으므로 일부 패치는 GKI가 빌드된 Android 공통 커널(ACK) 소스에서 유지 관리됩니다.

개발자는 LKML(Linux Kernel Mailing List)을 첫 번째 선택으로 사용하여 코드 변경 사항을 업스트림으로 제출하고 업스트림이 실행 가능하지 않은 강력한 이유가 있는 경우에만 ACK android-mainline 분기에 코드 변경 사항을 제출해야 합니다. 정당한 사유의 예와 처리방법은 다음과 같습니다.

  • 패치는 LKML에 제출되었지만 제품 릴리스에 맞춰 승인되지 않았습니다. 이 패치를 처리하려면:

    • 패치가 LKML에 제출되었고 패치에 대한 의견이 접수되었다는 증거 또는 패치가 업스트림으로 제출될 예상 시간을 제공하십시오.
    • 패치를 ACK에 배치하고 업스트림에서 승인을 받은 다음 최종 업스트림 버전이 ACK에 병합되면 ACK에서 제거하는 작업 과정을 결정합니다.
  • 패치는 공급업체 모듈에 대한 EXPORT_SYMBOLS_GPL() 정의하지만 해당 기호를 사용하는 트리 내 모듈이 없기 때문에 업스트림으로 제출할 수 없습니다. 이 패치를 처리하려면 모듈을 업스트림으로 제출할 수 없는 이유와 이 요청을 하기 전에 고려한 대안에 대한 세부 정보를 제공하십시오.

  • 패치는 업스트림용으로 충분히 일반적이지 않으며 제품 릴리스 전에 리팩토링할 시간이 없습니다. 이 패치를 처리하려면 리팩토링된 패치가 업스트림으로 제출되는 예상 시간을 제공하십시오(패치는 검토를 위해 리팩토링된 패치 업스트림을 제출할 계획이 없으면 ACK에서 수락되지 않습니다).

  • 업스트림에서 패치를 수락할 수 없는 이유는... <insert reason here> . 이 패치를 처리하려면 Android 커널 팀에 연락하여 검토를 위해 제출하고 업스트림에서 수락할 수 있도록 패치를 리팩터링하는 옵션에 대해 저희와 함께 작업하세요.

더 많은 잠재적 정당화가 있습니다. 버그 또는 패치를 제출할 때 유효한 근거를 포함하고 일부 반복 및 토론을 기대하십시오. 모든 사람이 업스트림 작업 방법을 배우고 있지만 그렇게 하기 위해 제품 일정을 늦출 수는 없는 동안 특히 GKI의 초기 단계에서 ACK가 일부 패치를 수행할 것임을 알고 있습니다. 시간이 지남에 따라 업스트림 요구 사항이 더욱 엄격해질 것으로 예상됩니다.

패치 요구 사항

패치는 업스트림으로 제출되든 ACK에 제출되든 Linux 소스 트리 에 설명된 Linux 커널 코딩 표준을 준수해야 합니다. scripts/checkpatch.pl 스크립트는 Gerrit 사전 제출 테스트의 일부로 실행되므로 사전에 실행하여 통과하는지 확인하십시오. 사전 제출 테스트와 동일한 구성으로 checkpatch 스크립트를 실행하려면 repo 체크아웃에서 build/static_analysis/checkpatch_presubmit.sh 사용하십시오.

ACK 패치

ACK에 제출된 패치는 Linux 커널 코딩 표준 및 기여 지침을 준수해야 합니다. 커밋 메시지에 Change-Id 태그를 포함해야 합니다. 패치를 여러 브랜치(예: android-mainlineandroid12-5.4 )에 제출하는 경우 패치의 모든 인스턴스에 대해 동일한 Change-Id 사용해야 합니다.

업스트림 검토를 위해 먼저 LKML에 패치를 제출하십시오. 패치가 다음과 같은 경우:

  • 업스트림이 허용되면 자동으로 android-mainline 에 병합됩니다.
  • 허용되지 않는 업스트림, 업스트림 제출에 대한 참조 또는 LKML에 제출되지 않은 이유에 대한 설명과 함께 android-mainline 에 제출하세요.

패치가 업스트림 또는 android-mainline 에서 승인되면 적절한 LTS 기반 ACK(예: Android 관련 코드를 수정하는 패치의 경우 android12-5.4android11-5.4 )로 백포트될 수 있습니다. android-mainline 에 제출하면 새로운 업스트림 릴리스 후보로 테스트할 수 있고 패치가 다음 LTS 기반 ACK에 있음을 보장할 수 있습니다. 업스트림 패치가 android12-5.4 로 백포트되는 경우는 예외입니다(패치가 이미 android-mainline 에 있을 가능성이 높기 때문).

업스트림 패치

기여 지침 에 지정된 대로 ACK 커널을 대상으로 하는 업스트림 패치는 다음 그룹에 속합니다(허용될 가능성이 있는 순서대로 나열됨).

  • UPSTREAM: - 합당한 사용 사례가 있는 경우 'android-mainline'에서 선별된 패치가 ACK에 허용될 가능성이 높습니다.
  • BACKPORT: - 적절하게 선별되지 않고 수정이 필요한 업스트림의 패치도 합당한 사용 사례가 있는 경우 허용될 가능성이 높습니다.
  • FROMGIT: - Linux 메인라인에 제출하기 위해 유지 관리 브랜치에서 선별한 패치는 다가오는 마감일이 있는 경우 수락될 수 있습니다. 내용과 일정 모두에 대해 정당화되어야 합니다.
  • FROMLIST: - LKML에 제출되었지만 유지 관리자 브랜치에 아직 승인되지 않은 패치는 패치가 업스트림 Linux에 있는지 여부에 관계없이 패치가 승인될 만큼 정당성이 충분히 설득력이 없는 한 승인될 가능성이 낮습니다. 않을 것입니다). Android 커널 팀과의 논의를 용이하게 하려면 FROMLIST 패치와 관련된 문제가 있어야 합니다.

Android 관련 패치

필요한 변경 사항을 업스트림에 적용할 수 없는 경우 트리 외부 패치를 ACK에 직접 제출할 수 있습니다. 트리 외부 패치를 제출하려면 IT에서 패치를 인용하는 문제를 만들고 패치를 업스트림으로 제출할 수 없는 이유를 설명해야 합니다(이전 목록의 예 참조). 그러나 코드를 업스트림으로 제출할 수 없는 몇 가지 경우가 있습니다. 이러한 사례는 다음과 같이 다루어지며 Android 관련 패치에 대한 기여 지침을 따르고 제목에 ANDROID: 접두사 태그가 지정되어야 합니다.

gki_defconfig 변경 사항

CONFIG 아키텍처에 한정되지 않는 한 gki_defconfig 에 대한 모든 CONFIG 변경 사항은 arm64 및 x86 버전 모두에 적용되어야 합니다. CONFIG 설정에 대한 변경을 요청하려면 IT에서 문제를 만들어 변경 사항을 논의하십시오. 고정된 후 KMI(커널 모듈 인터페이스)에 영향을 주는 모든 CONFIG 변경 사항은 거부됩니다. 파트너가 단일 구성에 대해 상충되는 설정을 요청하는 경우 관련 버그에 대한 토론을 통해 충돌을 해결합니다.

업스트림에 존재하지 않는 코드

이미 Android 전용인 코드에 대한 수정 사항은 업스트림으로 보낼 수 없습니다. 예를 들어 바인더 드라이버가 업스트림으로 유지되더라도 바인더 드라이버의 우선 순위 상속 기능에 대한 수정 사항은 Android 전용이기 때문에 업스트림으로 보낼 수 없습니다. 코드를 업스트림으로 보낼 수 없는 이유를 버그 및 패치에 명시하십시오. 가능하면 패치를 업스트림으로 제출할 수 있는 조각과 업스트림으로 제출할 수 없는 Android 관련 조각으로 분할하여 ACK에서 유지 관리되는 트리 외부 코드의 양을 최소화합니다.

이 범주의 다른 변경 사항은 KMI 표시 파일, KMI 기호 목록, gki_defconfig , 빌드 스크립트 또는 구성 또는 업스트림에 존재하지 않는 기타 스크립트에 대한 업데이트입니다.

트리 외부 모듈

업스트림 Linux는 트리 외부 모듈 빌드에 대한 지원을 적극적으로 권장하지 않습니다. 이는 Linux 관리자가 커널 내 소스 또는 바이너리 호환성에 대해 보장하지 않고 트리에 없는 코드를 지원하기를 원하지 않는다는 점에서 합리적인 입장입니다. 그러나 GKI는 공급업체 모듈에 대해 ABI를 보장 하여 지원되는 커널 수명 동안 KMI 인터페이스가 안정적임을 보장합니다. 따라서 ACK에는 허용되지만 업스트림에는 허용되지 않는 공급업체 모듈을 지원하기 위한 변경 클래스가 있습니다.

예를 들어 내보내기를 사용하는 모듈이 소스 트리에 없는 EXPORT_SYMBOL_GPL() 매크로를 추가하는 패치를 고려하십시오. EXPORT_SYMBOL_GPL() 업스트림을 요청하고 새로 내보낸 기호를 사용하는 모듈을 제공해야 하지만 모듈이 업스트림으로 제출되지 않는 이유에 대한 유효한 정당성이 있는 경우 대신 ACK에 패치를 제출할 수 있습니다. 문제에서 모듈을 업스트림할 수 없는 이유에 대한 근거를 포함해야 합니다. (GPL이 아닌 변형 EXPORT_SYMBOL() 을 요청하지 마십시오.)

숨겨진 구성

일부 트리 내 모듈은 gki_defconfig 에서 지정할 수 없는 숨겨진 구성을 자동으로 선택합니다. 예를 들어 CONFIG_SND_SOC_TOPOLOGY CONFIG_SND_SOC_SOF=y 가 구성된 경우 자동으로 선택됩니다. 트리 외부 모듈 빌드를 수용하기 위해 GKI에는 숨겨진 구성을 활성화하는 메커니즘이 포함되어 있습니다.

숨겨진 구성을 활성화하려면 gki_defconfig 에서 활성화된 CONFIG_GKI_HACKS_TO_FIX 커널 구성에 따라 자동으로 선택되도록 init/Kconfig.gkiselect 문을 추가합니다. 숨겨진 구성에만 이 메커니즘을 사용하십시오. 구성이 숨겨져 있지 않으면 명시적으로 또는 종속성으로 gki_defconfig 에 지정되어야 합니다.

로드 가능한 거버너

로드 가능한 거버너를 지원하는 커널 프레임워크(예: cpufreq )의 경우 기본 거버너(예: cpufreqschedutil 거버너)를 재정의할 수 있습니다. 로드 가능한 거버너 또는 드라이버를 지원하지 않지만 여전히 공급업체별 구현, IT에서 문제를 생성하고 Android 커널 팀 과 협의합니다.

필요한 지원을 추가하기 위해 귀하 및 업스트림 관리자와 협력할 것입니다.

공급업체 후크

이전 릴리스에서는 공급업체별 수정 사항을 코어 커널에 직접 추가할 수 있었습니다. GKI 2.0에서는 제품별 코드가 모듈에서 구현되어야 하고 코어 커널 업스트림 또는 ACK에서 허용되지 않기 때문에 이는 불가능합니다. 핵심 커널 코드에 미치는 영향을 최소화하면서 파트너가 의존하는 부가 가치 기능을 활성화하기 위해 GKI는 핵심 커널 코드에서 모듈을 호출할 수 있도록 하는 공급업체 후크를 허용합니다. 또한 이러한 기능을 구현하기 위해 공급업체별 데이터를 저장하는 데 사용할 수 있는 공급업체 데이터 필드로 주요 데이터 구조를 채울 수 있습니다.

공급업체 후크는 공급업체 모듈이 연결할 수 있는 추적점(추적 이벤트가 아님)을 기반으로 하는 두 가지 변형(일반 및 제한)으로 제공됩니다. 예를 들어, 작업 종료 시 회계를 수행하기 위해 새로운 sched_exit() 함수를 추가하는 대신 공급업체는 처리를 위해 공급업체 모듈이 연결할 수 있는 do_exit() 에 후크를 추가할 수 있습니다. 예제 구현에는 다음 벤더 후크가 포함됩니다.

  • 일반 공급업체 후크는 DECLARE_HOOK() 사용하여 trace_ name 이름의 추적점 함수를 생성합니다. 여기서 name 추적의 고유 식별자입니다. 규칙에 따라 일반 공급업체 후크 이름은 android_vh 로 시작하므로 sched_exit() 후크의 이름은 android_vh_sched_exit 입니다.
  • 제한된 공급업체 후크는 CPU가 오프라인이거나 비원자적 컨텍스트가 필요한 경우에도 연결된 함수를 호출해야 하는 스케줄러 후크와 같은 경우에 필요합니다. 제한된 공급업체 후크는 분리할 수 없으므로 제한된 후크에 연결된 모듈은 언로드할 수 없습니다. 하나의 첨부 파일만 허용되므로 다른 첨부 시도는 -EBUSY 로 인해 실패합니다. 제한된 공급업체 후크 이름은 android_rvh 로 시작합니다.

공급업체 후크를 추가하려면 IT 부서에 문제를 제출하고 패치를 제출하세요(모든 Android 관련 패치와 마찬가지로 문제가 존재해야 하며 정당성을 제공해야 합니다). 공급업체 후크에 대한 지원은 ACK에만 있으므로 이러한 패치를 업스트림 Linux로 보내지 마십시오.

구조에 공급업체 필드 추가

ANDROID_VENDOR_DATA() 매크로를 사용하여 android_vendor_data 필드를 추가하여 공급업체 데이터를 주요 데이터 구조와 연결할 수 있습니다. 예를 들어 부가 가치 기능을 지원하려면 다음 코드 샘플과 같이 구조에 필드를 추가합니다.

공급업체에 필요한 필드와 OEM에 필요한 필드 간의 잠재적인 충돌을 방지하기 위해 OEM은 ANDROID_VENDOR_DATA() 매크로를 사용하여 선언된 필드를 사용해서는 안 됩니다. 대신 OEM은 ANDROID_OEM_DATA() 사용하여 android_oem_data 필드를 선언해야 합니다.

#include <linux/android_vendor.h>
...
struct important_kernel_data {
  [all the standard fields];
  /* Create vendor data for use by hook implementations. The
   * size of vendor data is based on vendor input. Vendor data
   * can be defined as single u64 fields like the following that
   * declares a single u64 field named "android_vendor_data1" :
   */
  ANDROID_VENDOR_DATA(1);

  /*
   * ...or an array can be declared. The following is equivalent to
   * u64 android_vendor_data2[20]:
   */
  ANDROID_VENDOR_DATA_ARRAY(2, 20);

  /*
   * SoC vendors must not use fields declared for OEMs and
   * OEMs must not use fields declared for SoC vendors.
   */
  ANDROID_OEM_DATA(1);

  /* no further fields */
}

공급업체 후크 정의

공급업체 후크를 DECLARE_HOOK() 또는 DECLARE_RESTRICTED_HOOK() 사용하여 선언한 다음 추적점으로 코드에 추가하여 추적점으로 커널 코드에 공급업체 후크를 추가합니다. 예를 들어 trace_android_vh_sched_exit() 기존 do_exit() 커널 함수에 추가하려면:

#include <trace/hooks/exit.h>
void do_exit(long code)
{
    struct task_struct *tsk = current;
    ...
    trace_android_vh_sched_exit(tsk);
    ...
}

trace_android_vh_sched_exit() 함수는 초기에 무언가가 첨부되어 있는지 확인합니다. 그러나 벤더 모듈이 register_trace_android_vh_sched_exit() 사용하여 핸들러를 등록하면 등록된 함수가 호출됩니다. 핸들러는 보류된 잠금, RCS 상태 및 기타 요소와 관련된 컨텍스트를 인식해야 합니다. 후크는 include/trace/hooks 디렉토리의 헤더 파일에 정의되어야 합니다.

예를 들어, 다음 코드는 include/trace/hooks/exit.h 파일에서 trace_android_vh_sched_exit() 에 대한 가능한 선언을 제공합니다.

/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM sched
#define TRACE_INCLUDE_PATH trace/hooks

#if !defined(_TRACE_HOOK_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HOOK_SCHED_H
#include <trace/hooks/vendor_hooks.h>
/*
 * Following tracepoints are not exported in tracefs and provide a
 * mechanism for vendor modules to hook and extend functionality
 */

struct task_struct;

DECLARE_HOOK(android_vh_sched_exit,
             TP_PROTO(struct task_struct *p),
             TP_ARGS(p));

#endif /* _TRACE_HOOK_SCHED_H */

/* This part must be outside protection */
#include <trace/define_trace.h>

벤더 후크에 필요한 인터페이스를 인스턴스화하려면 drivers/android/vendor_hooks.c 에 후크 선언이 있는 헤더 파일을 추가하고 기호를 내보냅니다. 예를 들어 다음 코드는 android_vh_sched_exit() 후크 선언을 완료합니다.

#ifndef __GENKSYMS__
/* struct task_struct */
#include <linux/sched.h>
#endif

#define CREATE_TRACE_POINTS
#include <trace/hooks/vendor_hooks.h>
#include <trace/hooks/exit.h>
/*
 * Export tracepoints that act as a bare tracehook (i.e. have no trace
 * event associated with them) to allow external modules to probe
 * them.
 */
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sched_exit);

참고 : 후크 선언 내에서 사용되는 데이터 구조는 ABI 안정성을 보장하기 위해 완전히 정의되어야 합니다. 그렇지 않으면 불투명 포인터를 역참조하거나 크기가 조정된 컨텍스트에서 구조체를 사용하는 것이 안전하지 않습니다. 이러한 데이터 구조의 전체 정의를 제공하는 포함은 drivers/android/vendor_hooks.c#ifndef __GENKSYMS__ 섹션 내부에 있어야 합니다. include/trace/hooks 의 헤더 파일은 KMI를 손상시키는 CRC 변경을 피하기 위해 유형 정의가 있는 커널 헤더 파일을 포함하지 않아야 합니다. 대신 유형을 앞으로 선언하십시오.

공급업체 후크에 연결

공급업체 후크를 사용하려면 공급업체 모듈이 후크에 대한 처리기를 등록해야 합니다(일반적으로 모듈 초기화 중에 수행됨). 예를 들어 다음 코드는 trace_android_vh_sched_exit() 에 대한 모듈 foo.ko 핸들러를 보여줍니다.

#include <trace/hooks/sched.h>
...
static void foo_sched_exit_handler(void *data, struct task_struct *p)
{
    foo_do_exit_accounting(p);
}
...
static int foo_probe(..)
{
    ...
    rc = register_trace_android_vh_sched_exit(foo_sched_exit_handler, NULL);
    ...
}

핵심 커널 기능

이전 기술 중 어느 것도 모듈에서 기능을 구현할 수 없는 경우 해당 기능을 코어 커널에 Android 관련 수정으로 추가해야 합니다. 문제 추적기(IT)에서 문제를 만들어 대화를 시작하세요.

사용자 애플리케이션 프로그래밍 인터페이스(UAPI)

  • UAPI 헤더 파일. UAPI 헤더 파일 에 대한 변경 사항은 Android 관련 인터페이스에 대한 변경 사항이 아닌 한 업스트림에서 발생해야 합니다. 공급업체별 헤더 파일을 사용하여 공급업체 모듈과 공급업체 사용자 공간 코드 간의 인터페이스를 정의합니다.
  • sysfs 노드. GKI 커널에 새 sysfs 노드를 추가하지 마세요(이러한 추가는 공급업체 모듈에서만 유효함). Android 프레임워크를 구성하는 SoC 및 기기에 구애받지 않는 라이브러리와 Java 코드에서 사용하는 sysfs 노드는 호환되는 방식으로만 변경할 수 있으며 Android 관련 sysfs 노드가 아닌 경우 업스트림에서 변경해야 합니다. 공급업체 사용자 공간에서 사용할 공급업체별 sysfs 노드를 생성 할 수 있습니다 . 기본적으로 사용자 공간에 의한 sysfs 노드에 대한 액세스는 SELinux를 사용하여 거부됩니다. 인증된 공급업체 소프트웨어의 액세스를 허용하기 위해 적절한 SELinux 레이블을 추가하는 것은 공급업체의 책임입니다.
  • DebugFS 노드. 공급업체 모듈은 디버그용으로만 debugfs 에서 노드를 정의할 수 있습니다( debugfs 장치의 정상 작동 중에 마운트되지 않음).