Bạn có thể sử dụng công cụ giám sát giao diện nhị phân của ứng dụng (ABI), có trong Android 11 trở lên, để ổn định ABI trong nhân của nhân Android. Công cụ này thu thập và so sánh các bản trình bày ABI từ các tệp nhị phân hạt nhân hiện có (mô-đun vmlinux
+ GKI). Các nội dung đại diện ABI này là tệp .stg
và danh sách biểu tượng. Giao diện mà nội dung trình bày cung cấp một chế độ xem được gọi là Giao diện mô-đun hạt nhân (KMI). Bạn có thể sử dụng công cụ này để theo dõi và giảm thiểu các thay đổi đối với KMI.
Công cụ giám sát ABI được phát triển trong AOSP và sử dụng STG (hoặc libabigail
trong Android 13 trở xuống) để tạo và so sánh các bản trình bày.
Trang này mô tả công cụ, quy trình thu thập và phân tích các bản trình bày ABI cũng như cách sử dụng các bản trình bày đó để mang lại sự ổn định cho ABI trong hạt nhân. Trang này cũng cung cấp thông tin để đóng góp các thay đổi cho nhân Android.
Quy trình
Việc phân tích ABI của hạt nhân cần thực hiện nhiều bước, hầu hết các bước đều có thể được tự động hoá:
- Tạo nhân và phần trình bày ABI của nhân.
- Phân tích sự khác biệt về ABI giữa bản dựng và tệp đối chiếu.
- Cập nhật nội dung trình bày ABI (nếu cần).
- Xử lý danh sách ký hiệu.
Hướng dẫn sau đây áp dụng cho mọi hạt nhân mà bạn có thể tạo bằng cách sử dụng chuỗi công cụ được hỗ trợ (chẳng hạn như chuỗi công cụ Clang tạo sẵn). repo manifests
có sẵn cho tất cả các nhánh nhân phổ biến của Android và cho một số nhân dành riêng cho thiết bị, các nhân này đảm bảo rằng bạn sử dụng đúng chuỗi công cụ khi tạo bản phân phối nhân để phân tích.
Danh sách biểu tượng
KMI không bao gồm tất cả các ký hiệu trong hạt nhân hoặc thậm chí là tất cả 30.000 ký hiệu được xuất. Thay vào đó, các ký hiệu mà mô-đun của nhà cung cấp có thể sử dụng được liệt kê rõ ràng trong một tập hợp các tệp danh sách ký hiệu được duy trì công khai trong cây nhân kernel (gki/{ARCH}/symbols/*
hoặc android/abi_gki_{ARCH}_*
trong Android 15 trở xuống). Tập hợp hợp nhất của tất cả các ký hiệu trong tất cả các tệp danh sách ký hiệu xác định tập hợp các ký hiệu KMI được duy trì ổn định. Tệp danh sách biểu tượng mẫu là gki/aarch64/symbols/db845c
, khai báo các biểu tượng cần thiết cho DragonBoard 845c.
Chỉ những ký hiệu được liệt kê trong danh sách ký hiệu và các cấu trúc và định nghĩa liên quan của chúng mới được coi là một phần của KMI. Bạn có thể đăng các thay đổi lên danh sách ký hiệu nếu không có ký hiệu bạn cần. Sau khi giao diện mới nằm trong danh sách ký hiệu và là một phần của nội dung mô tả KMI, các giao diện này sẽ được duy trì ở trạng thái ổn định và không được xoá khỏi danh sách ký hiệu hoặc sửa đổi sau khi nhánh bị đóng băng.
Mỗi nhánh hạt nhân KMI của Hạt nhân chung Android (ACK) đều có một nhóm danh sách biểu tượng riêng. Không có nỗ lực nào nhằm đảm bảo tính ổn định của ABI giữa các nhánh hạt nhân KMI khác nhau. Ví dụ: KMI cho android12-5.10
hoàn toàn độc lập với KMI cho android13-5.10
.
Các công cụ ABI sử dụng danh sách ký hiệu KMI để giới hạn những giao diện cần được theo dõi để đảm bảo tính ổn định. Nhà cung cấp dự kiến sẽ gửi và cập nhật danh sách biểu tượng của riêng họ để đảm bảo rằng các giao diện mà họ dựa vào duy trì khả năng tương thích với ABI. Ví dụ: để xem danh sách danh sách biểu tượng cho hạt nhân android16-6.12
, hãy tham khảo https://android.googlesource.com/kernel/common/+/refs/heads/android16-6.12/gki/aarch64/symbols
Danh sách ký hiệu chứa các ký hiệu được báo cáo là cần thiết cho một nhà cung cấp hoặc thiết bị cụ thể. Danh sách đầy đủ mà các công cụ sử dụng là tập hợp của tất cả các tệp danh sách ký hiệu KMI. Các công cụ ABI xác định thông tin chi tiết của từng biểu tượng, bao gồm cả chữ ký hàm và cấu trúc dữ liệu lồng nhau.
Khi KMI bị đóng băng, bạn không được phép thay đổi giao diện KMI hiện có; giao diện này sẽ ổn định. Tuy nhiên, nhà cung cấp có thể tự do thêm các ký hiệu vào KMI bất cứ lúc nào miễn là các nội dung bổ sung không ảnh hưởng đến độ ổn định của ABI hiện có. Các ký hiệu mới thêm sẽ được duy trì ở trạng thái ổn định ngay khi được trích dẫn theo danh sách ký hiệu KMI. Bạn không nên xoá các ký hiệu khỏi danh sách cho một hạt nhân trừ phi có thể xác nhận rằng không có thiết bị nào từng được vận chuyển với phần phụ thuộc trên ký hiệu đó.
Bạn có thể tạo danh sách ký hiệu KMI cho một thiết bị bằng cách làm theo hướng dẫn trong phần Cách xử lý danh sách ký hiệu. Nhiều đối tác gửi một danh sách ký hiệu cho mỗi ACK, nhưng đây không phải là yêu cầu bắt buộc. Nếu việc này giúp ích cho việc bảo trì, bạn có thể gửi nhiều danh sách biểu tượng.
Mở rộng KMI
Mặc dù các ký hiệu KMI và các cấu trúc liên quan được duy trì ở trạng thái ổn định (nghĩa là không thể chấp nhận các thay đổi làm hỏng giao diện ổn định trong một hạt nhân có KMI bị đóng băng), nhưng hạt nhân GKI vẫn mở cho các tiện ích để các thiết bị xuất xưởng vào cuối năm không cần xác định tất cả các phần phụ thuộc trước khi KMI bị đóng băng. Để mở rộng KMI, bạn có thể thêm các ký hiệu mới vào KMI cho các hàm nhân mới hoặc hiện có được xuất, ngay cả khi KMI bị đóng băng. Các bản vá hạt nhân mới cũng có thể được chấp nhận nếu không làm hỏng KMI.
Giới thiệu về lỗi KMI
Hạt nhân có nguồn và các tệp nhị phân được tạo từ các nguồn đó.
Các nhánh hạt nhân được giám sát ABI bao gồm một ABI đại diện cho ABI GKI hiện tại (ở dạng tệp .stg
). Sau khi tạo các tệp nhị phân (vmlinux
, Image
và mọi mô-đun GKI), bạn có thể trích xuất một bản trình bày ABI từ các tệp nhị phân. Mọi thay đổi đối với tệp nguồn hạt nhân đều có thể ảnh hưởng đến tệp nhị phân và từ đó cũng ảnh hưởng đến .stg
đã trích xuất. Trình phân tích AbiAnalyzer
so sánh tệp .stg
đã cam kết với tệp được trích xuất từ cấu phần phần mềm bản dựng và đặt nhãn Lint-1 trên thay đổi trong Gerrit nếu tìm thấy sự khác biệt về ngữ nghĩa.
Xử lý lỗi ABI
Ví dụ: bản vá sau đây gây ra lỗi ABI rất rõ ràng:
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 42786e6364ef..e15f1d0f137b 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -657,6 +657,7 @@ struct mm_struct {
ANDROID_KABI_RESERVE(1);
} __randomize_layout;
+ int tickle_count;
/*
* The mm_cpumask needs to be at the end of mm_struct, because it
* is dynamically sized based on nr_cpu_ids.
Khi bạn chạy ABI bản dựng bằng bản vá này, công cụ sẽ thoát bằng một mã lỗi khác 0 và báo cáo sự khác biệt về ABI tương tự như sau:
function symbol 'struct block_device* I_BDEV(struct inode*)' changed
CRC changed from 0x8d400dbd to 0xabfc92ad
function symbol 'void* PDE_DATA(const struct inode*)' changed
CRC changed from 0xc3c38b5c to 0x7ad96c0d
function symbol 'void __ClearPageMovable(struct page*)' changed
CRC changed from 0xf489e5e8 to 0x92bd005e
... 4492 omitted; 4495 symbols have only CRC changes
type 'struct mm_struct' changed
byte size changed from 992 to 1000
member 'int tickle_count' was added
member 'unsigned long cpu_bitmap[0]' changed
offset changed by 64
Phát hiện sự khác biệt về ABI tại thời điểm tạo bản dựng
Lý do phổ biến nhất gây ra lỗi là khi trình điều khiển sử dụng một ký hiệu mới từ hạt nhân không có trong danh sách ký hiệu nào.
Nếu biểu tượng không có trong danh sách biểu tượng, trước tiên, bạn cần xác minh rằng biểu tượng đó được xuất bằng EXPORT_SYMBOL_GPL(symbol_name)
, sau đó cập nhật danh sách biểu tượng và nội dung trình bày ABI. Ví dụ: các thay đổi sau đây sẽ thêm tính năng FS gia tăng mới vào nhánh android-12-5.10
, bao gồm cả việc cập nhật danh sách biểu tượng và bản trình bày ABI.
- Ví dụ về thay đổi tính năng có trong aosp/1345659.
- Ví dụ về danh sách biểu tượng có trong aosp/1346742.
- Ví dụ về thay đổi cách trình bày ABI có trong aosp/1349377.
Nếu biểu tượng được xuất (bởi bạn hoặc đã được xuất trước đó) nhưng không có trình điều khiển nào khác đang sử dụng biểu tượng đó, thì bạn có thể gặp lỗi bản dựng tương tự như sau.
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
Để giải quyết, hãy cập nhật danh sách ký hiệu KMI trong cả hạt nhân và ACK (xem phần Cập nhật nội dung trình bày ABI). Để biết ví dụ về cách cập nhật danh sách biểu tượng và cách biểu thị ABI trong ACK, hãy tham khảo aosp/1367601.
Giải quyết lỗi ABI của hạt nhân
Bạn có thể xử lý các lỗi ABI của hạt nhân bằng cách tái cấu trúc mã để không thay đổi ABI hoặc cập nhật cách trình bày ABI. Hãy sử dụng biểu đồ sau đây để xác định phương pháp phù hợp nhất với trường hợp của bạn.
Hình 1. Giải pháp khắc phục lỗi ABI
Tái cấu trúc mã để tránh thay đổi ABI
Hãy cố gắng hết sức để tránh sửa đổi ABI hiện có. Trong nhiều trường hợp, bạn có thể tái cấu trúc mã để xoá các thay đổi ảnh hưởng đến ABI.
Tái cấu trúc các thay đổi về trường cấu trúc. Nếu một thay đổi sửa đổi ABI cho một tính năng gỡ lỗi, hãy thêm
#ifdef
xung quanh các trường (trong cấu trúc và tệp tham chiếu nguồn) và đảm bảoCONFIG
dùng cho#ifdef
bị tắt cho defconfig sản xuất vàgki_defconfig
. Để biết ví dụ về cách thêm cấu hình gỡ lỗi vào một cấu trúc mà không làm hỏng ABI, hãy tham khảo nhóm bản vá này.Tái cấu trúc các tính năng để không thay đổi hạt nhân cốt lõi. Nếu cần thêm các tính năng mới vào ACK để hỗ trợ các mô-đun đối tác, hãy cố gắng tái cấu trúc phần ABI của thay đổi để tránh sửa đổi ABI hạt nhân. Để biết ví dụ về cách sử dụng ABI hạt nhân hiện có để thêm các chức năng bổ sung mà không thay đổi ABI hạt nhân, hãy tham khảo aosp/1312213.
Khắc phục ABI bị hỏng trên Android Gerrit
Nếu không cố ý phá vỡ ABI hạt nhân, bạn cần điều tra bằng cách sử dụng hướng dẫn do công cụ giám sát ABI cung cấp. Nguyên nhân phổ biến nhất dẫn đến lỗi là do thay đổi cấu trúc dữ liệu và các thay đổi CRC biểu tượng liên quan, hoặc do thay đổi tuỳ chọn cấu hình dẫn đến bất kỳ nguyên nhân nào nêu trên. Hãy bắt đầu bằng cách giải quyết các vấn đề mà công cụ này phát hiện được.
Bạn có thể tái tạo các phát hiện về ABI trên máy, hãy xem phần Tạo hạt nhân và nội dung đại diện ABI của hạt nhân.
Giới thiệu về nhãn Lint-1
Nếu bạn tải các thay đổi lên một nhánh chứa KMI đã đóng băng hoặc đã hoàn tất, thì các thay đổi đó phải vượt qua AbiAnalyzer
để đảm bảo các thay đổi không ảnh hưởng đến ABI ổn định theo cách không tương thích. Trong quá trình này, AbiAnalyzer
sẽ tìm báo cáo ABI được tạo trong quá trình xây dựng (một bản dựng mở rộng thực hiện bản dựng thông thường, sau đó là một số bước trích xuất và so sánh ABI.
Nếu AbiAnalyzer
tìm thấy một báo cáo không trống, thì báo cáo này sẽ đặt nhãn Lint-1 và thay đổi sẽ bị chặn gửi cho đến khi được giải quyết; cho đến khi nhóm bản vá nhận được nhãn Lint+1.
Cập nhật ABI hạt nhân
Nếu không thể tránh việc sửa đổi ABI, thì bạn phải áp dụng các thay đổi về mã, nội dung trình bày ABI và danh sách biểu tượng cho ACK. Để yêu cầu Tìm lỗi mã nguồn xoá -1 mà không làm hỏng khả năng tương thích với GKI, hãy làm theo các bước sau:
Chờ nhận được điểm Code-Review +2 cho nhóm bản vá.
Hợp nhất các thay đổi về mã và thay đổi về nội dung cập nhật ABI.
Tải các thay đổi về mã ABI lên ACK
Việc cập nhật ABI ACK phụ thuộc vào loại thay đổi đang được thực hiện.
Nếu thay đổi ABI liên quan đến một tính năng ảnh hưởng đến kiểm thử CTS hoặc VTS, thì thay đổi đó thường có thể được chọn để ACK như hiện có. Ví dụ:
- Cần có aosp/1289677 để âm thanh hoạt động.
- Cần có aosp/1295945 để USB hoạt động.
Nếu thay đổi ABI là cho một tính năng có thể chia sẻ với ACK, thì thay đổi đó có thể được chọn để ACK như hiện tại. Ví dụ: các thay đổi sau đây không cần thiết cho kiểm thử CTS hoặc VTS nhưng có thể được chia sẻ với ACK:
- aosp/1250412 là thay đổi về tính năng nhiệt.
- aosp/1288857 là một thay đổi
EXPORT_SYMBOL_GPL
.
Nếu một thay đổi ABI giới thiệu một tính năng mới không cần đưa vào ACK, bạn có thể giới thiệu các ký hiệu vào ACK bằng cách sử dụng một mã giả như mô tả trong phần sau.
Sử dụng mã giả lập cho ACK
Bạn chỉ cần sử dụng các mô-đun giả lập cho những thay đổi cốt lõi về hạt nhân không mang lại lợi ích cho ACK, chẳng hạn như thay đổi về hiệu suất và nguồn điện. Danh sách sau đây trình bày chi tiết các ví dụ về mã giả và một số lựa chọn trong ACK cho GKI.
Trình giữ chỗ tính năng Core-isolate (aosp/1284493). Các chức năng trong ACK không cần thiết, nhưng các biểu tượng cần có trong ACK để các mô-đun của bạn có thể sử dụng các biểu tượng này.
Ký hiệu phần giữ chỗ cho mô-đun nhà cung cấp (aosp/1288860).
Chỉ ABI mới có thể chọn tính năng theo dõi sự kiện
mm
theo quy trình (aosp/1288454). Bản vá ban đầu được chọn để ACK và sau đó được cắt bớt để chỉ bao gồm những thay đổi cần thiết để giải quyết sự khác biệt về ABI chotask_struct
vàmm_event_count
. Bản vá này cũng cập nhật enummm_event_type
để chứa các thành phần cuối cùng.Một số thay đổi ABI cấu trúc nhiệt cần nhiều hơn việc chỉ thêm các trường ABI mới.
Bản vá aosp/1255544 đã giải quyết các khác biệt về ABI giữa nhân đối tác và ACK.
Bản vá aosp/1291018 khắc phục các vấn đề về chức năng phát hiện được trong quá trình kiểm thử GKI của bản vá trước. Bản sửa lỗi bao gồm việc khởi chạy cấu trúc tham số cảm biến để đăng ký nhiều vùng nhiệt cho một cảm biến.
Thay đổi ABI
CONFIG_NL80211_TESTMODE
(aosp/1344321). Bản vá này đã thêm các thay đổi cấu trúc cần thiết cho ABI và đảm bảo rằng các trường bổ sung không gây ra sự khác biệt về chức năng, cho phép các đối tác đưaCONFIG_NL80211_TESTMODE
vào hạt nhân sản xuất của họ và vẫn duy trì khả năng tuân thủ GKI.
Thực thi KMI trong thời gian chạy
Hạt nhân GKI sử dụng các tuỳ chọn cấu hình TRIM_UNUSED_KSYMS=y
và UNUSED_KSYMS_WHITELIST=<union
of all symbol lists>
, giúp giới hạn các biểu tượng đã xuất (chẳng hạn như các biểu tượng đã xuất bằng EXPORT_SYMBOL_GPL()
) ở những biểu tượng được liệt kê trong danh sách biểu tượng. Tất cả các biểu tượng khác đều không được xuất và việc tải một mô-đun yêu cầu biểu tượng không được xuất sẽ bị từ chối. Quy định hạn chế này được thực thi tại thời điểm tạo bản dựng và các mục bị thiếu sẽ được gắn cờ.
Đối với mục đích phát triển, bạn có thể sử dụng bản dựng hạt nhân GKI không bao gồm tính năng cắt bớt ký hiệu (nghĩa là tất cả các ký hiệu thường được xuất đều có thể được sử dụng). Để tìm các bản dựng này, hãy tìm bản dựng kernel_debug_aarch64
trên ci.android.com.
Thực thi KMI bằng cách sử dụng tính năng tạo phiên bản mô-đun
Hạt nhân Hình ảnh hạt nhân chung (GKI) sử dụng phiên bản mô-đun (CONFIG_MODVERSIONS
) làm biện pháp bổ sung để thực thi việc tuân thủ KMI trong thời gian chạy. Việc tạo phiên bản mô-đun có thể gây ra lỗi không khớp kiểm tra dư thừa tuần hoàn (CRC) tại thời điểm tải mô-đun nếu KMI dự kiến của mô-đun không khớp với KMI vmlinux
. Ví dụ: sau đây là lỗi điển hình xảy ra tại thời điểm tải mô-đun do CRC không khớp với biểu tượng module_layout()
:
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 ''
Các cách sử dụng tính năng tạo phiên bản mô-đun
Việc tạo phiên bản mô-đun hữu ích vì những lý do sau:
Việc tạo phiên bản mô-đun sẽ phát hiện các thay đổi về chế độ hiển thị cấu trúc dữ liệu. Nếu các mô-đun thay đổi cấu trúc dữ liệu mờ, tức là các cấu trúc dữ liệu không thuộc KMI, thì các mô-đun đó sẽ bị lỗi sau khi cấu trúc thay đổi trong tương lai.
Ví dụ: hãy xem xét trường
fwnode
trongstruct device
. Trường này PHẢI mờ đối với các mô-đun để chúng không thể thay đổi các trường củadevice->fw_node
hoặc đưa ra giả định về kích thước của trường này.Tuy nhiên, nếu một mô-đun bao gồm
<linux/fwnode.h>
(trực tiếp hoặc gián tiếp), thì trườngfwnode
trongstruct device
sẽ không còn mờ đối với mô-đun đó. Sau đó, mô-đun có thể thực hiện các thay đổi đối vớidevice->fwnode->dev
hoặcdevice->fwnode->ops
. Tình huống này có vấn đề vì một số lý do, như sau:Điều này có thể phá vỡ các giả định mà mã nhân cốt lõi đang đưa ra về cấu trúc dữ liệu nội bộ.
Nếu bản cập nhật nhân trong tương lai thay đổi
struct fwnode_handle
(loại dữ liệu củafwnode
), thì mô-đun sẽ không còn hoạt động với nhân mới. Hơn nữa,stgdiff
sẽ không hiển thị bất kỳ sự khác biệt nào vì mô-đun này đang phá vỡ KMI bằng cách trực tiếp thao tác với các cấu trúc dữ liệu nội bộ theo những cách không thể ghi lại được bằng cách chỉ kiểm tra bản trình bày nhị phân.
Mô-đun hiện tại được coi là không tương thích với KMI khi được tải vào một ngày sau đó bằng một nhân mới không tương thích. Việc tạo phiên bản mô-đun sẽ thêm một bước kiểm tra thời gian chạy để tránh vô tình tải một mô-đun không tương thích với KMI với hạt nhân. Bước kiểm tra này giúp ngăn chặn các sự cố thời gian chạy và sự cố hạt nhân khó gỡ lỗi có thể xảy ra do sự không tương thích chưa được phát hiện trong KMI.
Việc bật tính năng tạo phiên bản mô-đun sẽ ngăn chặn tất cả các vấn đề này.
Kiểm tra để tìm những trường hợp không khớp CRC mà không cần khởi động thiết bị
stgdiff
so sánh và báo cáo các trường hợp không khớp CRC giữa các hạt nhân cùng với các điểm khác biệt khác về ABI.
Ngoài ra, bản dựng hạt nhân đầy đủ với CONFIG_MODVERSIONS
được bật sẽ tạo một tệp Module.symvers
trong quy trình xây dựng thông thường. Tệp này có một dòng cho mỗi ký hiệu do hạt nhân (vmlinux
) và các mô-đun xuất. Mỗi dòng bao gồm giá trị CRC, tên biểu tượng, không gian tên biểu tượng, vmlinux
hoặc tên mô-đun đang xuất biểu tượng và loại xuất (ví dụ: EXPORT_SYMBOL
so với EXPORT_SYMBOL_GPL
).
Bạn có thể so sánh các tệp Module.symvers
giữa bản dựng GKI và bản dựng của mình để kiểm tra xem có sự khác biệt nào về CRC trong các biểu tượng do vmlinux
xuất ra hay không. Nếu có sự khác biệt về giá trị CRC trong bất kỳ biểu tượng nào do vmlinux
xuất và biểu tượng đó được một trong các mô-đun bạn tải trong thiết bị sử dụng, thì mô-đun đó sẽ không tải.
Nếu không có tất cả cấu phần phần mềm xây dựng, nhưng có các tệp vmlinux
của hạt nhân GKI và hạt nhân của bạn, bạn có thể so sánh các giá trị CRC cho một ký hiệu cụ thể bằng cách chạy lệnh sau trên cả hai hạt nhân và so sánh đầu ra:
nm <path to vmlinux>/vmlinux | grep __crc_<symbol name>
Ví dụ: lệnh sau đây sẽ kiểm tra giá trị CRC cho ký hiệu module_layout
:
nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout
Giải quyết trường hợp không khớp CRC
Hãy làm theo các bước sau để giải quyết lỗi không khớp CRC khi tải mô-đun:
Tạo hạt nhân GKI và hạt nhân thiết bị bằng tuỳ chọn
--kbuild_symtypes
như trong lệnh sau:tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
Lệnh này tạo một tệp
.symtypes
cho mỗi tệp.o
. Hãy xemKBUILD_SYMTYPES
trong Kleaf để biết thông tin chi tiết.Đối với Android 13 trở xuống, hãy tạo hạt nhân GKI và hạt nhân thiết bị bằng cách thêm
KBUILD_SYMTYPES=1
vào đầu lệnh bạn sử dụng để tạo hạt nhân, như trong lệnh sau:KBUILD_SYMTYPES=1 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
Khi sử dụng
build_abi.sh,
, cờKBUILD_SYMTYPES=1
đã được đặt ngầm.Tìm tệp
.c
chứa biểu tượng có CRC không khớp được xuất bằng lệnh sau:cd common && git grep EXPORT_SYMBOL.*module_layout kernel/module.c:EXPORT_SYMBOL(module_layout);
Tệp
.c
có một tệp.symtypes
tương ứng trong GKI và các cấu phần phần mềm bản dựng nhân thiết bị. Tìm tệp.c
bằng các lệnh sau:cd out/$BRANCH/common && ls -1 kernel/module.* kernel/module.o kernel/module.o.symversions kernel/module.symtypes
Sau đây là các đặc điểm của tệp
.c
:Định dạng của tệp
.c
là một dòng (có thể rất dài) cho mỗi ký hiệu.[s|u|e|etc]#
ở đầu dòng có nghĩa là biểu tượng thuộc loại dữ liệu[struct|union|enum|etc]
. Ví dụ:t#bool typedef _Bool bool
Việc thiếu tiền tố
#
ở đầu dòng cho biết ký hiệu đó là một hàm. Ví dụ:find_module s#module * find_module ( const char * )
So sánh hai tệp và khắc phục mọi điểm khác biệt.
Trường hợp 1: Sự khác biệt do chế độ hiển thị loại dữ liệu
Nếu một hạt nhân giữ một biểu tượng hoặc loại dữ liệu không rõ ràng cho các mô-đun và hạt nhân khác không giữ, thì sự khác biệt đó sẽ xuất hiện giữa các tệp .symtypes
của hai hạt nhân. Tệp .symtypes
từ một trong các hạt nhân có UNKNOWN
cho một biểu tượng và tệp .symtypes
từ hạt nhân còn lại có chế độ xem mở rộng của biểu tượng hoặc loại dữ liệu.
Ví dụ: việc thêm dòng sau vào tệp include/linux/device.h
trong hạt nhân sẽ gây ra sự không khớp CRC, một trong số đó là module_layout()
:
#include <linux/fwnode.h>
Khi so sánh module.symtypes
cho biểu tượng đó, bạn sẽ thấy các điểm khác biệt sau:
$ 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 ] ; }
...
Nếu hạt nhân của bạn có giá trị là UNKNOWN
và hạt nhân GKI có chế độ xem mở rộng của biểu tượng (rất khó xảy ra), hãy hợp nhất Hạt nhân Android phổ biến mới nhất vào hạt nhân của bạn để bạn đang sử dụng cơ sở hạt nhân GKI mới nhất.
Trong hầu hết các trường hợp, hạt nhân GKI có giá trị là UNKNOWN
, nhưng hạt nhân của bạn có thông tin chi tiết nội bộ về biểu tượng do các thay đổi đã thực hiện đối với hạt nhân. Lý do là một trong các tệp trong hạt nhân của bạn đã thêm một #include
không có trong hạt nhân GKI.
Thông thường, cách khắc phục chỉ là ẩn #include
mới khỏi genksyms
.
#ifndef __GENKSYMS__
#include <linux/fwnode.h>
#endif
Nếu không, để xác định #include
gây ra sự khác biệt, hãy làm theo các bước sau:
Mở tệp tiêu đề xác định biểu tượng hoặc kiểu dữ liệu có sự khác biệt này. Ví dụ: chỉnh sửa
include/linux/fwnode.h
chostruct fwnode_handle
.Thêm mã sau vào đầu tệp tiêu đề:
#ifdef CRC_CATCH #error "Included from here" #endif
Trong tệp
.c
của mô-đun có CRC không khớp, hãy thêm nội dung sau làm dòng đầu tiên trước bất kỳ dòng#include
nào.#define CRC_CATCH 1
Biên dịch mô-đun. Lỗi thời gian tạo kết quả cho thấy chuỗi tệp tiêu đề
#include
dẫn đến sự không khớp CRC này. Ví dụ: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"
Một trong các đường liên kết trong chuỗi
#include
này là do một thay đổi đã được thực hiện trong hạt nhân của bạn, nhưng lại bị thiếu trong hạt nhân GKI.Xác định thay đổi, huỷ bỏ thay đổi đó trong hạt nhân hoặc tải lên ACK và hợp nhất thay đổi đó.
Trường hợp 2: Sự khác biệt do thay đổi về loại dữ liệu
Nếu CRC không khớp cho một ký hiệu hoặc kiểu dữ liệu không phải do sự khác biệt về chế độ hiển thị, thì đó là do các thay đổi thực tế (thêm, xoá hoặc thay đổi) trong chính kiểu dữ liệu đó.
Ví dụ: việc thực hiện thay đổi sau đây trong hạt nhân sẽ gây ra một số lỗi không khớp CRC vì nhiều ký hiệu bị ảnh hưởng gián tiếp bởi loại thay đổi này:
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);
Một CRC không khớp là đối với devm_of_platform_populate()
.
Nếu so sánh các tệp .symtypes
cho biểu tượng đó, bạn có thể thấy như sau:
$ 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 * ) ; ...
Để xác định loại đã thay đổi, hãy làm theo các bước sau:
Tìm định nghĩa của biểu tượng trong mã nguồn (thường là trong tệp
.h
).- Đối với sự khác biệt về biểu tượng giữa hạt nhân của bạn và hạt nhân GKI, hãy tìm thay đổi bằng cách chạy lệnh sau:
git blame
- Đối với các ký hiệu đã xoá (trong đó một ký hiệu bị xoá trong một cây và bạn cũng muốn xoá ký hiệu đó trong cây khác), bạn cần tìm thay đổi đã xoá dòng đó. Sử dụng lệnh sau trên cây đã xoá dòng:
git log -S "copy paste of deleted line/word" -- <file where it was deleted>
Xem lại danh sách các thay đổi đã gửi để tìm thay đổi hoặc nội dung đã xoá. Lần thay đổi đầu tiên có thể là lần thay đổi bạn đang tìm kiếm. Nếu không, hãy xem danh sách cho đến khi bạn tìm thấy thay đổi đó.
Sau khi xác định thay đổi, hãy huỷ thay đổi đó trong hạt nhân hoặc tải thay đổi đó lên ACK và hợp nhất thay đổi đó.