Độ ổn định của ABI

Tính ổn định của Giao diện nhị phân ứng dụng (ABI) là điều kiện tiên quyết của các bản cập nhật chỉ dành cho 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 Vendor Native Development Kit (VNDK) nằm trong phân vùng hệ thống. Trong một bản phát hành Android, các thư viện dùng chung VNDK mới tạo phải tương thích với ABI của các thư viện dùng chung VNDK đã phát hành trước đó để các mô-đun của nhà cung cấp có thể hoạt động với những 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, các thư viện VNDK có thể thay đổi và không có đảm bảo ABI.

Để đảm bảo khả năng tương thích ABI, Android 9 có một trình kiểm tra ABI tiêu đề, như mô tả trong các phần sau.

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

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

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

Biểu tượng được xuất (còn gọi là biểu tượng chung) đề cập đến một biểu tượng đáp ứng tất cả các điều kiện sau:

  • Được xuất bởi tiêu đề công khai của một 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 dùng chung.
  • Có liên kết YẾU hoặc TOÀN CỤC.
  • Chế độ hiển thị là MẶC ĐỊNH hoặc ĐƯỢC BẢO VỆ.
  • Chỉ mục phần không phải là UNDEFINED.
  • Loại là FUNC hoặc OBJECT.

Tiêu đề công khai của một thư viện dùng chung được xác định là các tiêu đề có sẵn cho các thư viện/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 các đị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 tích hợp sẵn hoặc do người dùng xác định nào của C/C++ 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 các tiêu đề công khai. Ví dụ: libfoo.so có hàm Foo. Đây là một biểu tượng được xuất có trong bảng .dynsym. Thư viện libfoo.so bao gồm những nội dung 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

Nhìn vào 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ố đầu tiên Foo.
bar_t * Loại tham số Foo thứ hai. Thông qua bar_t *, bar_t được xuất 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 có nhiều loại được xuất 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 thể truy cập được vì không được xuất thông qua foo_exported.h. (foo_private_t * là một đối tượng mờ, do đó, bạn được phép thay đổi foo_private_t.)

Bạn cũng có thể đưa ra lời giải thích tương tự cho các loại có thể truy cập thông qua các bộ 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 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 kiểu dữ liệu có thể truy cập trực tiếp hoặc gián tiếp bằng một hàm đã xuất, những thay đổi sau đây đối với một thư viện được phân loại là thay đổi làm gián đoạn ABI:

Loại dữ liệu Mô tả
Cấu trúc và lớp học
  • 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á các 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 viên*.
    • Thêm hoặc xoá đối số khỏi các hàm thành viên.
    • Thay đổi các loại đối số hoặc các loại dữ liệu trả về của các hàm thành phần*.
    • Thay đổi bố cục bảng ảo.
  • Thành viên dữ liệu
    • Xoá các thành phần dữ liệu tĩnh.
    • Thêm hoặc xoá các thành viên dữ liệu không tĩnh.
    • Thay đổi các loại thành viên dữ liệu.
    • Thay đổi các độ lệch thành thành viên dữ liệu không tĩnh**.
    • Thay đổi các trình đủ tiêu chuẩn const, volatile và/hoặc restricted của thành phần dữ liệu***.
    • Hạ cấp bộ chỉ định quyền truy cập của các thành viên dữ liệu***.
  • Thay đổi đối số mẫu.
Liên minh
  • Thêm hoặc xoá thành viên dữ liệu.
  • Thay đổi kích thước của loại hợp nhất.
  • Thay đổi các loại thành viên dữ liệu.
Bảng liệt kê
  • Thay đổi loại cơ bản.
  • Thay đổi tên của các trình liệt kê.
  • Thay đổi giá trị của các trình liệt kê.
Biểu tượng toàn cầu
  • Xoá các biểu tượng do tiêu đề công khai xuất.
  • Đối với các biểu tượng toàn cầu thuộc loại FUNC
    • Thêm hoặc xoá đối số.
    • Thay đổi các loại đối số.
    • Thay đổi loại dữ liệu trả về.
    • Giảm cấp chỉ định quyền truy cập***.
  • Đối với các biểu tượng chung thuộc loại OBJECT
    • Thay đổi loại C/C++ tương ứng.
    • Giảm cấp chỉ định quyền truy cập***.

* Cả hàm thành viên công khai và riêng tư đều không được thay đổi hoặc xoá 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ư. Các tham chiếu biểu tượng đến các hàm thành viên riêng tư có thể được giữ trong các tệp nhị phân của người 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 độ lệch của các 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 độ lệch của 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 thay đổi này không làm thay đổi bố cục bộ nhớ của loại, nhưng có những khác biệt về ngữ nghĩa có thể khiến các thư viện không hoạt động như mong đợi.

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

Khi một thư viện VNDK được tạo, 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 kết xuất ABI tham chiếu nằm trong:

${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 sẽ được so sánh với ABI tham chiếu tại:

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

Lỗi ABI bị hỏng

Khi ABI bị gián đoạn, nhật ký bản dựng sẽ hiển thị cảnh báo kèm theo 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 bản dựng sẽ phát sinh 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 một 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 riêng 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 tĩnh bắc cầu), để tạo ra các tệp .sdump tương ứng với từng nguồn.
    tạo sdump
    Hình 1. Tạo tệp .sdump
  2. header-abi-linker sau đó 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 tệp đó hoặc tệp .so tương ứng với thư viện dùng chung) để tạo ra tệp .lsdump ghi lại 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 ra một báo cáo chênh lệch 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 chênh lệch

header-abi-dumper

Công cụ header-abi-dumper phân tích cú pháp một tệp nguồn C/C++ và kết xuất ABI suy luận 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 xây dựng 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++
  • Xuất các thư mục bao gồm
  • Cờ trình biên dịch
Đầu ra Một 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. Định dạng này không đảm bảo tính ổn định trong các bản phát hành sau này. Do đó, việc định dạng tệp .sdump cần được coi là một chi tiết triển khai hệ thống bản dựng.

Ví dụ: libfoo.so có tệp nguồn sau 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 sau -- và phát ra 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 và các tiêu đề công khai xuất, ví dụ:

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

header-abi-linker

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 ra
  • 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
  • Xuất các thư mục bao gồm
Đầu ra Một 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ề một định nghĩa (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 nhau về mặt 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 một 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 được xuất.

Ví dụ: libfoo bao gồm foo.cppbar.cpp. header-abi-linker có thể được gọi để tạo bản 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

Ví dụ về đầu ra của lệnh 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 tệp đó (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 biểu tượng do thư viện xuất thông 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 ra một báo cáo chênh lệch 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 chênh lệch nêu rõ sự khác biệt trong ABI do hai thư viện dùng chung được so sánh cung cấp.

Tệp chênh lệch ABI có đị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 của libfoo: libfoo_old.solibfoo_new.so. Trong libfoo_new.so, trong bar_t, bạn thay đổi loại mfoo từ foo_t thành foo_t *. Vì bar_t là một kiểu có thể truy cập, nên header-abi-diff sẽ gắn cờ đây là một thay đổi có thể gây lỗi ABI.

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ề đầu ra 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 làm gián đoạn 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ị loại bỏ).

Trường type_stack cho biết cách header-abi-diff đạt đến loại đã thay đổi (bar). Trường này có thể được diễn giải là Foo là một hàm được xuất nhận 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 các thư viện dùng chung VNDK, bạn phải kiểm tra các tham chiếu ABI vào ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/vndk/. Để tạo các tham 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 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 một thư viện VNDK hiện sẽ dẫn đến lỗi bản dựng.

Để cập nhật các 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 tham chiếu ABI libbinder, hãy chạy:

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