Độ ổn định của ABI

Tính ổn định của Giao diện nhị phân của ứng dụng (ABI) là điều kiện tiên quyết của việc cập nhật chỉ khung, vì các mô-đun của nhà cung cấp có thể phụ thuộc vào các thư viện dùng chung của Bộ phát triển gốc dành cho nhà cung cấp (VNDK) nằm trong phân vùng hệ thống. Trong bản phát hành Android, các thư viện chia sẻ VNDK mới tạo phải tương thích với ABI với các thư viện chia sẻ VNDK đã phát hành trước đó để các mô-đun nhà cung cấp có thể hoạt động với các thư viện đó mà không cần biên dịch lại và không gặp lỗi thời gian chạy. Giữa các bản phát hành Android, thư viện VNDK có thể thay đổi và không có gì đảm bảo về ABI.

Để giúp đảm bảo khả năng tương thích với ABI, Android 9 cung cấp trình kiểm tra ABI tiêu đề, như mô tả trong các phần sau.

Giới thiệu về việc tuân thủ ABI và VNDK

VNDK là một tập hợp thư viện hạn chế mà các mô-đun nhà cung cấp có thể liên kết đến và cho phép cập nhật chỉ khung. Tuân thủ ABI đề cập đến khả năng một phiên bản thư viện dùng chung mới hơn hoạt động như mong đợi với một mô-đun được liên kết động với mô-đun đó (tức là hoạt động như phiên bản thư viện cũ).

Giới thiệu về biểu tượng đã xuất

Ký hiệu được xuất (còn gọi là ký hiệu toàn cục) là một ký hiệu đáp ứng tất cả các điều kiện sau:

  • Được xuất bởi tiêu đề công khai của thư viện dùng chung.
  • Xuất hiện trong bảng .dynsym của tệp .so tương ứng với thư viện chia sẻ.
  • Có liên kết WEAK hoặc GLOBAL.
  • Chế độ hiển thị là MẶC ĐỊNH hoặc BẢO VỆ.
  • Chỉ mục của mục không ĐƯỢC XÁC ĐỊNH.
  • Loại là FUNC hoặc OBJECT.

Tiêu đề công khai của thư viện dùng chung được xác định là tiêu đề có sẵn cho các thư viện/tệp nhị phân khác thông qua các thuộc tính export_include_dirs, export_header_lib_headers, export_static_lib_headers, export_shared_lib_headersexport_generated_headers trong định nghĩa Android.bp của mô-đun tương ứng với thư viện dùng chung.

Giới thiệu về các loại có thể truy cập

Loại có thể truy cập là bất kỳ loại C/C++ tích hợp hoặc do người dùng xác định nào có thể truy cập trực tiếp hoặc gián tiếp thông qua một biểu tượng đã xuất VÀ được xuất thông qua tiêu đề công khai. Ví dụ: libfoo.so có hàm Foo, đây là một biểu tượng đã xuất có trong bảng .dynsym. Thư viện libfoo.so bao gồm các thành phần sau:

foo_exported.h foo.private.h
typedef struct foo_private foo_private_t;

typedef struct foo {
  int m1;
  int *m2;
  foo_private_t *mPfoo;
} foo_t;

typedef struct bar {
  foo_t mfoo;
} bar_t;

bool Foo(int id, bar_t *bar_ptr);
typedef struct foo_private {
  int m1;
  float mbar;
} foo_private_t;
Android.bp
cc_library {
  name : libfoo,
  vendor_available: true,
  vndk {
    enabled : true,
  }
  srcs : ["src/*.cpp"],
  export_include_dirs : [
    "exported"
  ],
}
bảng .dynsym
Num Value Size Type Bind Vis Ndx Name
1 0 0 FUNC GLOB DEF UND dlerror@libc
2 1ce0 20 FUNC GLOB DEF 12 Foo

Khi xem xét Foo, các loại có thể truy cập trực tiếp/gián tiếp bao gồm:

Loại Mô tả
bool Loại dữ liệu trả về của Foo.
int Loại tham số Foo đầu tiên.
bar_t * Loại tham số Foo thứ hai. Thông qua bar_t *, bar_t được xuất thông qua foo_exported.h.

bar_t chứa một thành phần mfoo, thuộc loại foo_t, được xuất thông qua foo_exported.h, dẫn đến việc xuất nhiều loại hơn:
  • int : là loại m1.
  • int * : là loại m2.
  • foo_private_t * : là loại mPfoo.

Tuy nhiên, foo_private_t KHÔNG truy cập được vì không được xuất thông qua foo_exported.h. (foo_private_t * là mờ, do đó, các thay đổi đối với foo_private_t được cho phép.)

Bạn cũng có thể đưa ra giải thích tương tự cho các loại có thể truy cập thông qua chỉ định lớp cơ sở và tham số mẫu.

Đảm bảo tuân thủ ABI

Bạn phải đảm bảo tuân thủ ABI cho các thư viện được đánh dấu là vendor_available: truevndk.enabled: true trong các tệp Android.bp tương ứng. Ví dụ:

cc_library {
    name: "libvndk_example",
    vendor_available: true,
    vndk: {
        enabled: true,
    }
}

Đối với các loại dữ liệu mà hàm đã xuất có thể truy cập trực tiếp hoặc gián tiếp, các thay đổi sau đây đối với thư viện được phân loại là vi phạm ABI:

Kiểu dữ liệu Mô tả
Cấu trúc và lớp
  • Thay đổi kích thước của loại lớp hoặc loại cấu trúc.
  • Lớp cơ sở
    • Thêm hoặc xoá lớp cơ sở.
    • Thêm hoặc xoá các lớp cơ sở được kế thừa ảo.
    • Thay đổi thứ tự của các lớp cơ sở.
  • Hàm thành phần
    • Xoá các hàm thành phần*.
    • Thêm hoặc xoá đối số khỏi các hàm thành viên.
    • Thay đổi loại đối số hoặc loại dữ liệu trả về của hàm thành phần*.
    • Thay đổi bố cục bảng ảo.
  • Thành phần dữ liệu
    • Xoá các thành phần dữ liệu tĩnh.
    • Thêm hoặc xoá thành phần dữ liệu không tĩnh.
    • Thay đổi loại thành phần dữ liệu.
    • Thay đổi độ dời thành thành phần dữ liệu không tĩnh**.
    • Thay đổi bộ hạn định const, volatile và/hoặc restricted của các thành phần dữ liệu***.
    • Hạ cấp chỉ định quyền truy cập của các thành phần dữ liệu***.
  • Thay đổi đối số mẫu.
Liên minh
  • Thêm hoặc xoá thành phần dữ liệu.
  • Thay đổi kích thước của loại dữ liệu hợp nhất.
  • Thay đổi loại thành phần dữ liệu.
Liệt kê
  • Thay đổi loại cơ bản.
  • Thay đổi tên của bộ đếm.
  • Thay đổi giá trị của bộ đếm.
Biểu tượng chung
  • Xoá các biểu tượng do tiêu đề công khai xuất.
  • Đối với các ký hiệu toàn cục thuộc loại FUNC
    • Thêm hoặc xoá đối số.
    • Thay đổi loại đối số.
    • Thay đổi loại dữ liệu trả về.
    • Hạ cấp chỉ định quyền truy cập***.
  • Đối với các ký hiệu toàn cục thuộc loại OBJECT
    • Thay đổi loại C/C++ tương ứng.
    • Hạ cấp chỉ định quyền truy cập***.

* Bạn không được thay đổi hoặc xoá cả hàm thành viên công khai và hàm thành viên riêng tư vì các hàm nội tuyến công khai có thể tham chiếu đến các hàm thành viên riêng tư. Bạn có thể giữ lại ký hiệu tham chiếu đến các hàm thành phần riêng tư trong tệp nhị phân của phương thức gọi. Việc thay đổi hoặc xoá các hàm thành viên riêng tư khỏi thư viện dùng chung có thể dẫn đến các tệp nhị phân không tương thích ngược.

** Bạn không được thay đổi độ dời đối với thành phần dữ liệu công khai hoặc riêng tư vì các hàm nội tuyến có thể tham chiếu đến các thành phần dữ liệu này trong phần nội dung hàm. Việc thay đổi độ dời thành phần dữ liệu có thể dẫn đến các tệp nhị phân không tương thích ngược.

*** Mặc dù những điều này không thay đổi bố cục bộ nhớ của loại, nhưng có sự khác biệt về ngữ nghĩa có thể khiến thư viện không hoạt động như mong đợi.

Sử dụng các công cụ tuân thủ ABI

Khi tạo thư viện VNDK, ABI của thư viện sẽ được so sánh với tài liệu tham khảo ABI tương ứng cho phiên bản VNDK đang được tạo. Tệp báo lỗi tham chiếu ABI nằm ở:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/<PLATFORM_VNDK_VERSION>/<BINDER_BITNESS>/<ARCH>/source-based

Ví dụ: khi tạo libfoo cho x86 ở API cấp 27, ABI suy luận của libfoo được so sánh với tệp tham chiếu của ABI đó tại:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/27/64/x86/source-based/libfoo.so.lsdump

Lỗi hỏng ABI

Khi xảy ra lỗi ABI, nhật ký bản dựng sẽ hiển thị cảnh báo cùng với loại cảnh báo và đường dẫn đến báo cáo abi-diff. Ví dụ: nếu ABI của libbinder có một thay đổi không tương thích, hệ thống xây dựng sẽ gửi một lỗi kèm theo thông báo tương tự như sau:

*****************************************************
error: VNDK library: libbinder.so's ABI has INCOMPATIBLE CHANGES
Please check compatibility report at:
out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm64_armv8-a_cortex-a73_vendor_shared/libbinder.so.abidiff
******************************************************
---- Please update abi references by running
platform/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l libbinder ----

Tạo các bước kiểm tra ABI thư viện VNDK

Khi thư viện VNDK được tạo:

  1. header-abi-dumper xử lý các tệp nguồn được biên dịch để tạo thư viện VNDK (các tệp nguồn của thư viện cũng như các tệp nguồn được kế thừa thông qua các phần phụ thuộc bắc cầu tĩnh) để tạo các tệp .sdump tương ứng với từng nguồn.
    Tạo sdump
    Hình 1. Tạo các tệp .sdump
  2. Sau đó, header-abi-linker sẽ xử lý các tệp .sdump (bằng cách sử dụng tập lệnh phiên bản được cung cấp cho thư viện dùng chung hoặc tệp .so tương ứng với thư viện dùng chung) để tạo một tệp .lsdump ghi nhật ký tất cả thông tin ABI tương ứng với thư viện dùng chung.
    Tạo lsdump
    Hình 2. Tạo tệp .lsdump
  3. header-abi-diff so sánh tệp .lsdump với tệp .lsdump đối chiếu để tạo báo cáo so sánh nêu rõ sự khác biệt trong ABI của hai thư viện.
    tạo abi diff
    Hình 3. Tạo báo cáo điểm khác biệt

header-abi-dumper

Công cụ header-abi-dumper phân tích cú pháp tệp nguồn C/C++ và kết xuất ABI suy ra từ tệp nguồn đó vào một tệp trung gian. Hệ thống xây dựng chạy header-abi-dumper trên tất cả các tệp nguồn đã biên dịch, đồng thời tạo một thư viện bao gồm các tệp nguồn từ các phần phụ thuộc bắc cầu.

Ngõ vào
  • Tệp nguồn C/C++
  • Thư mục bao gồm đã xuất
  • Cờ trình biên dịch
Đầu ra Tệp mô tả ABI của tệp nguồn (ví dụ: foo.sdump đại diện cho ABI của foo.cpp).

Hiện tại, các tệp .sdump ở định dạng JSON và không được đảm bảo sẽ ổn định trong các bản phát hành trong tương lai. Do đó, việc định dạng tệp .sdump nên được coi là một chi tiết triển khai hệ thống xây dựng.

Ví dụ: libfoo.so có tệp nguồn sau đây foo.cpp:

#include <stdio.h>
#include <foo_exported.h>

bool Foo(int id, bar_t *bar_ptr) {
    if (id > 0 && bar_ptr->mfoo.m1 > 0) {
        return true;
    }
    return false;
}

Bạn có thể sử dụng header-abi-dumper để tạo một tệp .sdump trung gian đại diện cho ABI do tệp nguồn trình bày bằng cách sử dụng:

$ header-abi-dumper foo.cpp -I exported -o foo.sdump -- -I exported -x c++

Lệnh này yêu cầu header-abi-dumper phân tích cú pháp foo.cpp bằng các cờ trình biên dịch theo -- và phát thông tin ABI do các tiêu đề công khai xuất trong thư mục exported. Sau đây là foo.sdump do header-abi-dumper tạo:

{
 "array_types" : [],
 "builtin_types" :
 [
  {
   "alignment" : 4,
   "is_integral" : true,
   "linker_set_key" : "_ZTIi",
   "name" : "int",
   "referenced_type" : "_ZTIi",
   "self_type" : "_ZTIi",
   "size" : 4
  }
 ],
 "elf_functions" : [],
 "elf_objects" : [],
 "enum_types" : [],
 "function_types" : [],
 "functions" :
 [
  {
   "function_name" : "FooBad",
   "linker_set_key" : "_Z6FooBadiP3foo",
   "parameters" :
   [
    {
     "referenced_type" : "_ZTIi"
    },
    {
     "referenced_type" : "_ZTIP3foo"
    }
   ],
   "return_type" : "_ZTI3bar",
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "global_vars" : [],
 "lvalue_reference_types" : [],
 "pointer_types" :
 [
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP11foo_private",
   "name" : "foo_private *",
   "referenced_type" : "_ZTI11foo_private",
   "self_type" : "_ZTIP11foo_private",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP3foo",
   "name" : "foo *",
   "referenced_type" : "_ZTI3foo",
   "self_type" : "_ZTIP3foo",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIPi",
   "name" : "int *",
   "referenced_type" : "_ZTIi",
   "self_type" : "_ZTIPi",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "qualified_types" : [],
 "record_types" :
 [
  {
   "alignment" : 8,
   "fields" :
   [
    {
     "field_name" : "mfoo",
     "referenced_type" : "_ZTI3foo"
    }
   ],
   "linker_set_key" : "_ZTI3bar",
   "name" : "bar",
   "referenced_type" : "_ZTI3bar",
   "self_type" : "_ZTI3bar",
   "size" : 24,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "fields" :
   [
    {
     "field_name" : "m1",
     "referenced_type" : "_ZTIi"
    },
    {
     "field_name" : "m2",
     "field_offset" : 64,
     "referenced_type" : "_ZTIPi"
    },
    {
     "field_name" : "mPfoo",
     "field_offset" : 128,
     "referenced_type" : "_ZTIP11foo_private"
    }
   ],
   "linker_set_key" : "_ZTI3foo",
   "name" : "foo",
   "referenced_type" : "_ZTI3foo",
   "self_type" : "_ZTI3foo",
   "size" : 24,
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "rvalue_reference_types" : []
}

foo.sdump chứa thông tin ABI do tệp nguồn foo.cpp xuất và các tiêu đề công khai, chẳng hạn như

  • record_types. Tham khảo các cấu trúc, liên kết hoặc lớp được xác định trong tiêu đề công khai. Mỗi loại bản ghi đều có thông tin về các trường, kích thước, thông số xác định quyền truy cập, tệp tiêu đề được xác định trong đó và các thuộc tính khác.
  • pointer_types. Tham chiếu đến các loại con trỏ được tham chiếu trực tiếp/gián tiếp bởi các bản ghi/hàm đã xuất trong tiêu đề công khai, cùng với loại con trỏ trỏ đến (thông qua trường referenced_type trong type_info). Thông tin tương tự được ghi lại trong tệp .sdump cho các loại đủ điều kiện, các loại C/C++ tích hợp, các loại mảng và các loại tham chiếu lvalue và rvalue. Thông tin đó cho phép so sánh đệ quy.
  • functions. Biểu thị các hàm do tiêu đề công khai xuất. Các tệp này cũng có thông tin về tên bị xáo trộn của hàm, loại dữ liệu trả về, loại tham số, chỉ định quyền truy cập và các thuộc tính khác.

trình liên kết tiêu đề

Công cụ header-abi-linker lấy các tệp trung gian do header-abi-dumper tạo làm dữ liệu đầu vào, sau đó liên kết các tệp đó:

Ngõ vào
  • Các tệp trung gian do header-abi-dumper tạo
  • Tập lệnh phiên bản/Tệp bản đồ (không bắt buộc)
  • Tệp .so của thư viện dùng chung
  • Thư mục bao gồm đã xuất
Đầu ra Tệp mô tả ABI của một thư viện dùng chung (ví dụ: libfoo.so.lsdump đại diện cho ABI của libfoo).

Công cụ này hợp nhất các biểu đồ loại trong tất cả các tệp trung gian được cung cấp cho công cụ, có tính đến sự khác biệt về định nghĩa một (các loại do người dùng xác định trong các đơn vị dịch khác nhau có cùng tên đủ điều kiện, có thể khác về ngữ nghĩa) giữa các đơn vị dịch. Sau đó, công cụ này sẽ phân tích cú pháp tập lệnh phiên bản hoặc bảng .dynsym của thư viện dùng chung (tệp .so) để tạo danh sách các ký hiệu đã xuất.

Ví dụ: libfoo bao gồm foo.cppbar.cpp. header-abi-linker có thể được gọi để tạo tệp kết xuất ABI được liên kết hoàn chỉnh của libfoo như sau:

header-abi-linker -I exported foo.sdump bar.sdump \
                  -o libfoo.so.lsdump \
                  -so libfoo.so \
                  -arch arm64 -api current

Kết quả lệnh mẫu trong libfoo.so.lsdump:

{
 "array_types" : [],
 "builtin_types" :
 [
  {
   "alignment" : 1,
   "is_integral" : true,
   "is_unsigned" : true,
   "linker_set_key" : "_ZTIb",
   "name" : "bool",
   "referenced_type" : "_ZTIb",
   "self_type" : "_ZTIb",
   "size" : 1
  },
  {
   "alignment" : 4,
   "is_integral" : true,
   "linker_set_key" : "_ZTIi",
   "name" : "int",
   "referenced_type" : "_ZTIi",
   "self_type" : "_ZTIi",
   "size" : 4
  }
 ],
 "elf_functions" :
 [
  {
   "name" : "_Z3FooiP3bar"
  },
  {
   "name" : "_Z6FooBadiP3foo"
  }
 ],
 "elf_objects" : [],
 "enum_types" : [],
 "function_types" : [],
 "functions" :
 [
  {
   "function_name" : "Foo",
   "linker_set_key" : "_Z3FooiP3bar",
   "parameters" :
   [
    {
     "referenced_type" : "_ZTIi"
    },
    {
     "referenced_type" : "_ZTIP3bar"
    }
   ],
   "return_type" : "_ZTIb",
   "source_file" : "exported/foo_exported.h"
  },
  {
   "function_name" : "FooBad",
   "linker_set_key" : "_Z6FooBadiP3foo",
   "parameters" :
   [
    {
     "referenced_type" : "_ZTIi"
    },
    {
     "referenced_type" : "_ZTIP3foo"
    }
   ],
   "return_type" : "_ZTI3bar",
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "global_vars" : [],
 "lvalue_reference_types" : [],
 "pointer_types" :
 [
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP11foo_private",
   "name" : "foo_private *",
   "referenced_type" : "_ZTI11foo_private",
   "self_type" : "_ZTIP11foo_private",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP3bar",
   "name" : "bar *",
   "referenced_type" : "_ZTI3bar",
   "self_type" : "_ZTIP3bar",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIP3foo",
   "name" : "foo *",
   "referenced_type" : "_ZTI3foo",
   "self_type" : "_ZTIP3foo",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "linker_set_key" : "_ZTIPi",
   "name" : "int *",
   "referenced_type" : "_ZTIi",
   "self_type" : "_ZTIPi",
   "size" : 8,
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "qualified_types" : [],
 "record_types" :
 [
  {
   "alignment" : 8,
   "fields" :
   [
    {
     "field_name" : "mfoo",
     "referenced_type" : "_ZTI3foo"
    }
   ],
   "linker_set_key" : "_ZTI3bar",
   "name" : "bar",
   "referenced_type" : "_ZTI3bar",
   "self_type" : "_ZTI3bar",
   "size" : 24,
   "source_file" : "exported/foo_exported.h"
  },
  {
   "alignment" : 8,
   "fields" :
   [
    {
     "field_name" : "m1",
     "referenced_type" : "_ZTIi"
    },
    {
     "field_name" : "m2",
     "field_offset" : 64,
     "referenced_type" : "_ZTIPi"
    },
    {
     "field_name" : "mPfoo",
     "field_offset" : 128,
     "referenced_type" : "_ZTIP11foo_private"
    }
   ],
   "linker_set_key" : "_ZTI3foo",
   "name" : "foo",
   "referenced_type" : "_ZTI3foo",
   "self_type" : "_ZTI3foo",
   "size" : 24,
   "source_file" : "exported/foo_exported.h"
  }
 ],
 "rvalue_reference_types" : []
}

Công cụ header-abi-linker:

  • Liên kết các tệp .sdump được cung cấp cho nó (foo.sdumpbar.sdump), lọc ra thông tin ABI không có trong các tiêu đề nằm trong thư mục: exported.
  • Phân tích cú pháp libfoo.so và thu thập thông tin về các ký hiệu mà thư viện xuất qua bảng .dynsym.
  • Thêm _Z3FooiP3bar_Z6FooBadiP3foo.

libfoo.so.lsdump là tệp kết xuất ABI được tạo cuối cùng của libfoo.so.

header-abi-diff

Công cụ header-abi-diff so sánh hai tệp .lsdump đại diện cho ABI của hai thư viện và tạo một báo cáo so sánh nêu rõ sự khác biệt giữa hai ABI.

Ngõ vào
  • Tệp .lsdump đại diện cho ABI của một thư viện dùng chung cũ.
  • Tệp .lsdump đại diện cho ABI của một thư viện dùng chung mới.
Đầu ra Báo cáo so sánh cho biết sự khác biệt trong ABI do hai thư viện dùng chung được so sánh cung cấp.

Tệp so sánh ABI ở định dạng văn bản protobuf. Định dạng này có thể thay đổi trong các bản phát hành sau này.

Ví dụ: bạn có hai phiên bản libfoo: libfoo_old.solibfoo_new.so. Trong libfoo_new.so, trong bar_t, bạn sẽ thay đổi loại mfoo từ foo_t thành foo_t *. Vì bar_t là một loại có thể tiếp cận, nên loại thay đổi này phải được gắn cờ là thay đổi có thể gây lỗi ABI trước header-abi-diff.

Cách chạy header-abi-diff:

header-abi-diff -old libfoo_old.so.lsdump \
                -new libfoo_new.so.lsdump \
                -arch arm64 \
                -o libfoo.so.abidiff \
                -lib libfoo

Ví dụ về kết quả của lệnh trong libfoo.so.abidiff:

lib_name: "libfoo"
arch: "arm64"
record_type_diffs {
  name: "bar"
  type_stack: "Foo-> bar *->bar "
  type_info_diff {
    old_type_info {
      size: 24
      alignment: 8
    }
    new_type_info {
      size: 8
      alignment: 8
    }
  }
  fields_diff {
    old_field {
      referenced_type: "foo"
      field_offset: 0
      field_name: "mfoo"
      access: public_access
    }
    new_field {
      referenced_type: "foo *"
      field_offset: 0
      field_name: "mfoo"
      access: public_access
    }
  }
}

libfoo.so.abidiff chứa báo cáo về tất cả các thay đổi phá vỡ ABI trong libfoo. Thông báo record_type_diffs cho biết một bản ghi đã thay đổi và liệt kê các thay đổi không tương thích, bao gồm:

  • Kích thước của bản ghi thay đổi từ 24 byte thành 8 byte.
  • Loại trường của mfoo thay đổi từ foo thành foo * (tất cả các typedef đều bị xoá).

Trường type_stack cho biết cách header-abi-diff truy cập vào loại đã thay đổi (bar). Trường này có thể được diễn giải là Foo là một hàm đã xuất, lấy bar * làm tham số, trỏ đến bar đã được xuất và thay đổi.

Thực thi ABI và API

Để thực thi ABI và API của thư viện dùng chung VNDK, bạn phải kiểm tra các tệp tham chiếu ABI vào ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/. Để tạo các tệp đối chiếu này, hãy chạy lệnh sau:

${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py

Sau khi tạo các tệp tham chiếu, mọi thay đổi đối với mã nguồn dẫn đến thay đổi ABI/API không tương thích trong thư viện VNDK hiện sẽ dẫn đến lỗi bản dựng.

Để cập nhật các tệp tham chiếu ABI cho các thư viện cụ thể, hãy chạy lệnh sau:

${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l <lib1> -l <lib2>

Ví dụ: để cập nhật các tệp tham chiếu ABI libbinder, hãy chạy:

${ANDROID_BUILD_TOP}/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l libbinder