Giám sát ABI của nhân hệ điều hành Android

Bạn có thể dùng công cụ theo dõi giao diện nhị phân của ứng dụng (ABI) có trong Android 11 trở lên, giúp ổn định nhân hệ điều hành ABI của nhân Android. Công cụ này thu thập và so sánh các biểu diễn ABI từ các tệp nhị phân nhân hiện có (vmlinux+ mô-đun GKI). Các ABI này là các tệp .stg và danh sách biểu tượng. Giao diện bật mà bản trình bày cung cấp một khung hiển thị được gọi là Giao diện mô-đun Kernel (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 hiện được phát triển trong AOSP (Dự án nguồn mở Android) và sử dụng STG (hoặc libabigail inch Android 13 trở xuống) để tạo và so sánh đại diện.

Trang này mô tả công cụ, quy trình thu thập và phân tích ABI và việc sử dụng các bản trình bày đó để đảm bảo tính ổn định cho ABI trong nhân. Trang này cũng cung cấp thông tin về những thay đổi góp phần cho nhân Android.

Quy trình

Quá trình phân tích ABI của nhân hệ điều hành bao gồm nhiều bước, hầu hết các bước đều được tự động hoá:

  1. Xây dựng hạt nhân và bản trình bày ABI của hạt nhân đó.
  2. Phân tích sự khác biệt về ABI giữa bản dựng và tệp tham chiếu.
  3. Cập nhật bản trình bày ABI (nếu cần).
  4. Thao tác với danh sách biểu tượng.

Các hướng dẫn sau đây áp dụng cho bất kỳ hạt nhân mà bạn có thể xây dựng bằng cách sử dụng được hỗ trợ (chẳng hạn như chuỗi công cụ Clang được tạo sẵn). repo manifests có sẵn cho tất cả các nhánh nhân hệ điều hành phổ biến của Android và cho một số nhân dành riêng cho thiết bị, giúp đảm bảo bạn sử dụng đúng chuỗi công cụ khi bạn xây dựng 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 nhân hoặc thậm chí là tất cả hơn 30.000 ký hiệu ký hiệu đã xuất. Thay vào đó, các ký hiệu mà mô-đun nhà cung cấp có thể sử dụng là được liệt kê rõ ràng trong một tập hợp các tệp danh sách biểu tượng được duy trì công khai trong thư mục gốc của cây nhân. Tập hợp tất cả các biểu tượng trong tất cả tệp danh sách biểu tượng xác định tập hợp các ký hiệu KMI được duy trì là ổn định. Tệp danh sách biểu tượng mẫu là abi_gki_aarch64_db845c, Mã này khai báo các ký hiệu bắt buộc cho DragonBoard 845c.

Chỉ những ký hiệu được liệt kê trong danh sách biểu tượng cũng như cấu trúc và được coi là một phần của KMI. Bạn có thể đăng thay đổi lên nếu không có các ký hiệu bạn cần. Sau khi có giao diện mới danh sách biểu tượng và là một phần của mô tả KMI, chúng được duy trì ở mức ổn định và không được xoá khỏi danh sách biểu tượng hoặc sửa đổi sau khi nhánh được bị treo.

Mỗi nhánh hạt nhân KMI của Hạt nhân phổ biến (ACK) của Android có một bộ biểu tượng riêng danh sách. Không có nỗ lực nào để cung cấp tính ổn định cho ABI giữa các nhân KMI khác nhau cành cây. 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 biểu tượng KMI để giới hạn những giao diện phải được giám sát độ ổn định. Chiến lược phát hành đĩa đơn danh sách biểu tượng chính chứa các ký hiệu mà mô-đun nhân GKI yêu cầu. Nhà cung cấp gửi và cập nhật danh sách biểu tượng bổ sung để đảm bảo rằng mà chúng dựa vào để duy trì khả năng tương thích với ABI. Ví dụ: để xem danh sách của danh sách biểu tượng cho android13-5.15, tham khảo https://android.googlesource.com/kernel/common/+/refs/heads/android13-5.15/android

Một danh sách biểu tượng chứa các ký hiệu được báo cáo là cần thiết cho thuộc tính cụ thể nhà cung cấp hoặc thiết bị. Danh sách đầy đủ mà các công cụ sử dụng là tổng hợp tất cả Tệp danh sách biểu tượng 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 chữ ký hàm và cấu trúc dữ liệu lồng nhau.

Khi KMI bị treo, các giao diện KMI hiện có sẽ không được thay đổi; đều ổn định. Tuy nhiên, nhà cung cấp có thể tuỳ ý thêm các biểu tượng vào KMI bất cứ lúc nào miễn là việc bổ sung không ảnh hưởng đến độ ổn định của ABI hiện có. Mới thêm các biểu tượng được duy trì ổn định ngay sau khi chúng được trích dẫn bởi một danh sách biểu tượng KMI. Không nên xoá biểu tượng khỏi danh sách của một hạt nhân trừ phi hạt nhân đó được xác nhận chưa từng xuất bản thiết bị nào phụ thuộc vào biểu tượng đó.

Bạn có thể tạo danh sách biểu tượng KMI cho một thiết bị bằng cách làm theo hướng dẫn trong Cách làm việc với danh sách biểu tượng. Nhiều đối tác gửi một danh sách biểu tượng cho mỗi ACK, nhưng đây không phải là một yêu cầu khó khăn. Nếu việc này giúp bảo trì, bạn có thể gửi nhiều danh sách biểu tượng.

Mở rộng KMI

Trong khi các ký hiệu KMI và cấu trúc liên quan được duy trì ở dạng ổn định (nghĩa là những thay đổi phá vỡ giao diện ổn định trong một nhân có KMI bị treo không thể đã chấp nhận) hạt nhân GKI vẫn mở cho các tiện ích để thiết bị vận chuyển không cần xác định tất cả các phần phụ thuộc trước khi KMI bị treo. Để mở rộng KMI, bạn có thể thêm các biểu tượng mới vào KMI cho các hàm nhân hệ điều hành đã xuất hiện có, ngay cả khi KMI bị treo. Nhân hệ điều hành mới bản vá cũng có thể được chấp nhận nếu chúng không phá vỡ KMI.

Giới thiệu về lỗi KMI

Hạt nhân có các nguồn và tệp nhị phân được xây dựng từ các nguồn đó. Các nhánh nhân được giám sát theo ABI chứa một bản đại diện ABI của GKI hiện tại ABI (ở dạng tệp .stg). Sau tệp nhị phân (vmlinux, Image và bất kỳ mô-đun GKI nào), thì bản trình bày ABI có thể được trích xuất từ tệp nhị phân. Mọi thay đổi đối với tệp nguồn kernel đều có thể ảnh hưởng đến tệp nhị phân và cũng ảnh hưởng đến .stg được trích xuất. Trình phân tích AbiAnalyzer so sánh tệp .stg đã xác nhận, trong đó tệp được trích xuất từ các cấu phần phần mềm bản dựng và đặt một Nhãn tìm lỗi mã nguồn 1 trên sự 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 một 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 có áp dụ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 ABI 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 xây dựng

Nguyên nhân phổ biến nhất gây ra lỗi là khi người lái xe sử dụng biểu tượng mới từ nhân không có trong bất kỳ danh sách biểu tượng nào.

Nếu biểu tượng đó không có trong danh sách biểu tượng (android/abi_gki_aarch64), thì trước tiên, bạn cần xác minh rằng dữ liệu được xuất bằng EXPORT_SYMBOL_GPL(symbol_name), sau đó cập nhật Danh sách biểu tượng và bản trình bày XML của ABI. Ví dụ: những 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 việc cập nhật danh sách biểu tượng và bản trình bày XML của ABI.

  • Ví dụ về thay đổi tính năng ở aosp/1345659.
  • Ví dụ về danh sách biểu tượng có trong aosp/1346742.
  • Ví dụ về thay đổi XML của ABI có trong aosp/1349377.

Nếu biểu tượng được xuất (do bạn hoặc đã được xuất trước đó) nhưng không trình điều khiển khác đang sử dụng đoạn mã đó, 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 biểu tượng KMI trong cả nhân và ACK (xem Cập nhật bản trình bày ABI). Ví dụ về việc cập nhật XML của ABI và danh sách biểu tượng trong ACK, hãy tham khảo aosp/1367601.

Khắc phục lỗi hỏng ABI trong hệ điều hành

Bạn có thể xử lý lỗi với ABI kernel bằng cách cải tiến cấu trúc mã để không thay đổi ABI hoặc cập nhật bản trình bày ABI. Sử dụng biểu đồ để xác định phương pháp tốt nhất cho trường hợp của bạn.

Biểu đồ quy trình ngắt ABI

Hình 1. Độ phân giải của ABI (Giao diện nhị phân ứng dụng)

Tái cấu trúc mã để tránh các thay đổi về ABI

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á những 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 để gỡ lỗi hãy thêm #ifdef xung quanh các trường (trong cấu trúc và nguồn tham chiếu) và đảm bảo rằng CONFIG dùng cho #ifdef đã bị tắt cho defconfig sản xuất và gki_defconfig. Ví dụ về cách gỡ lỗi cấu hình có thể được thêm vào một cấu trúc mà không làm hỏng ABI, hãy tham khảo bài viết này patchset.

  • Tái cấu trúc các tính năng để không thay đổi nhân hệ điều hành chính. Nếu các tính năng mới cần để thêm vào ACK nhằm hỗ trợ các mô-đun đối tác, hãy thử tái cấu trúc ABI của nội dung thay đổi nhằm tránh sửa đổi ABI của nhân. Ví dụ về cách sử dụng ABI nhân hiện tại để thêm các tính năng bổ sung mà không cần thay đổi ABI nhân tham chiếu đến aosp/1312213.

Khắc phục ABI bị hỏng trên Android Gerrit

Nếu không cố ý phá vỡ ABI nhân hệ điều hành thì bạn cần điều tra, theo hướng dẫn do công cụ theo dõi ABI cung cấp. Phổ biến nhất nguyên nhân gây ra sự cố là cấu trúc dữ liệu bị thay đổi và ký hiệu tương ứng là CRC hoặc do các thay đổi về tuỳ chọn cấu hình dẫn đến bất kỳ sự thay đổi 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 ABI cục bộ, xem Xây dựng hạt nhân và bản trình bày 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 có chứa KMI cố định hoặc đã hoàn tất, thì các thay đổi phải chuyển AbiAnalyzer để đảm bảo các thay đổi không ảnh hưởng đến phiên bản ổn định ABI theo cách không tương thích. Trong quá trình này, AbiAnalyzer sẽ tìm kiếm Báo cáo ABI được tạo trong quá trình tạo bản dựng (bản dựng mở rộng thực hiện bản dựng thông thường và sau đó là một số bước so sánh và trích xuất ABI.

Nếu tìm thấy một báo cáo không trống, AbiAnalyzer sẽ đặt nhãn Tìm lỗi mã nguồn 1 và thay đổi sẽ không được gửi cho đến khi được giải quyết; cho đến khi tập hợp bản vá nhận được Nhãn tìm lỗi mã nguồn+1.

Cập nhật ABI kernel

Nếu bắt buộc phải sửa đổi ABI, bạn phải áp dụng các thay đổi mã, bản trình bày ABI và danh sách biểu tượng cho ACK. Để tìm lỗi mã nguồn đến xoá -1 và không làm hỏng khả năng tương thích của GKI, hãy làm theo các bước sau:

  1. Tải các thay đổi mã lên ACK.

  2. Chờ nhận 2 tính năng Đánh giá mã cho bộ bản vá.

  3. Cập nhật bản trình bày ABI tham chiếu.

  4. Hợp nhất các thay đổi về mã và thay đổi về bản 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 tuỳ thuộc vào loại thay đổi được thực hiện.

  • Nếu thay đổi về ABI có liên quan đến một tính năng ảnh hưởng đến thử nghiệm CTS hoặc VTS, thì thường có thể được chọn chính xác cho ACK. Ví dụ:

  • Nếu thay đổi về ABI xảy ra với một tính năng có thể chia sẻ được với ACK, thì thay đổi có thể được chọn chính xác cho ACK. Ví dụ: những thay đổi sau không cần cho xét nghiệm CTS hoặc VTS nhưng có thể chia sẻ với ACK:

  • Nếu thay đổi về 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ể đưa các ký hiệu vào ACK bằng cách sử dụng một mã giả lập như được mô tả trong phần sau đây.

Sử dụng mã giả lập cho ACK

Các đoạn mã tạm thời chỉ cần thiết cho những thay đổi về nhân cốt lõi 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. Các ví dụ sau đây về danh sách chi tiết các mã giả lập và một phần lựa chọn quả anh đào trong ACK cho GKI.

  • Mã giả lập tính năng cốt lõi (aosp/1284493). Không nhất thiết phải có các khả năng trong ACK nhưng bắt buộc phải có các ký hiệu trong ACK cho các mô-đun của bạn để sử dụng các ký hiệu này.

  • Biểu tượng phần giữ chỗ cho mô-đun nhà cung cấp (aosp/1288860).

  • Lựa chọn anh đào chỉ dành cho ABI của tính năng theo dõi sự kiện mm trên mỗi quy trình (aosp/1288454). Bản vá ban đầu được chọn tại ACK, sau đó được cắt bớt để chỉ đưa vào bản vá các thay đổi cần thiết để giải quyết điểm khác biệt về ABI cho task_structmm_event_count Bản vá này cũng cập nhật enum mm_event_type để chứa thành viên cuối cùng.

  • Lựa chọn một phần các thay đổi về cấu trúc nhiệt của ABI đòi hỏi nhiều hơn so với chỉ thêm các trường ABI mới.

    • Miếng dán aosp/1255544 đã giải quyết sự khác biệt về ABI giữa nhân hệ điều hành của đối tác và ACK.

    • Miếng dán aosp/1291018 khắc phục các vấn đề về chức năng phát hiện thấy trong quá trình kiểm thử GKI của bản vá trước đó. Khắc phục lỗi bao gồm việc khởi tạo cấu trúc thông số cảm biến để đăng ký nhiều vùng nhiệt thành một cảm biến.

  • CONFIG_NL80211_TESTMODE thay đổi về ABI (aosp/1344321). Bản vá này thêm các thay đổi cần thiết về cấu trúc cho ABI và đảm bảo các trường bổ sung không gây ra sự khác biệt về chức năng, nên các đối tác có thể để đưa CONFIG_NL80211_TESTMODE vào hạt nhân sản xuất mà vẫn duy trì 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=yUNUSED_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 được xuất sử dụng EXPORT_SYMBOL_GPL()) sang các biểu tượng được liệt kê trên danh sách biểu tượng. Tất cả các biểu tượng khác chưa được xuất và việc tải một mô-đun đòi hỏi biểu tượng chưa xuất bị từ chối. Quy định hạn chế này được thực thi tại thời điểm xây dựng và mục nhập bị thiếu đã bị 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 cắt bớt biểu tượng (có nghĩa là có thể sử dụng tất cả các biểu tượng thường được xuất). Để định vị các bản dựng này, hãy tìm kernel_debug_aarch64 dựa trên ci.android.com.

Thực thi KMI bằng cách sử dụng 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 tuân thủ KMI tại thời gian chạy. Việc tạo phiên bản mô-đun có thể khiến tính năng kiểm tra dự phòng theo chu kỳ (CRC) không khớp lỗi tại thời gian tải mô-đun nếu KMI dự kiến của một mô-đun không khớp với vmlinux KMI. Ví dụ: sau đây là một lỗi thường xảy ra lúc thời gian tải mô-đun do CRC không khớp đối 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 ''

Việc sử dụng cách tạo phiên bản mô-đun

Việc tạo phiên bản mô-đun rất hữu ích vì những lý do sau:

  • Việc lập phiên bản mô-đun sẽ nắm bắt các thay đổi về chế độ hiển thị cấu trúc dữ liệu. Nếu 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, chúng sẽ bị hỏng sau các thay đổi sau này đối với cấu trúc.

    Ví dụ: hãy cân nhắc về fwnode trong struct device. Trường này PHẢI được làm mờ đối với các mô-đun để chúng không thể thực hiện các thay đổi đối với trường device->fw_node hoặc đưa ra giả định về kích thước của nó.

    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ường fwnode trong struct device không còn mờ với trường này nữa. Chiến lược phát hành đĩa đơn sau đó có thể thực hiện các thay đổi đối với device->fwnode->dev hoặc device->fwnode->ops Tình huống này có vấn đề vì một vài lý do, được khai báo như sau:

    • Nó có thể phá vỡ các giả định mà mã hạt nhân cốt lõi đưa ra về nội bộ cấu trúc dữ liệu.

    • Nếu một bản cập nhật nhân hệ điều hành trong tương lai làm thay đổi struct fwnode_handle (dữ liệu fwnode), thì mô-đun không còn hoạt động với nhân mới. Hơn nữa, stgdiff sẽ không cho thấy sự khác biệt nào do mô-đun đang bị lỗi KMI bằng cách trực tiếp thao túng các cấu trúc dữ liệu nội bộ theo những cách mà chỉ được thu thập bằng cách kiểm tra cách biểu diễn nhị phân.

  • Một mô-đun hiện tại bị coi là không tương thích với KMI khi được tải vào một ngày sau này bởi một nhân mới không tương thích. Việc tạo phiên bản mô-đun sẽ bổ sung tính năng kiểm tra thời gian chạy cho tránh vô tình tải một mô-đun không tương thích với KMI với nhân. Bước kiểm tra này ngăn chặn các vấn đề khó gỡ lỗi trong thời gian chạy và các sự cố về nhân hệ điều hành có thể do sự không tương thích không xác định được trong KMI.

Việc bật tính năng tạo phiên bản mô-đun sẽ ngăn tất cả các vấn đề này.

Kiểm tra các trường hợp CRC không khớp mà không cần khởi động thiết bị

stgdiff so sánh và báo cáo trường hợp không khớp CRC giữa các hạt nhân cùng với các hạt nhân khác Sự khác biệt về ABI.

Ngoài ra, bản dựng nhân hệ điều hành đầy đủ có bật CONFIG_MODVERSIONS sẽ tạo ra một 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 biểu tượng mà nhân (vmlinux) và các mô-đun xuất. Một 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 dành cho biểu tượng và kiểu xuất (ví dụ: EXPORT_SYMBOL đấu 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 mà vmlinux xuất hay không. Nếu có là sự khác biệt về giá trị CRC trong bất kỳ biểu tượng nào được xuất bởi vmlinux đó là biểu tượng được sử dụng bởi một trong các mô-đun bạn tải trong thiết bị của mình, mô-đun không tải.

Nếu bạn không có tất cả cấu phần phần mềm của bản dựng nhưng lại có tệp vmlinux của nhân GKI và nhân của bạn, bạn có thể so sánh các giá trị CRC cho một bằng cách chạy lệnh sau trên cả hai nhân và so sánh đầu ra:

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

Ví dụ: lệnh sau đây kiểm tra giá trị CRC cho module_layout ký hiệu:

nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout

Giải quyết trường hợp không khớp CRC

Làm theo các bước sau đây để giải quyết lỗi CRC không khớp khi tải mô-đun:

  1. Tạo nhân hệ điều hành GKI và nhân hệ điều hành của thiết bị bằng --kbuild_symtypes như được thể hiện 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. Xem KBUILD_SYMTYPES trong Kleaf để biết thông tin chi tiết.

    Đối với Android 13 trở xuống, hãy tạo nhân GKI và nhân của thiết bị bằng cách thêm KBUILD_SYMTYPES=1 vào lệnh mà bạn dùng sử dụng để tạo nhân, như minh hoạ 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 sẽ được ngầm đặt rồi.

  2. Tìm tệp .c, trong đó biểu tượng không khớp CRC được xuất, sử dụng lệnh sau:

    cd common && git grep EXPORT_SYMBOL.*module_layout
    kernel/module.c:EXPORT_SYMBOL(module_layout);
    
  3. Tệp .c có tệp .symtypes tương ứng trong GKI và cấu phần phần mềm bản dựng nhân hệ điều hành của thiết bị. Xác định vị trí tệp .c bằng cách sử dụng đoạn mã sau các lệnh:

    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 biểu tượng.

    • [s|u|e|etc]# ở đầu đườ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 biểu tượng là một hàm. Ví dụ:

      find_module s#module * find_module ( const char * )
      
  4. So sánh 2 tệp rồi khắc phục tất cả các đ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ữ nguyên một biểu tượng hoặc kiểu dữ liệu làm mờ các mô-đun và hạt nhân còn lại kernel không, sự khác biệt đó sẽ xuất hiện giữa các tệp .symtypes về 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 khác có chế độ xem mở rộng của ký hiệu hoặc kiểu dữ liệu.

Ví dụ: thêm dòng sau vào thẻ Tệp include/linux/device.h trong nhân của bạn khiến CRC không khớp, một trong số đó dành cho module_layout():

 #include <linux/fwnode.h>

So sánh module.symtypes cho biểu tượng đó, hiển thị kết quả sau khác biệt:

 $ 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), sau đó hợp nhất Hạt nhân phổ biến mới nhất của Android thành nhân hệ điều hành của mình để bạn đang dùng cơ sở nhân hệ điều hành 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 này có giá trị chi tiết bên trong của biểu tượng do các thay đổi đối với nhân của bạn. Đây là vì một trong các tệp trong nhân của bạn đã thêm một #include không có trong 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 các bước:

  1. Mở tệp tiêu đề xác định biểu tượng hoặc kiểu dữ liệu có hàm này khác biệt. Ví dụ: chỉnh sửa include/linux/fwnode.h cho phần tử struct fwnode_handle

  2. Thêm mã sau vào đầu tệp tiêu đề:

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. Trong tệp .c của mô-đun có CRC không khớp, hãy thêm tiếp theo là dòng đầu tiên trước mọi dòng #include.

    #define CRC_CATCH 1
    
  4. Biên dịch mô-đun. Lỗi thời gian xây dựng thu được cho thấy chuỗi tệp tiêu đề #include dẫn đến CRC không khớp 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 có sự thay đổi trong nhân hệ điều hành, bị thiếu trong nhân GKI.

  5. Xác định thay đổi, huỷ bỏ thay đổi đó trong nhân của bạn hoặc tải tệp lên ACK rồi hợp nhất tệp đó.

Trường hợp 2: Chênh lệch do các thay đổi về loại dữ liệu

Nếu CRC không khớp đối với một biểu tượng hoặc loại dữ liệu không phải là do có sự khác biệt về thì đó là do những thay đổi thực tế (thêm, xoá hoặc thay đổi) trong chính loại dữ liệu đó.

Ví dụ: việc thực hiện thay đổi sau đây trong nhân hệ điều hành của bạn sẽ gây ra một số CRC không khớp 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à cho devm_of_platform_populate().

Nếu bạn so sánh các tệp .symtypes cho biểu tượng đó, thì mã sẽ có dạng 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:

  1. Tìm định nghĩa của biểu tượng trong mã nguồn (thường có trong các tệp .h).

    • Để biết sự khác biệt về biểu tượng giữa nhân hệ điều hành của bạn và nhân hệ điều hành GKI, tìm cam kết bằng cách chạy lệnh sau:
    git blame
    
    • Đối với các biểu tượng bị xoá (trong đó một biểu tượng bị xoá trong cây và bạn cũng muốn xoá trong cây khác), bạn cần tìm thay đổi mà đã xoá đường này. Sử dụng lệnh sau trên cây nơi dòng đã bị xoá:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
    
  2. Xem lại danh sách cam kết được trả về để tìm nội dung thay đổi hoặc xoá. Chiến lược phát hành đĩa đơn đầu tiên cam kết có thể là điều bạn đang tìm kiếm. Nếu không, hãy truy cập qua danh sách cho đến khi bạn tìm thấy cam kết.

  3. Sau khi xác định được thay đổi, hãy huỷ bỏ thay đổi đó trong nhân của bạn hoặc tải tệp lên ACK và tải xuống đã hợp nhất.