ความเสถียรของ ABI

ความเสถียรของ Application Binary Interface (ABI) เป็นข้อกำหนดเบื้องต้นของการอัปเดตเฉพาะเฟรมเวิร์ก เนื่องจากโมดูลผู้ขายอาจขึ้นอยู่กับไลบรารีที่แชร์ของ Vendor Native Development Kit (VNDK) ที่อยู่ในพาร์ติชันระบบ ภายในรุ่น Android ไลบรารีที่ใช้ร่วมกัน VNDK ที่สร้างขึ้นใหม่จะต้องเข้ากันได้กับ ABI กับไลบรารีที่ใช้ร่วมกันของ VNDK ที่เผยแพร่ก่อนหน้านี้ ดังนั้นโมดูลผู้ขายจึงสามารถทำงานกับไลบรารีเหล่านั้นได้โดยไม่ต้องคอมไพล์ซ้ำและไม่มีข้อผิดพลาดรันไทม์ ระหว่างการเปิดตัว Android ไลบรารี VNDK สามารถเปลี่ยนแปลงได้และไม่มีการรับประกัน ABI

เพื่อช่วยให้แน่ใจว่า ABI เข้ากันได้ Android 9 มีตัวตรวจสอบ ABI ส่วนหัวตามที่อธิบายไว้ในส่วนต่อไปนี้

เกี่ยวกับการปฏิบัติตาม VNDK และ ABI

VNDK เป็นชุดของไลบรารีที่จำกัดซึ่งโมดูลผู้ขายอาจเชื่อมโยงและเปิดใช้งานการอัปเดตเฉพาะเฟรมเวิร์ก การ ปฏิบัติตาม ABI หมายถึงความสามารถของไลบรารีที่ใช้ร่วมกันเวอร์ชันใหม่กว่าในการทำงานตามที่คาดไว้กับโมดูลที่เชื่อมโยงกับไลบรารีแบบไดนามิก

เกี่ยวกับสัญลักษณ์ที่ส่งออก

สัญลักษณ์ที่ส่งออก (หรือเรียกอีกอย่างว่า สัญลักษณ์สากล ) หมายถึงสัญลักษณ์ที่ตรงตามเงื่อนไขต่อไปนี้ทั้งหมด:

  • ส่งออกโดย ส่วนหัวสาธารณะ ของไลบรารีที่ใช้ร่วมกัน
  • ปรากฏในตาราง .dynsym ของไฟล์ . .so ที่สอดคล้องกับไลบรารีที่ใช้ร่วมกัน
  • มีการผูกมัดที่อ่อนแอหรือเป็นสากล
  • การมองเห็นเป็นค่าเริ่มต้นหรือป้องกันไว้
  • ดัชนีส่วนไม่ได้กำหนด
  • ประเภทคือ FUNC หรือ OBJECT

ส่วนหัวสาธารณะ ของไลบรารีที่แบ่งใช้ถูกกำหนดให้เป็นส่วนหัวที่พร้อมใช้งานสำหรับไลบรารี/ไบนารีอื่นๆ ผ่าน export_include_dirs , export_header_lib_headers , export_static_lib_headers , export_shared_lib_headers และ export_generated_headers ในนิยาม Android.bp ของโมดูลที่สอดคล้องกับไลบรารีที่ใช้ร่วมกัน

เกี่ยวกับประเภทที่เข้าถึงได้

ชนิดที่ เข้าถึงได้คือชนิด C/C++ ที่มีอยู่ภายในหรือที่ผู้ใช้กำหนด ซึ่งสามารถเข้าถึงได้โดยตรงหรือโดยอ้อมผ่านสัญลักษณ์ที่ส่งออกและส่งออกผ่านส่วนหัวสาธารณะ ตัวอย่างเช่น libfoo.so มีฟังก์ชัน Foo ซึ่งเป็นสัญลักษณ์ส่งออกที่พบในตาราง . .dynsym ไลบรารี libfoo.so มีดังต่อไปนี้:

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 : [
    "include"
  ],
}
.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

ดูที่ Foo ประเภทที่เข้าถึงได้โดยตรง/โดยอ้อม ได้แก่:

พิมพ์ คำอธิบาย
bool ประเภทการส่งคืนของ Foo
int ประเภทของพารามิเตอร์ Foo แรก
bar_t * ประเภทของพารามิเตอร์ Foo ที่สอง โดยวิธีการของ bar_t * bar_t จะถูกส่งออกผ่าน foo_exported.h

bar_t มีสมาชิก mfoo ประเภท foo_t ซึ่งส่งออกผ่าน foo_exported.h ซึ่งส่งผลให้มีการส่งออกหลายประเภทมากขึ้น:
  • int : เป็นประเภท m1
  • int * : เป็นประเภทของ m2
  • foo_private_t * : เป็นประเภทของ mPfoo

อย่างไรก็ตาม foo_private_t ไม่สามารถเข้าถึงได้เนื่องจากไม่ได้ส่งออกผ่าน foo_exported.h ( foot_private_t * เป็นสีทึบ ดังนั้นการเปลี่ยนแปลงที่ทำกับ foo_private_t จะได้รับอนุญาต)

สามารถให้คำอธิบายที่คล้ายกันสำหรับประเภทที่เข้าถึงได้ผ่านตัวระบุคลาสพื้นฐานและพารามิเตอร์เทมเพลตเช่นกัน

สร้างความมั่นใจในการปฏิบัติตาม ABI

ต้องรับรองการปฏิบัติตาม ABI สำหรับไลบรารีที่ทำเครื่องหมาย vendor_available: true และ vndk.enabled: true ในไฟล์ Android.bp ที่เกี่ยวข้อง ตัวอย่างเช่น:

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

สำหรับชนิดข้อมูลที่สามารถเข้าถึงได้โดยตรงหรือโดยอ้อมโดยฟังก์ชันที่ส่งออก การเปลี่ยนแปลงต่อไปนี้ในไลบรารีถูกจัดประเภทเป็นการทำลาย ABI:

ประเภทข้อมูล คำอธิบาย
โครงสร้างและชั้นเรียน
  • เปลี่ยนขนาดของประเภทคลาสหรือประเภทโครงสร้าง
  • คลาสพื้นฐาน
    • เพิ่มหรือลบคลาสพื้นฐาน
    • เพิ่มหรือลบคลาสฐานที่สืบทอดมาเสมือน
    • เปลี่ยนลำดับของคลาสพื้นฐาน
  • ฟังก์ชั่นสมาชิก
    • ลบฟังก์ชันสมาชิก*
    • เพิ่มหรือลบอาร์กิวเมนต์จากฟังก์ชันสมาชิก
    • เปลี่ยนประเภทอาร์กิวเมนต์หรือชนิดส่งคืนของฟังก์ชันสมาชิก*
    • เปลี่ยนเค้าโครงตารางเสมือน
  • สมาชิกข้อมูล
    • ลบสมาชิกข้อมูลคงที่
    • เพิ่มหรือลบสมาชิกข้อมูลที่ไม่คงที่
    • เปลี่ยนประเภทของสมาชิกข้อมูล
    • เปลี่ยนการชดเชยเป็นสมาชิกข้อมูลที่ไม่คงที่**
    • เปลี่ยน const , volatile และ/หรือ restricted qualifiers ของสมาชิกข้อมูล***
    • ดาวน์เกรดตัวระบุการเข้าถึงของสมาชิกข้อมูล***
  • เปลี่ยนอาร์กิวเมนต์เทมเพลต
สหภาพแรงงาน
  • เพิ่มหรือลบสมาชิกข้อมูล
  • เปลี่ยนขนาดของประเภทสหภาพแรงงาน
  • เปลี่ยนประเภทของสมาชิกข้อมูล
  • เปลี่ยนลำดับของสมาชิกข้อมูล
การแจงนับ
  • เปลี่ยนประเภทพื้นฐาน
  • เปลี่ยนชื่อของผู้แจงนับ
  • เปลี่ยนค่าของการแจงนับ
สัญลักษณ์สากล
  • ลบสัญลักษณ์ที่ส่งออกโดยส่วนหัวสาธารณะ
  • สำหรับสัญลักษณ์สากลประเภท FUNC
    • เพิ่มหรือลบอาร์กิวเมนต์
    • เปลี่ยนประเภทอาร์กิวเมนต์
    • เปลี่ยนประเภทการส่งคืน
    • ดาวน์เกรดตัวระบุการเข้าถึง***
  • สำหรับสัญลักษณ์สากลประเภท OBJECT
    • เปลี่ยนประเภท C/C++ ที่สอดคล้องกัน
    • ดาวน์เกรดตัวระบุการเข้าถึง***

* ต้องไม่เปลี่ยนหรือลบฟังก์ชันทั้งแบบสาธารณะและส่วนตัวของสมาชิก เนื่องจากฟังก์ชันแบบอินไลน์สาธารณะสามารถอ้างถึงฟังก์ชันของสมาชิกส่วนตัวได้ การอ้างอิงสัญลักษณ์ไปยังฟังก์ชันสมาชิกส่วนตัวสามารถเก็บไว้ในระบบไบนารีของผู้โทรได้ การเปลี่ยนหรือลบฟังก์ชันสมาชิกไพรเวตจากไลบรารีที่แบ่งใช้อาจส่งผลให้ไบนารีเข้ากันไม่ได้แบบย้อนหลัง

** ต้องไม่เปลี่ยนแปลงการชดเชยให้กับสมาชิกข้อมูลสาธารณะหรือส่วนตัวเนื่องจากฟังก์ชันอินไลน์สามารถอ้างถึงสมาชิกข้อมูลเหล่านี้ในเนื้อหาฟังก์ชันได้ การเปลี่ยนค่าชดเชยสมาชิกข้อมูลอาจส่งผลให้ไบนารีเข้ากันไม่ได้แบบย้อนหลัง

*** แม้ว่าสิ่งเหล่านี้จะไม่เปลี่ยนเลย์เอาต์หน่วยความจำของประเภท แต่ก็มีความแตกต่างทางความหมายที่อาจทำให้ไลบรารีไม่ทำงานตามที่คาดไว้

การใช้เครื่องมือที่สอดคล้องกับ ABI

เมื่อมีการสร้างไลบรารี VNDK ABI ของไลบรารีจะถูกเปรียบเทียบกับการอ้างอิง ABI ที่สอดคล้องกันสำหรับเวอร์ชันของ VNDK ที่กำลังสร้าง การถ่ายโอนข้อมูล ABI อ้างอิงอยู่ใน:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/(v)ndk/<${PLATFORM_VNDK_VERSION}>/<BINDER_BITNESS>/<ARCH_ARCH-VARIANT>/source-based

ตัวอย่างเช่น ในการสร้าง libfoo สำหรับ API ระดับ 27 ของ VNDK นั้น ABI ที่อนุมานของ libfoo จะถูกนำไปเปรียบเทียบกับข้อมูลอ้างอิงที่:

${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/(v)ndk/27/64/<ARCH_ARCH-VARIANT>/source-based/libfoo.so.lsdump

ข้อผิดพลาดการแตกหักของ ABI

ในการแตกของ ABI บันทึกการสร้างจะแสดงคำเตือนด้วยประเภทคำเตือนและเส้นทางไปยังรายงาน abi-diff ตัวอย่างเช่น หาก ABI ของ libbinder มีการเปลี่ยนแปลงที่เข้ากันไม่ได้ ระบบบิลด์จะแสดงข้อผิดพลาดพร้อมข้อความที่คล้ายกับต่อไปนี้:

*****************************************************
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 ----

การสร้างห้องสมุด VNDK การตรวจสอบ ABI

เมื่อสร้างไลบรารี VNDK:

  1. header-abi-dumper ประมวลผลไฟล์ต้นฉบับที่คอมไพล์เพื่อสร้างไลบรารี VNDK (ไฟล์ต้นฉบับของไลบรารีเอง เช่นเดียวกับไฟล์ต้นฉบับที่สืบทอดผ่านการพึ่งพาสกรรมกริยาแบบคงที่) เพื่อสร้างไฟล์ .sdump ที่สอดคล้องกับแต่ละแหล่งที่มา
    sdump creation
    รูปที่ 1. การสร้างไฟล์ .sdump
  2. header-abi-linker ประมวลผลไฟล์ .sdump (โดยใช้สคริปต์เวอร์ชันที่มีให้หรือไฟล์ .so ที่สอดคล้องกับไลบรารีที่ใช้ร่วมกัน) เพื่อสร้างไฟล์ .lsdump ที่บันทึกข้อมูล ABI ทั้งหมดที่สอดคล้องกับไลบรารีที่ใช้ร่วมกัน
    lsdump creation
    รูปที่ 2. การสร้างไฟล์ .lsdump
  3. header-abi-diff เปรียบเทียบไฟล์ .lsdump กับไฟล์อ้างอิง .lsdump เพื่อสร้างรายงาน diff ที่สรุปความแตกต่างใน ABI ของทั้งสองไลบรารี
    abi diff creation
    รูปที่ 3 การสร้างรายงานส่วนต่าง

header-abi-dumper

เครื่องมือ header-abi-dumper แยกวิเคราะห์ไฟล์ต้นฉบับ C/C++ และดัมพ์ ABI ที่อนุมานจากไฟล์ต้นทางนั้นลงในไฟล์ระดับกลาง ระบบบิลด์รัน header-abi-dumper บนไฟล์ต้นฉบับที่คอมไพล์แล้วทั้งหมด ในขณะที่สร้างไลบรารีที่รวมไฟล์ต้นฉบับจากการพึ่งพาสกรรมกริยา

ปัจจุบันไฟล์ .sdump มีรูปแบบเป็น Protobuf TextFormatted ซึ่งไม่รับประกันว่าจะมีเสถียรภาพในรุ่นต่อๆ ไป ดังนั้น การจัดรูปแบบไฟล์ .sdump จึงควรถือเป็นรายละเอียดการใช้งานระบบบิลด์

ตัวอย่างเช่น libfoo.so มีไฟล์ต้นฉบับ 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;
}

คุณสามารถใช้ header-abi-dumper เพื่อสร้างไฟล์ .sdump ระดับกลางที่แสดงถึง ABI ที่นำเสนอโดยไฟล์ต้นฉบับโดยใช้:

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

คำสั่งนี้บอกให้ header-abi-dumper แยกวิเคราะห์ foo.cpp และส่งข้อมูล ABI ที่เปิดเผยในส่วนหัวสาธารณะในไดเร็กทอรีที่ exported นี่เป็นข้อความที่ตัดตอนมา (ไม่ใช่การแสดงทั้งหมด) จาก foo.sdump ที่สร้างโดย header-abi-dumper :

record_types {
  type_info {
    name: "foo"
    size: 12
    alignment: 4
    referenced_type: "type-1"
    source_file: "foo/include/foo_exported.h"
    linker_set_key: "foo"
    self_type: "type-1"
  }
  fields {
    referenced_type: "type-2"
    field_offset: 0
    field_name: "m1"
    access: public_access
  }
  fields {
    referenced_type: "type-3"
    field_offset: 32
    field_name: "m2"
    access: public_access
  }
  fields {
    referenced_type: "type-5"
    field_offset: 64
    field_name: "mPfoo"
    access: public_access
  }
  access: public_access
  record_kind: struct_kind
  tag_info {
    unique_id: "_ZTS3foo"
  }
}
record_types {
  type_info {
    name: "bar"
    size: 12
    alignment: 4
    referenced_type: "type-6"
…
pointer_types {
  type_info {
    name: "bar *"
    size: 4
    alignment: 4
    referenced_type: "type-6"
    source_file: "foo/include/foo_exported.h"
    linker_set_key: "bar *"
    self_type: "type-8"
  }
}
builtin_types {
  type_info {
    name: "int"
    size: 4
    alignment: 4
    referenced_type: "type-2"
    source_file: ""
    linker_set_key: "int"
    self_type: "type-2"
  }
  is_unsigned: false
  is_integral: true
}
functions {
  return_type: "type-7"
  function_name: "Foo"
  source_file: "foo/include/foo_exported.h"
  parameters {
    referenced_type: "type-2"
    default_arg: false
  }
  parameters {
    referenced_type: "type-8"
    default_arg: false
  }
  linker_set_key: "_Z3FooiP3bar"
  access: public_access
}

foo.sdump มีข้อมูล ABI ที่เปิดเผยโดยไฟล์ต้นฉบับ foo.cpp เช่น:

  • บันทึก record_types อ้างถึงโครงสร้าง สหภาพแรงงาน หรือชั้นเรียนที่เปิดเผยโดยส่วนหัวสาธารณะ เร็กคอร์ดแต่ละประเภทมีข้อมูลเกี่ยวกับฟิลด์ ขนาด ตัวระบุการเข้าถึง ไฟล์ส่วนหัวที่เปิดเผย ฯลฯ
  • pointer_types อ้างถึงประเภทพอยน์เตอร์ที่อ้างอิงโดยตรง/โดยอ้อมโดยเร็กคอร์ด/ฟังก์ชันที่เปิดเผยโดยส่วนหัวสาธารณะ พร้อมกับประเภทที่ตัวชี้ชี้ไป (ผ่านฟิลด์ referenced_type ใน type_info ) ข้อมูลที่คล้ายกันถูกบันทึกไว้ในไฟล์ .sdump สำหรับประเภทที่ผ่านการรับรอง ประเภท C/C++ ในตัว ประเภทอาร์เรย์ และประเภทการอ้างอิง lvalue และ rvalue (ข้อมูลการบันทึกเกี่ยวกับประเภทดังกล่าวอนุญาตให้มี diffing แบบเรียกซ้ำ)
  • functions . แสดงถึงฟังก์ชันที่เปิดเผยโดยส่วนหัวสาธารณะ พวกเขายังมีข้อมูลเกี่ยวกับชื่อ mangled ของฟังก์ชัน ประเภทการส่งคืน ประเภทของพารามิเตอร์ ตัวระบุการเข้าถึง ฯลฯ

header-abi-linker

เครื่องมือ header-abi-linker ใช้ไฟล์ระดับกลางที่สร้างโดย header-abi-dumper เป็นอินพุต จากนั้นลิงก์ไฟล์เหล่านั้น:

อินพุต
  • ไฟล์ระดับกลางที่สร้างโดย header-abi-dumper
  • สคริปต์เวอร์ชัน/ไฟล์แผนที่ (ไม่บังคับ)
  • .so ไฟล์ของไลบรารีที่ใช้ร่วมกัน
เอาท์พุต ไฟล์ที่บันทึก ABI ของไลบรารีที่ใช้ร่วมกัน (เช่น libfoo.so.lsdump แสดงถึง ABI ของ libfoo )

เครื่องมือนี้จะรวมกราฟประเภทในไฟล์ระดับกลางทั้งหมดที่มีให้ โดยคำนึงถึงความแตกต่างระหว่างหน่วยการแปลที่มีคำจำกัดความเดียว (ประเภทที่กำหนดโดยผู้ใช้ในหน่วยการแปลต่างๆ ที่มีชื่อเต็มเหมือนกัน อาจมีความหมายต่างกัน) ในแต่ละหน่วยการแปล จากนั้นเครื่องมือจะแยกวิเคราะห์สคริปต์เวอร์ชันหรือตาราง .dynsym ของไลบรารีที่ใช้ร่วมกัน (ไฟล์ . .so ) เพื่อสร้างรายการสัญลักษณ์ที่เอ็กซ์พอร์ต

ตัวอย่างเช่น เมื่อ libfoo เพิ่มไฟล์ bar.cpp (ซึ่งแสดง bar ฟังก์ชัน C) ในการคอมไพล์ สามารถเรียกใช้ header-abi-linker เพื่อสร้าง ABI dump ที่ลิงก์โดยสมบูรณ์ของ libfoo ได้ดังนี้:

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

ตัวอย่างเอาต์พุตคำสั่งใน libfoo.so.lsdump :

record_types {
  type_info {
    name: "foo"
    size: 24
    alignment: 8
    referenced_type: "type-1"
    source_file: "foo/include/foo_exported.h"
    linker_set_key: "foo"
    self_type: "type-1"
  }
  fields {
    referenced_type: "type-2"
    field_offset: 0
    field_name: "m1"
    access: public_access
  }
  fields {
    referenced_type: "type-3"
    field_offset: 64
    field_name: "m2"
    access: public_access
  }
  fields {
    referenced_type: "type-4"
    field_offset: 128
    field_name: "mPfoo"
    access: public_access
  }
  access: public_access
  record_kind: struct_kind
  tag_info {
    unique_id: "_ZTS3foo"
  }
}
record_types {
  type_info {
    name: "bar"
    size: 24
    alignment: 8
...
builtin_types {
  type_info {
    name: "void"
    size: 0
    alignment: 0
    referenced_type: "type-6"
    source_file: ""
    linker_set_key: "void"
    self_type: "type-6"
  }
  is_unsigned: false
  is_integral: false
}
functions {
  return_type: "type-19"
  function_name: "Foo"
  source_file: "foo/include/foo_exported.h"
  parameters {
    referenced_type: "type-2"
    default_arg: false
  }
  parameters {
    referenced_type: "type-20"
    default_arg: false
  }
  linker_set_key: "_Z3FooiP3bar"
  access: public_access
}
functions {
  return_type: "type-6"
  function_name: "FooBad"
  source_file: "foo/include/foo_exported_bad.h"
  parameters {
    referenced_type: "type-2"
    default_arg: false
  }
parameters {
    referenced_type: "type-7"
    default_arg: false
  }
  linker_set_key: "_Z6FooBadiP3foo"
  access: public_access
}
elf_functions {
  name: "_Z3FooiP3bar"
}
elf_functions {
  name: "_Z6FooBadiP3foo"
}

เครื่องมือ header-abi-linker :

  • ลิงก์ไฟล์ .sdump ที่มีให้ ( foo.sdump และ bar.sdump ) กรองข้อมูล ABI ที่ไม่มีอยู่ในส่วนหัวที่อยู่ในไดเร็กทอรี: exported
  • แยกวิเคราะห์ libfoo.so และรวบรวมข้อมูลเกี่ยวกับสัญลักษณ์ที่ส่งออกโดยไลบรารีผ่านตาราง . .dynsym
  • เพิ่ม _Z3FooiP3bar และ Bar

libfoo.so.lsdump เป็นการถ่ายโอนข้อมูล ABI ขั้นสุดท้ายของ libfoo.so

header-abi-diff

เครื่องมือ header-abi-diff เปรียบเทียบไฟล์ .lsdump สองไฟล์ที่แสดงถึง ABI ของสองไลบรารีและสร้างรายงาน diff ที่ระบุความแตกต่างระหว่าง ABI ทั้งสอง

อินพุต
  • ไฟล์ .lsdump ที่แสดงถึง ABI ของไลบรารีที่ใช้ร่วมกันแบบเก่า
  • ไฟล์ .lsdump ที่แสดงถึง ABI ของไลบรารีที่ใช้ร่วมกันใหม่
เอาท์พุต รายงานความแตกต่างที่ระบุความแตกต่างใน ABI ที่เสนอโดยไลบรารีที่แบ่งใช้สองแห่งเมื่อเปรียบเทียบ

ไฟล์ diff ของ ABI ได้รับการออกแบบมาให้ละเอียดและอ่านง่ายที่สุด รูปแบบอาจมีการเปลี่ยนแปลงในรุ่นต่อๆ ไป ตัวอย่างเช่น คุณมี libfoo สองเวอร์ชัน: libfoo_old.so และ libfoo_new.so ใน libfoo_new.so ใน bar_t คุณเปลี่ยนประเภทของ mfoo จาก foo_t เป็น foo_t * เนื่องจาก bar_t เป็นประเภทที่เข้าถึงได้โดยตรง จึงควรติดธงว่าเป็นการเปลี่ยนแปลงการทำลาย ABI โดย header-abi-diff

ในการเรียกใช้ header-abi-diff :

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

ตัวอย่างเอาต์พุตคำสั่งใน 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 มีรายงานการเปลี่ยนแปลงการละเมิด ABI ทั้งหมดใน libfoo ข้อความ record_type_diffs ระบุว่าเร็กคอร์ดมีการเปลี่ยนแปลงและแสดงรายการการเปลี่ยนแปลงที่เข้ากันไม่ได้ ซึ่งรวมถึง:

  • ขนาดของเร็กคอร์ดเปลี่ยนจาก 24 ไบต์เป็น 8 ไบต์
  • ประเภทฟิลด์ของ mfoo เปลี่ยนจาก foo เป็น foo * (typedefs ทั้งหมดถูกถอดออก)

ฟิลด์ type_stack ระบุว่า header-abi-diff ถึงประเภทที่เปลี่ยนแปลงอย่างไร ( bar ) ฟิลด์นี้อาจตีความได้ว่า Foo เป็นฟังก์ชันที่ส่งออกซึ่งรับ bar * เป็นพารามิเตอร์ ซึ่งชี้ไปที่ bar ซึ่งส่งออกและเปลี่ยนแปลงแล้ว

การบังคับใช้ ABI/API

ในการบังคับใช้ ABI/API ของไลบรารีที่ใช้ร่วมกันของ VNDK และ LLNDK จะต้องตรวจสอบการอ้างอิง ABI ใน ${ANDROID_BUILD_TOP}/prebuilts/abi-dumps/(v)ndk/ ในการสร้างข้อมูลอ้างอิงเหล่านี้ ให้รันคำสั่งต่อไปนี้:

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

หลังจากสร้างข้อมูลอ้างอิง การเปลี่ยนแปลงใดๆ ที่ทำกับซอร์สโค้ดที่ส่งผลให้เกิดการเปลี่ยนแปลง ABI/API ที่เข้ากันไม่ได้ในไลบรารี VNDK หรือ LLNDK จะส่งผลให้เกิดข้อผิดพลาดในการสร้าง

ในการอัพเดตการอ้างอิง ABI สำหรับไลบรารีหลักของ VNDK ให้รันคำสั่งต่อไปนี้:

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

ตัวอย่างเช่น ในการอัปเดตการอ้างอิง libbinder ABI ให้เรียกใช้:

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

เมื่อต้องการอัพเดตการอ้างอิง ABI สำหรับไลบรารี LLNDK เฉพาะ ให้รันคำสั่งต่อไปนี้:

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

ตัวอย่างเช่น ในการอัพเดตการอ้างอิง libm ABI ให้รัน:

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