Generic Kernel Image (GKI) làm giảm sự phân mảnh kernel bằng cách căn chỉnh chặt chẽ với kernel Linux ngược dòng. Tuy nhiên, có những lý do chính đáng khiến một số bản vá không thể được chấp nhận ngược dòng và có những lịch trình sản phẩm phải được đáp ứng, vì vậy một số bản vá được duy trì trong các nguồn Hạt nhân chung (ACK) của Android mà từ đó GKI được tạo.
Các nhà phát triển phải gửi các thay đổi mã ngược dòng bằng cách sử dụng Danh sách gửi thư hạt nhân Linux (LKML) làm lựa chọn đầu tiên và chỉ gửi các thay đổi mã tới nhánh ACK android-mainline
khi có lý do chính đáng khiến việc ngược dòng không khả thi. Ví dụ về lý do hợp lệ và cách xử lý chúng được liệt kê như sau.
Bản vá đã được gửi tới LKML, nhưng không được chấp nhận kịp thời để phát hành sản phẩm. Để xử lý bản vá này:
- Cung cấp bằng chứng rằng bản vá đã được gửi tới LKML và nhận xét nhận được cho bản vá hoặc thời gian ước tính mà bản vá sẽ được gửi ngược dòng.
- Quyết định một quá trình hành động để đưa bản vá vào ACK, phê duyệt nó ngược dòng và sau đó đưa nó ra khỏi ACK khi phiên bản ngược dòng cuối cùng được hợp nhất vào ACK.
Bản vá xác định
EXPORT_SYMBOLS_GPL()
cho mô-đun của nhà cung cấp, nhưng không thể gửi ngược dòng vì không có mô-đun trong cây nào sử dụng biểu tượng đó. Để xử lý bản vá lỗi này, hãy cung cấp thông tin chi tiết về lý do tại sao mô-đun của bạn không thể được gửi ngược dòng và các giải pháp thay thế mà bạn đã cân nhắc trước khi đưa ra yêu cầu này.Bản vá không đủ chung cho thượng nguồn và không có thời gian để cấu trúc lại nó trước khi phát hành sản phẩm. Để xử lý bản vá này, hãy cung cấp thời gian ước tính mà một bản vá tái cấu trúc sẽ được gửi ngược dòng (bản vá sẽ không được chấp nhận trong ACK nếu không có kế hoạch gửi bản vá tái cấu trúc ngược dòng để xem xét).
Bản vá không thể được chấp nhận bởi thượng nguồn vì... <chèn lý do tại đây> . Để xử lý bản vá này, hãy liên hệ với nhóm nhân Android và làm việc với chúng tôi về các tùy chọn để cấu trúc lại bản vá để có thể gửi bản vá để xem xét và chấp nhận ngược dòng.
Có rất nhiều biện minh tiềm năng hơn. Khi bạn gửi lỗi hoặc bản vá của mình, hãy đưa ra lời giải thích hợp lệ và mong đợi một số lần lặp lại và thảo luận. Chúng tôi nhận thấy rằng ACK sẽ mang theo một số bản vá lỗi, đặc biệt là trong giai đoạn đầu của GKI khi mọi người đang học cách làm việc ngược dòng nhưng không thể nới lỏng lịch trình sản phẩm để làm như vậy. Mong đợi các yêu cầu ngược dòng trở nên nghiêm ngặt hơn theo thời gian.
Yêu cầu bản vá
Các bản vá phải tuân thủ các tiêu chuẩn mã hóa nhân Linux được mô tả trong cây nguồn Linux , cho dù chúng được gửi ngược dòng hay ACK. Tập lệnh scripts/checkpatch.pl
được chạy như một phần của quá trình thử nghiệm trước khi gửi cho Gerrit, vì vậy hãy chạy tập lệnh này trước để đảm bảo rằng tập lệnh sẽ vượt qua. Để chạy tập lệnh checkpatch có cùng cấu hình với thử nghiệm gửi trước, hãy sử dụng build/static_analysis/checkpatch_presubmit.sh
từ kiểm tra repo
.
bản vá ACK
Các bản vá được gửi tới ACK phải phù hợp với các tiêu chuẩn mã hóa nhân Linux và các nguyên tắc đóng góp . Bạn phải bao gồm thẻ Change-Id
trong thông báo cam kết; nếu bạn gửi bản vá tới nhiều nhánh (ví dụ: android-mainline
và android12-5.4
), thì bạn phải sử dụng cùng một Change-Id
cho tất cả các phiên bản của bản vá.
Trước tiên hãy gửi các bản vá tới LKML để xem xét ngược dòng. Nếu bản vá là:
- Được chấp nhận ngược dòng, nó được tự động hợp nhất vào
android-mainline
. - Không được chấp nhận ngược dòng, hãy gửi nó tới
android-mainline
với tham chiếu đến lần gửi ngược dòng hoặc giải thích lý do tại sao nó không được gửi tới LKML.
Sau khi một bản vá được chấp nhận ngược dòng hoặc trong android-mainline
, bản vá đó có thể được nhập vào ACK dựa trên LTS thích hợp (chẳng hạn như android12-5.4
và android11-5.4
đối với các bản vá sửa mã dành riêng cho Android). Gửi lên android-mainline
cho phép thử nghiệm với các ứng cử viên phát hành ngược dòng mới và đảm bảo rằng bản vá nằm trong ACK dựa trên LTS tiếp theo. Các trường hợp ngoại lệ bao gồm các trường hợp trong đó bản vá ngược dòng được nhập vào android12-5.4
(vì bản vá có thể đã có trong android-mainline
).
các bản vá ngược dòng
Như được chỉ định trong nguyên tắc đóng góp , các bản vá ngược dòng dành cho nhân ACK rơi vào các nhóm sau (được liệt kê theo thứ tự khả năng được chấp nhận).
-
UPSTREAM:
- Các bản vá được chọn từ 'android-mainline` có khả năng được chấp nhận vào ACK nếu có trường hợp sử dụng hợp lý. -
BACKPORT:
- Các bản vá lỗi từ thượng nguồn không được chọn lọc sạch sẽ và cần sửa đổi cũng có khả năng được chấp nhận nếu có trường hợp sử dụng hợp lý. -
FROMGIT:
- Các bản vá được lựa chọn cẩn thận từ chi nhánh bảo trì để chuẩn bị gửi lên dòng chính của Linux có thể được chấp nhận nếu có thời hạn sắp tới. Những điều này phải được chứng minh cả về nội dung và lịch trình. -
FROMLIST:
- Các bản vá đã được gửi tới LKML nhưng chưa được chấp nhận vào nhánh bảo trì dường như không được chấp nhận, trừ khi lý do đủ thuyết phục để bản vá đó được chấp nhận cho dù nó có nằm trong Linux ngược dòng hay không (chúng tôi giả sử rằng nó sẽ không). Phải có một vấn đề liên quan đến các bản váFROMLIST
để tạo điều kiện thảo luận với nhóm nhân Android.
Các bản vá dành riêng cho Android
Nếu bạn không thể hạ cánh các thay đổi bắt buộc ngược dòng, bạn có thể cố gắng gửi trực tiếp các bản vá ngoài cây tới ACK. Việc gửi các bản vá ngoài cây yêu cầu bạn phải tạo một vấn đề trong bộ phận CNTT trích dẫn bản vá và lý do tại sao bản vá không thể được gửi ngược dòng (xem danh sách trước để biết ví dụ). Tuy nhiên, có một số trường hợp không thể gửi mã ngược dòng. Những trường hợp này được đề cập như sau và phải tuân theo nguyên tắc đóng góp cho các bản vá dành riêng cho Android và được gắn thẻ ANDROID:
tiền tố trong chủ đề.
Thay đổi đối với gki_defconfig
Tất cả các thay đổi CONFIG
đối với gki_defconfig
phải được áp dụng cho cả phiên bản arm64 và x86 trừ khi CONFIG
dành riêng cho kiến trúc. Để yêu cầu thay đổi cài đặt CONFIG
, hãy tạo sự cố trong CNTT để thảo luận về thay đổi. Bất kỳ thay đổi CONFIG
nào ảnh hưởng đến Giao diện mô-đun hạt nhân (KMI) sau khi nó bị đóng băng đều bị từ chối. Trong trường hợp đối tác yêu cầu các cài đặt xung đột cho một cấu hình, chúng tôi sẽ giải quyết xung đột thông qua thảo luận về các lỗi liên quan.
Mã không tồn tại ngược dòng
Không thể gửi các sửa đổi đối với mã đã dành riêng cho Android. Ví dụ: mặc dù trình điều khiển liên kết được duy trì ngược dòng, các sửa đổi đối với các tính năng kế thừa ưu tiên của trình điều khiển liên kết không thể được gửi ngược dòng vì chúng dành riêng cho Android. Hãy rõ ràng về lỗi của bạn và vá lý do tại sao mã không thể được gửi ngược dòng. Nếu có thể, hãy chia các bản vá thành các phần có thể gửi ngược dòng và các phần dành riêng cho Android không thể gửi ngược dòng để giảm thiểu lượng mã ngoài cây được duy trì trong ACK.
Các thay đổi khác trong danh mục này là các bản cập nhật cho tệp đại diện KMI, danh sách ký hiệu KMI, gki_defconfig
, xây dựng tập lệnh hoặc cấu hình hoặc các tập lệnh khác không tồn tại ngược dòng.
Mô-đun ngoài cây
Linux ngược dòng chủ động không khuyến khích hỗ trợ xây dựng các mô-đun ngoài cây. Đây là một vị trí hợp lý vì các nhà bảo trì Linux không đảm bảo về nguồn trong nhân hoặc khả năng tương thích nhị phân và không muốn hỗ trợ mã không có trong cây. Tuy nhiên, GKI thực hiện đảm bảo ABI cho các mô-đun của nhà cung cấp, đảm bảo rằng các giao diện KMI ổn định trong thời gian tồn tại được hỗ trợ của nhân. Do đó, có một loại thay đổi để hỗ trợ các mô-đun của nhà cung cấp có thể chấp nhận được đối với ACK nhưng không được chấp nhận đối với thượng nguồn.
Ví dụ: hãy xem xét một bản vá bổ sung các macro EXPORT_SYMBOL_GPL()
trong đó các mô-đun sử dụng chức năng xuất không có trong cây nguồn. Mặc dù bạn phải cố gắng yêu cầu EXPORT_SYMBOL_GPL()
ngược dòng và cung cấp mô-đun sử dụng ký hiệu mới được xuất, nhưng nếu có lý do hợp lệ về lý do mô-đun không được gửi ngược dòng, bạn có thể gửi bản vá tới ACK để thay thế. Bạn cần bao gồm lý do tại sao không thể ngược dòng mô-đun trong vấn đề này. (Không yêu cầu biến thể không phải GPL, EXPORT_SYMBOL()
.)
cấu hình ẩn
Một số mô-đun trong cây tự động chọn cấu hình ẩn không thể chỉ định trong gki_defconfig
. Ví dụ: CONFIG_SND_SOC_TOPOLOGY
được chọn tự động khi CONFIG_SND_SOC_SOF=y
được định cấu hình. Để phù hợp với việc xây dựng mô-đun ngoài cây, GKI bao gồm một cơ chế để kích hoạt các cấu hình ẩn.
Để bật cấu hình ẩn, hãy thêm câu lệnh select
trong init/Kconfig.gki
để nó được chọn tự động dựa trên cấu hình hạt nhân CONFIG_GKI_HACKS_TO_FIX
, cấu hình này được bật trong gki_defconfig
. Chỉ sử dụng cơ chế này cho các cấu hình ẩn; nếu cấu hình không bị ẩn, nó phải được chỉ định trong gki_defconfig
một cách rõ ràng hoặc dưới dạng phụ thuộc.
thống đốc có thể tải
Đối với các khung nhân (chẳng hạn như cpufreq
) hỗ trợ các bộ điều tốc có thể nạp, bạn có thể ghi đè bộ điều tốc mặc định (chẳng hạn như bộ điều tốc schedutil
của cpufreq
. Đối với các khung (chẳng hạn như khung nhiệt) không hỗ trợ các bộ điều tốc hoặc trình điều khiển có thể nạp nhưng vẫn yêu cầu một triển khai dành riêng cho nhà cung cấp, tạo sự cố trong CNTT và tham khảo ý kiến của nhóm nhân Android .
Chúng tôi sẽ làm việc với bạn và những người bảo trì ngược dòng để thêm hỗ trợ cần thiết.
móc nhà cung cấp
Trong các bản phát hành trước đây, bạn có thể thêm các sửa đổi dành riêng cho nhà cung cấp trực tiếp vào nhân lõi. Điều này không thể thực hiện được với GKI 2.0 vì mã dành riêng cho sản phẩm phải được triển khai trong các mô-đun và sẽ không được chấp nhận trong các nhân lõi ngược dòng hoặc trong ACK. Để kích hoạt các tính năng giá trị gia tăng mà các đối tác dựa vào với tác động tối thiểu đến mã nhân lõi, GKI chấp nhận móc của nhà cung cấp cho phép gọi các mô-đun từ mã nhân lõi. Ngoài ra, các cấu trúc dữ liệu chính có thể được đệm bằng các trường dữ liệu của nhà cung cấp có sẵn để lưu trữ dữ liệu dành riêng cho nhà cung cấp nhằm triển khai các tính năng này.
Móc của nhà cung cấp có hai biến thể (bình thường và bị hạn chế) dựa trên các điểm theo dõi (không phải sự kiện theo dõi) mà các mô-đun của nhà cung cấp có thể đính kèm. Ví dụ: thay vì thêm một hàm sched_exit()
mới để thực hiện tính toán khi thoát tác vụ, nhà cung cấp có thể thêm một hook trong do_exit()
mà mô-đun của nhà cung cấp có thể gắn vào để xử lý. Một triển khai ví dụ bao gồm các hook của nhà cung cấp sau đây.
- Các hook của nhà cung cấp bình thường sử dụng
DECLARE_HOOK()
để tạo một hàm theo dõi có tên làtrace_ name
trong đóname
là mã định danh duy nhất cho dấu vết. Theo quy ước, tên hook của nhà cung cấp thông thường bắt đầu bằngandroid_vh
, vì vậy tên hooksched_exit()
sẽ làandroid_vh_sched_exit
. - Móc nhà cung cấp bị hạn chế là cần thiết cho các trường hợp như móc bộ lập lịch trong đó chức năng đính kèm phải được gọi ngay cả khi CPU ngoại tuyến hoặc yêu cầu ngữ cảnh phi nguyên tử. Không thể tháo rời móc của nhà cung cấp bị hạn chế, vì vậy các mô-đun gắn vào móc bị hạn chế không bao giờ có thể dỡ tải. Chỉ cho phép một tệp đính kèm, vì vậy mọi nỗ lực đính kèm khác đều không thành công với
-EBUSY
. Tên hook của nhà cung cấp bị hạn chế bắt đầu bằngandroid_rvh
.
Để thêm móc nối nhà cung cấp, hãy gửi sự cố trong bộ phận CNTT và gửi các bản vá (như với tất cả các bản vá dành riêng cho Android, sự cố phải tồn tại và bạn phải đưa ra lời giải thích). Hỗ trợ cho hook của nhà cung cấp chỉ có trong ACK, vì vậy đừng gửi các bản vá này tới Linux ngược dòng.
Thêm trường nhà cung cấp vào cấu trúc
Bạn có thể liên kết dữ liệu nhà cung cấp với cấu trúc dữ liệu chính bằng cách thêm trường android_vendor_data
bằng cách sử dụng macro ANDROID_VENDOR_DATA()
. Ví dụ: để hỗ trợ các tính năng giá trị gia tăng, hãy thêm các trường vào cấu trúc như được hiển thị trong mẫu mã sau.
Để tránh xung đột tiềm ẩn giữa các trường mà nhà cung cấp cần và các trường mà OEM cần, OEM không bao giờ được sử dụng các trường được khai báo bằng macro ANDROID_VENDOR_DATA()
. Thay vào đó, các OEM phải sử dụng ANDROID_OEM_DATA()
để khai báo các trường 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 */
}
Xác định móc nhà cung cấp
Thêm móc của nhà cung cấp vào mã nhân dưới dạng điểm theo dõi bằng cách khai báo chúng bằng cách sử dụng DECLARE_HOOK()
hoặc DECLARE_RESTRICTED_HOOK()
rồi thêm chúng vào mã dưới dạng điểm theo dõi. Ví dụ: để thêm trace_android_vh_sched_exit()
vào hàm nhân do_exit()
hiện có:
#include <trace/hooks/exit.h>
void do_exit(long code)
{
struct task_struct *tsk = current;
...
trace_android_vh_sched_exit(tsk);
...
}
Chức năng trace_android_vh_sched_exit()
ban đầu chỉ kiểm tra xem có thứ gì đó được đính kèm hay không. Tuy nhiên, nếu một mô-đun của nhà cung cấp đăng ký một trình xử lý bằng cách sử dụng register_trace_android_vh_sched_exit()
, thì hàm đã đăng ký sẽ được gọi. Trình xử lý phải nhận thức được ngữ cảnh liên quan đến khóa bị giữ, trạng thái RCS và các yếu tố khác. Móc phải được xác định trong tệp tiêu đề trong thư mục include/trace/hooks
.
Ví dụ: đoạn mã sau đưa ra một khai báo có thể có cho trace_android_vh_sched_exit()
trong tệp include/trace/hooks/exit.h
.
/* 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>
Để khởi tạo các giao diện cần thiết cho hook của nhà cung cấp, hãy thêm tệp tiêu đề có khai báo hook vào drivers/android/vendor_hooks.c
và xuất các ký hiệu. Ví dụ: đoạn mã sau hoàn thành khai báo hook 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);
LƯU Ý : Các cấu trúc dữ liệu được sử dụng trong khai báo hook cần phải được xác định đầy đủ để đảm bảo tính ổn định của ABI. Nếu không, sẽ không an toàn khi hủy đăng ký các con trỏ mờ hoặc sử dụng cấu trúc trong ngữ cảnh có kích thước. Phần bao gồm cung cấp định nghĩa đầy đủ về các cấu trúc dữ liệu như vậy phải nằm trong phần #ifndef __GENKSYMS__
của drivers/android/vendor_hooks.c
. Các tệp tiêu đề trong include/trace/hooks
không được bao gồm tệp tiêu đề hạt nhân với các định nghĩa loại để tránh các thay đổi CRC làm hỏng KMI. Thay vì chuyển tiếp khai báo các loại.
Gắn vào móc của nhà cung cấp
Để sử dụng hook của nhà cung cấp, mô-đun của nhà cung cấp cần đăng ký trình xử lý cho hook (thường được thực hiện trong quá trình khởi tạo mô-đun). Ví dụ: đoạn mã sau hiển thị trình xử lý mô-đun foo.ko
cho trace_android_vh_sched_exit()
.
#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);
...
}
Tính năng hạt nhân cốt lõi
Nếu không có kỹ thuật nào trước đây cho phép bạn triển khai một tính năng từ một mô-đun, thì bạn phải thêm tính năng này dưới dạng sửa đổi dành riêng cho Android vào nhân lõi. Tạo một vấn đề trong trình theo dõi vấn đề (CNTT) để bắt đầu cuộc trò chuyện.
Giao diện lập trình ứng dụng người dùng (UAPI)
- Các tệp tiêu đề UAPI. Các thay đổi đối với tệp tiêu đề UAPI phải xảy ra ngược dòng trừ khi các thay đổi là đối với giao diện dành riêng cho Android. Sử dụng các tệp tiêu đề dành riêng cho nhà cung cấp để xác định giao diện giữa các mô-đun của nhà cung cấp và mã không gian người dùng của nhà cung cấp.
- các nút sysfs. Không thêm các nút sysfs mới vào nhân GKI (những bổ sung như vậy chỉ hợp lệ trong các mô-đun của nhà cung cấp). Các nút sysfs được sử dụng bởi các thư viện SoC và thiết bị bất khả tri cũng như mã Java bao gồm khung Android chỉ có thể được thay đổi theo các cách tương thích và phải được thay đổi ngược dòng nếu chúng không phải là các nút sysfs dành riêng cho Android. Bạn có thể tạo các nút sysfs dành riêng cho nhà cung cấp để không gian người dùng của nhà cung cấp sử dụng. Theo mặc định, quyền truy cập vào các nút sysfs của không gian người dùng bị từ chối khi sử dụng SELinux. Tùy thuộc vào nhà cung cấp để thêm các nhãn SELinux thích hợp để cho phép phần mềm của nhà cung cấp được ủy quyền truy cập.
- Các nút DebugFS. Các mô-đun của nhà cung cấp có thể xác định các nút trong trình
debugfs
chỉ để gỡ lỗi (vìdebugfs
không được gắn trong quá trình hoạt động bình thường của thiết bị).