Độ ổ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 bản cập nhật chỉ dựa trên khung vì các mô-đun nhà cung cấp có thể phụ thuộc vào Quảng cáo gốc của nhà cung cấp Các thư viện dùng chung của Bộ phát triển (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 thư viện chia sẻ VNDK đã phát hành trước đây, vì vậy, các mô-đun của nhà cung cấp có thể làm việc 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, bạn có thể thay đổi thư viện VNDK và không có ABI nào bảo đảm.

Để giúp đảm bảo khả năng tương thích với ABI, Android 9 bao gồm 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ủ VNDK và ABI

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 phiên bản mới hơn của thư viện dùng chung hoạt động như mong đợi với được liên kết động với mô-đun đó (tức là hoạt động như một phiên bản cũ của thư viện sẽ).

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

Biểu tượng được xuất (còn được gọi là biểu tượng toàn cầu) đề cập đến một ký hiệu thoả mãn tất cả các điều kiện sau:

  • Do tiêu đề công khai của thư viện chia sẻ xuất.
  • Xuất hiện trong bảng .dynsym của tệp .so tương ứng với thư viện chia sẻ.
  • Có ràng buộc WEAK hoặc TOÀN CẦU.
  • Chế độ hiển thị là MẶC ĐỊNH hoặc ĐƯỢ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 chia sẻ đượ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 export_include_dirs, export_header_lib_headers export_static_lib_headers, export_shared_lib_headers và Thuộc tính export_generated_headers trong Android.bp các định nghĩa của mô-đun tương ứng với thư viện chia sẻ.

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

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

Trong Foo, các loại có thể tiếp cận 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. Bằng 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 phải là được xuất thông qua foo_exported.h. (foo_private_t *) không rõ ràng, do đó các thay đổi được thực hiện cho foo_private_t được cho phép.)

Bạn có thể xem nội dung giải thích tương tự cho các loại có thể truy cập thông qua lớp cơ sở tham số mẫu và thông số kỹ thuật.

Đả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 Android.bp tệp 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 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 thư viện được phân loại là lỗi ABI:

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

* Cả hàm thành viên công khai và riêng tư đều phải không thể thay đổi hoặc xoá được vì các hàm cùng dòng công khai có thể tham chiếu đến hàm thành phần riêng tư. Tham chiếu biểu tượng đến các hàm thành phần riêng tư có thể được lưu trong tệp nhị phân của phương thức gọi. Thay đổi hoặc xoá các hàm thành viên riêng tư từ thư viện dùng chung có thể dẫn đến tệp nhị phân không tương thích ngược.

** Mức chênh lệch cho các thành viên có dữ liệu công khai hoặc riêng tư không được là vì các hàm cùng dòng có thể tham chiếu đến các thành phần dữ liệu này trong 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 tệp nhị phân không tương thích ngược.

*** Mặc dù các chế độ này không làm thay đổi bố cục bộ nhớ khác nhau về ngữ nghĩa có thể khiến thư viện không hoạt động như dự kiến.

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

Khi xây dựng một 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 xây dựng. Tham chiếu Tệp kết xuất ABI 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 theo dự đoán của libfoo được so sánh với tệp tham chiếu tại:

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

Lỗi hỏng ABI

Khi bị lỗi ABI, nhật ký bản dựng sẽ hiện 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ó thay đổi không tương thích, hệ thống xây dựng sẽ gửi 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 ----

Xây dựng quy trình kiểm tra ABI thư viện VNDK

Khi xây dựng thư viện VNDK:

  1. header-abi-dumper sẽ xử lý các tệp nguồn đã biên dịch thành tạo thư viện VNDK (tệp nguồn riêng của thư viện cũng như tệp nguồn kế thừa thông qua các phần phụ thuộc bắc cầu tĩnh), để tạo ra Các tệp .sdump tương ứng với mỗi nguồn.
    tạo hồ sơ
    Hình 1. Đang tạo .sdump tệp
  2. Sau đó, header-abi-linker sẽ xử lý .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 .so tương ứng với thư viện dùng chung) để tạo .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 tệp lsdump
    Hình 2. Đang tạo .lsdump tệp
  3. header-abi-diff so sánh .lsdump có tệp tham chiếu .lsdump để tạo báo cáo điểm khác biệt chỉ ra 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à tệp kết xuất ABI suy luận từ tệp nguồn đó thành tệp trung gian. Bản dựng hệ thống chạy header-abi-dumper trên tất cả các tệp nguồn được biên dịch trong khi tạo một thư viện bao gồm các tệp nguồn từ bắc cầu phần phụ thuộc.

Ngõ vào
  • Tệp nguồn C/C++
  • Đã xuất bao gồm các thư mục
  • 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 đang ở định dạng JSON và bạn không phải đảm bảo phiên bản ổn định trong các bản phát hành sau này. Do đó, .sdump định dạng tệp nên được coi là chi tiết triển khai hệ thống xây 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ể dùng header-abi-dumper để tạo một trung gian Tệp .sdump đại diện cho ABI mà tệp nguồn cung cấp 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 với cờ của trình biên dịch theo sau -- và phát đi thông tin ABI mà các tiêu đề công khai xuất trong Thư mục exported. Dưới đây là foo.sdump được tạo bởi header-abi-dumper:

{
 "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 mà tệp nguồn xuất ra foo.cpp và tiêu đề công khai, ví dụ:

  • record_types. Tham chiếu đến 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 có thông tin về các trường, kích thước, thông số truy cập, tệp tiêu đề mà thông số đó được xác định, và .
  • pointer_types. Tham khảo trực tiếp/gián tiếp các loại 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 bằng loại mà con trỏ trỏ đến (thông qua 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, loại C/C++ tích hợp sẵn, mảng và các kiểu tham chiếu lvalue và rvalue. Thông tin như vậy cho phép nhiễu xạ đệ 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 bớt của hàm, loại dữ liệu trả về, các loại tham số, thông số xác đị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 được tạo bởi header-abi-dumper làm đầ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 ánh xạ (không bắt buộc)
  • .so tệp của thư viện chia sẻ
  • Đã xuất bao gồm các thư mục
Đầ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 một định nghĩa (loại do người dùng xác định trong các các đơn vị bản dịch có cùng tên đủ điều kiện, có thể được về mặt ngữ nghĩa khác nhau) giữa các đơn vị bản dịch. Sau đó, công cụ này 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 biểu tượng đã xuất.

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

Ví dụ về kết quả 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 tới đó (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 được 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 2 tệp .lsdump đại diện cho ABI của hai thư viện và tạo một báo cáo điểm khác biệt nêu rõ sự khác biệt giữa 2 ABI.

Ngõ vào
  • Tệp .lsdump đại diện cho ABI của một tệp dùng chung cũ thư viện của bạn.
  • 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 điểm khác biệt nêu rõ sự khác biệt về ABI do 2 công cụ này cung cấp thư viện dùng chung.

Tệp điểm khác biệt về ABI nằm trong protobuf. Định dạng 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. Sau libfoo_new.so nữa, sau bar_t, bạn thay đổi loại mfoo từ foo_t đến foo_t *. Vì bar_t là một có thể truy cập được, thì loại có thể truy cập này phải được gắn cờ là thay đổi có thể gây lỗi ABI bằng cách 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ả lỗi ABI các thay đổi trong libfoo. Tin nhắn 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ả 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ể Foo là một hàm được xuất và nhận bar * làm tham số, trỏ đến bar, tức là đượ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, các tệp tham chiếu ABI phải được đăng ký trong ${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 tham chiếu, mọi thay đổi đối với mã nguồn dẫn đến việc thay đổi ABI/API không tương thích trong thư viện VNDK nay dẫn đến lỗi bản dựng.

Để cập nhật 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