บังคับใช้อินเทอร์เฟซการแบ่งส่วนผลิตภัณฑ์

Android 11 เลิกรวมพาร์ติชัน product ซึ่งทำให้ โดยไม่ขึ้นอยู่กับพาร์ติชัน system และ vendor ส่วนหนึ่งของการเปลี่ยนแปลงเหล่านี้ ตอนนี้คุณควบคุมการเข้าถึงของพาร์ติชัน product สำหรับเนทีฟและ Java ได้แล้ว อินเทอร์เฟซ (ซึ่งคล้ายกับวิธีบังคับใช้อินเทอร์เฟซสำหรับ vendor) พาร์ติชัน)

บังคับใช้อินเทอร์เฟซที่มาพร้อมเครื่อง

หากต้องการเปิดใช้การบังคับใช้อินเทอร์เฟซแบบเนทีฟ ให้ตั้งค่า PRODUCT_PRODUCT_VNDK_VERSIONเป็น current (ระบบจะตั้งค่าเวอร์ชันเป็น current โดยอัตโนมัติเมื่อระดับ Shipping API สำหรับเป้าหมายมากกว่า 29) การบังคับใช้ทำให้

  • โมดูลเนทีฟในพาร์ติชัน product ที่จะลิงก์:
    • แบบคงที่หรือแบบไดนามิกกับโมดูลอื่นๆ ในพาร์ติชัน product ซึ่งรวมถึงไลบรารีแบบคงที่ ที่ใช้ร่วมกัน หรือส่วนหัว
    • แบบไดนามิกไปยังไลบรารี VNDK ในพาร์ติชัน system
  • ไลบรารี JNI ใน APK ที่ไม่ได้รวมกลุ่มในพาร์ติชัน product ที่จะลิงก์ ไลบรารีใน /product/lib หรือ /product/lib64 (นอกเหนือจาก คลัง NDK)

การบังคับใช้ไม่อนุญาตให้ลิงก์อื่นๆ ไปยังพาร์ติชันอื่นที่ไม่ใช่ product พาร์ติชัน

การบังคับใช้เวลาสร้าง (Android.bp)

ใน Android 11 โมดูลของระบบสามารถสร้างตัวแปรรูปภาพของผลิตภัณฑ์ได้นอกเหนือจากตัวแปรรูปภาพหลักและตัวแปรรูปภาพจากผู้ให้บริการ เมื่อใช้เนทีฟ เปิดใช้การบังคับใช้อินเทอร์เฟซอยู่ (ตั้งค่า PRODUCT_PRODUCT_VNDK_VERSION เป็น current):

  • โมดูลเนทีฟในการแบ่งพาร์ติชัน product จะอยู่ในผลิตภัณฑ์ย่อยแทนผลิตภัณฑ์หลัก

  • โมดูลที่มี product_available: true ในไฟล์ Android.bp ของตน ใช้ได้กับผลิตภัณฑ์ย่อย

  • ไลบรารีหรือไบนารีที่ระบุว่า product_specific: true ลิงก์กับผลการค้นหาอื่นได้ ไลบรารีที่ระบุ product_specific: true หรือ product_available: true ในไฟล์ Android.bp

  • ไลบรารี VNDK ต้องมี product_available: true ในไฟล์ Android.bp เพื่อให้ไบนารี product ลิงก์กับคลัง VNDK ได้

ตารางต่อไปนี้สรุปพร็อพเพอร์ตี้ Android.bp ที่ใช้สร้างตัวแปรรูปภาพ

คุณสมบัติใน Android.bp ผลิตภัณฑ์ย่อยที่สร้างแล้ว
ก่อนการบังคับใช้ หลังบังคับใช้
ค่าเริ่มต้น (ไม่มี) core
(รวม /system, /system_ext และ /product)
แกนกลางร่างกาย
(รวม /system และ /system_ext แต่ไม่รวม /product)
system_ext_specific: true แกนกลาง แกนกลาง
product_specific: true แกนกลาง ผลิตภัณฑ์
vendor: true ผู้จำหน่าย ผู้จำหน่าย
vendor_available: true แกนกลางร่างกาย ผู้ให้บริการ หลัก, ผู้ให้บริการ
product_available: true ไม่มี core, product
vendor_available: true และ product_available: true ไม่มี หลัก, ผลิตภัณฑ์, ผู้ให้บริการ
system_ext_specific: true และ vendor_available: true หลัก, ผู้ให้บริการ หลัก, ผู้ให้บริการ
product_specific: true และ vendor_available: true หลัก, ผู้ให้บริการ ผลิตภัณฑ์, ผู้ให้บริการ

การบังคับใช้เวลาบิลด์ (Android.mk)

เมื่อเปิดใช้การบังคับใช้อินเทอร์เฟซแบบเนทีฟ จะมีการติดตั้งโมดูลเนทีฟลงใน พาร์ติชัน product มีลิงก์ประเภท native:product ที่ลิงก์ได้เพียงอย่างเดียว โมดูล native:product หรือ native:vndk อื่นๆ การพยายามลิงก์กับโมดูลอื่นนอกเหนือจากนี้จะทำให้ระบบบิลด์สร้างข้อผิดพลาดในการตรวจสอบประเภทลิงก์

การบังคับใช้รันไทม์

เมื่อเปิดใช้การบังคับใช้อินเทอร์เฟซแบบเนทีฟ การกําหนดค่า linker สําหรับ Bionic linker จะไม่อนุญาตให้กระบวนการของระบบใช้ไลบรารี product โดยสร้างส่วน product สําหรับกระบวนการ product ที่ลิงก์กับไลบรารีนอกพาร์ติชัน product ไม่ได้ (แต่กระบวนการดังกล่าวจะลิงก์กับไลบรารี VNDK ได้) การพยายามละเมิดการกำหนดค่าลิงก์รันไทม์จะทำให้กระบวนการล้มเหลวและสร้างข้อความแสดงข้อผิดพลาด CANNOT LINK EXECUTABLE

บังคับใช้อินเทอร์เฟซ Java

หากต้องการเปิดใช้การบังคับใช้อินเทอร์เฟซ Java ให้ตั้งค่า PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE ไปยัง true (ค่าคือ ตั้งค่าเป็น true โดยอัตโนมัติเมื่อระดับ API การจัดส่งสำหรับเป้าหมายคือ มากกว่า 29) เมื่อเปิดใช้ การบังคับใช้จะอนุญาตหรือไม่อนุญาตให้เข้าถึงข้อมูลต่อไปนี้

API /system /system_ext /product /vendor /data
Public API
@ระบบ API
API @ซ่อน

เช่นเดียวกับในพาร์ติชัน vendor แอปหรือไลบรารี Java ในพาร์ติชัน product จะได้รับอนุญาตให้ใช้เฉพาะ API สาธารณะและ API ของระบบเท่านั้น โดยไม่อนุญาตให้ลิงก์กับไลบรารีที่ใช้ API ที่ซ่อนอยู่ ข้อจำกัดนี้รวมถึงการลิงก์เมื่อสร้างและการแสดงผลในรันไทม์

การบังคับใช้เวลาในการสร้าง

ขณะสร้าง Make และ Soong จะยืนยันว่าโมดูล Java ในพาร์ติชัน product ไม่ได้ใช้ API ที่ซ่อนอยู่โดยตรวจสอบช่อง platform_apis และ sdk_version sdk_version ของแอปในพาร์ติชัน product ต้อง จะเติมด้วย current, system_current หรือเวอร์ชันตัวเลขของ API และ ฟิลด์ platform_apis ต้องว่างเปล่า

การบังคับใช้รันไทม์

รันไทม์ของ Android จะตรวจสอบว่าแอปในพาร์ติชัน product ไม่ได้ใช้ API ที่ซ่อนอยู่ รวมถึงการสะท้อน โปรดดูรายละเอียดที่ข้อจำกัดเกี่ยวกับอินเทอร์เฟซที่ไม่ใช่ SDK

เปิดใช้การบังคับใช้อินเทอร์เฟซผลิตภัณฑ์

ใช้ขั้นตอนในส่วนนี้เพื่อเปิดใช้การบังคับใช้อินเทอร์เฟซผลิตภัณฑ์

ขั้นตอน งาน ต้องระบุ
1 กำหนดไฟล์ Make ของระบบของคุณเองซึ่งระบุแพ็กเกจสำหรับพาร์ติชัน system จากนั้นตั้งค่าการตรวจสอบข้อกำหนดของเส้นทางอาร์ติแฟกต์ใน device.mk (เพื่อป้องกันไม่ให้ติดตั้งโมดูลที่ไม่ใช่ระบบลงในพาร์ติชัน system) ไม่ใช่
2 ล้างรายการที่อนุญาต ไม่ใช่
3 บังคับใช้อินเทอร์เฟซแบบเนทีฟและระบุลิงก์รันไทม์ที่ไม่สำเร็จ (สามารถทํางานควบคู่กับการบังคับใช้ Java ได้) Y
4 บังคับใช้อินเทอร์เฟซ Java และตรวจสอบลักษณะรันไทม์ (เรียกใช้ได้พร้อมกัน ด้วยการบังคับใช้แบบเนทีฟ) Y
5 ตรวจสอบลักษณะการทํางานของรันไทม์ Y
6 อัปเดต device.mk ให้มีการบังคับใช้อินเทอร์เฟซผลิตภัณฑ์ Y

ขั้นตอนที่ 1: สร้างไฟล์ Make และเปิดใช้การตรวจสอบเส้นทางอาร์ติแฟกต์

ในขั้นตอนนี้ คุณจะต้องกำหนด system makefile

  1. สร้าง โปรดตรวจสอบว่าแพ็กเกจสำหรับพาร์ติชัน system สำหรับ เช่น ให้สร้างไฟล์ oem_system.mk โดยใช้คำสั่งต่อไปนี้

    $(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system.mk)
    $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system.mk)
    
    # Applications
    PRODUCT_PACKAGES += \
        CommonSystemApp1 \
        CommonSystemApp2 \
        CommonSystemApp3 \
    
    # Binaries
    PRODUCT_PACKAGES += \
        CommonSystemBin1 \
        CommonSystemBin2 \
        CommonSystemBin3 \
    
    # Libraries
    PRODUCT_PACKAGES += \
        CommonSystemLib1 \
        CommonSystemLib2 \
        CommonSystemLib3 \
    
    PRODUCT_SYSTEM_NAME := oem_system
    PRODUCT_SYSTEM_BRAND := Android
    PRODUCT_SYSTEM_MANUFACTURER := Android
    PRODUCT_SYSTEM_MODEL := oem_system
    PRODUCT_SYSTEM_DEVICE := generic
    
    # For system-as-root devices, system.img should be mounted at /, so we
    # include ROOT here.
    _my_paths := \
     $(TARGET_COPY_OUT_ROOT)/ \
     $(TARGET_COPY_OUT_SYSTEM)/ \
    
    $(call require-artifacts-in-path, $(_my_paths),)
    
  2. ในไฟล์ device.mk ให้รับค่ามาจากการแมปไฟล์ทั่วไปสำหรับพาร์ติชัน system และเปิดใช้การตรวจสอบข้อกำหนดของเส้นทางอาร์ติแฟกต์ เช่น

    $(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk)
    
    # Enable artifact path requirements checking
    PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
    

เกี่ยวกับข้อกำหนดของเส้นทางอาร์ติแฟกต์

เมื่อตั้งค่า PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS เป็น true หรือ strict ระบบบิลด์จะป้องกันไม่ให้ติดตั้งแพ็กเกจที่กำหนดไว้ในไฟล์เครื่องสำอางอื่นๆ ลงใน เส้นทางที่กำหนดไว้ใน require-artifacts-in-path และ ป้องกันแพ็กเกจ ที่กำหนดไว้ในไฟล์สร้างปัจจุบันจากการติดตั้งอาร์ติแฟกต์นอกเส้นทาง กำหนดไว้ใน require-artifacts-in-path

ในตัวอย่างด้านบน โดยมีการตั้งค่า PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS เป็น strict ทำให้ไฟล์นอก oem_system.mk ไม่สามารถรวมโมดูลที่ติดตั้ง พาร์ติชัน root หรือ system หากต้องการรวมโมดูลเหล่านี้ คุณต้องกำหนดไว้ในไฟล์ oem_system.mk เองหรือในไฟล์ make ที่รวมไว้ การพยายามติดตั้งโมดูลไปยังเส้นทางที่ไม่อนุญาตจะทำให้บิลด์หยุดทำงาน หากต้องการแก้ไขการหยุดพัก ให้ทําอย่างใดอย่างหนึ่งต่อไปนี้

  • ตัวเลือกที่ 1: ใส่โมดูลระบบในไฟล์ยี่ห้อที่รวมไว้ใน oem_system.mk ซึ่งทำให้ระบบเป็นไปตามข้อกำหนดเส้นทางอาร์ติแฟกต์ (เนื่องจากพร็อพเพอร์ตี้ ขณะนี้มีโมดูลอยู่ในไฟล์ประเภทที่รวมไว้) จึงอนุญาตให้ติดตั้ง ชุดของเส้นทางใน "require-artifacts-in-path

  • ตัวเลือกที่ 2: ติดตั้งโมดูลลงในพาร์ติชัน system_ext หรือ product (และอย่าติดตั้งโมดูลลงในพาร์ติชัน system)

  • ตัวเลือกที่ 3: เพิ่มโมดูลลงในPRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST รายการนี้แสดงโมดูลที่อนุญาตให้ติดตั้ง

ขั้นตอนที่ 2: ล้างรายการที่อนุญาต

ในขั้นตอนนี้ คุณจะทําให้ PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST ว่างเพื่อให้อุปกรณ์ทั้งหมดที่แชร์ oem_system.mk สามารถแชร์system รูปภาพเดียวได้ด้วย หากต้องการทำให้รายการที่อนุญาตว่างเปล่า ให้ย้ายโมดูลในรายการไปยัง system_ext หรือ product แบ่งพาร์ติชันหรือเพิ่มใน system สร้างไฟล์ ช่วงเวลานี้ ไม่จำเป็นต้องระบุขั้นตอน เนื่องจากไม่จำเป็นต้องกำหนดรูปภาพ system ทั่วไปเพื่อ เปิดใช้การบังคับใช้อินเทอร์เฟซผลิตภัณฑ์ อย่างไรก็ตาม การล้างรายการที่อนุญาตจะมีประโยชน์ในการกําหนดขอบเขต system ด้วย system_ext

ขั้นตอนที่ 3: บังคับใช้อินเทอร์เฟซเนทีฟ

ในขั้นตอนนี้ คุณจะตั้งค่า PRODUCT_PRODUCT_VNDK_VERSION := current จากนั้นมองหาข้อผิดพลาดเกี่ยวกับบิลด์และรันไทม์ แล้วแก้ไขข้อผิดพลาดเหล่านั้น วิธีตรวจสอบการเปิดเครื่องและบันทึกของอุปกรณ์ และค้นหาและแก้ไขความล้มเหลวของลิงก์รันไทม์

  1. ตั้งค่าPRODUCT_PRODUCT_VNDK_VERSION := current

  2. สร้างอุปกรณ์และมองหาข้อผิดพลาดในการสร้าง คุณน่าจะได้เห็นงานสร้าง 2-3 รายการ ระบบจะหยุดพักในกรณีที่ไม่มีผลิตภัณฑ์ย่อยหรือผลิตภัณฑ์ย่อยหลัก ช่วงพักที่พบบ่อย รวมข้อมูลต่อไปนี้

    • โมดูล hidl_interface ที่มี product_specific: true จะไม่พร้อมใช้งานสำหรับโมดูลระบบ วิธีแก้ไขคือแทนที่ product_specific: true ด้วย system_ext_specific: true
    • โมดูลอาจไม่มีผลิตภัณฑ์ย่อยที่จําเป็นสําหรับโมดูลผลิตภัณฑ์ วิธีแก้ไขคือทำให้โมดูลนั้นพร้อมใช้งานสำหรับพาร์ติชัน product โดยการตั้งค่า product_available: true หรือย้ายโมดูลไปยังพาร์ติชัน product โดยการตั้งค่า product_specific: true
  3. แก้ไขข้อผิดพลาดในการสร้างและตรวจสอบว่าอุปกรณ์สร้างสำเร็จ

  4. แฟลชอิมเมจและมองหาข้อผิดพลาดเกี่ยวกับรันไทม์ในการเปิดเครื่องและบันทึกของอุปกรณ์

    • หากแท็ก linker จากบันทึกเคสทดสอบแสดงข้อความ CANNOT LINK EXECUTABLE แสดงว่าไฟล์ make ไม่มีไฟล์ที่ต้องพึ่งพา (และไม่ได้บันทึกไว้เมื่อสร้าง)
    • ในการตรวจสอบจากระบบบิลด์ ให้เพิ่มไลบรารีที่จำเป็นลงใน shared_libs: หรือ required:
  5. แก้ไขการพึ่งพาที่ขาดหายไปโดยใช้คําแนะนําที่ระบุไว้ด้านบน

ขั้นตอนที่ 4: บังคับใช้อินเทอร์เฟซ Java

ในขั้นตอนนี้ คุณจะตั้งค่า PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true จากนั้นค้นหาและแก้ไขข้อผิดพลาดของบิลด์ที่เกิดขึ้น มองหาข้อผิดพลาด 2 ประเภทต่อไปนี้

  • ข้อผิดพลาดของประเภทลิงก์ ข้อผิดพลาดนี้บ่งบอกว่าแอปลิงก์กับโมดูล Java ที่มี sdk_version กว้างกว่า หากต้องการแก้ไข ให้ขยายsdk_versionของแอปหรือจำกัดsdk_versionของคลัง ตัวอย่างข้อผิดพลาด

    error: frameworks/base/packages/SystemUI/Android.bp:138:1: module "SystemUI" variant "android_common": compiles against system API, but dependency "telephony-common" is compiling against private API.Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.
    
  • ข้อผิดพลาดเกี่ยวกับสัญลักษณ์ ข้อผิดพลาดนี้บ่งบอกว่าไม่พบสัญลักษณ์เนื่องจากอยู่ใน API ที่ซ่อนอยู่ หากต้องการแก้ไข ให้ใช้ API ที่มองเห็นได้ (ไม่ใช่แบบซ่อนอยู่) หรือหาวิธีอื่น ตัวอย่างข้อผิดพลาด

    frameworks/opt/net/voip/src/java/com/android/server/sip/SipSessionGroup.java:1051: error: cannot find symbol
                ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader(
                                               ^
      symbol:   class ProxyAuthenticate
      location: class SipSessionGroup.SipSessionImpl
    

ขั้นตอนที่ 5: ตรวจสอบลักษณะการทำงานของรันไทม์

ในขั้นตอนนี้ คุณจะตรวจสอบว่าลักษณะการทํางานของรันไทม์เป็นไปตามที่คาดไว้ สําหรับแอปที่แก้ไขข้อบกพร่องได้ คุณสามารถตรวจสอบการใช้ API ที่ซ่อนอยู่ได้โดยบันทึกโดยใช้ StrictMode.detectNonSdkApiUsage (ซึ่งจะสร้างบันทึกเมื่อแอปใช้ API ที่ซ่อนอยู่) อีกวิธีหนึ่งคือ veridex เครื่องมือวิเคราะห์แบบคงที่เพื่อดูประเภทการใช้งาน (การลิงก์หรือการทบทวน) ระดับการจำกัด และสแต็กการเรียกใช้

  • ไวยากรณ์ Veridex:

    ./art/tools/veridex/appcompat.sh --dex-file={apk file}
  • ตัวอย่างผลลัพธ์จาก Veridex

    #1: Linking greylist-max-o Landroid/animation/AnimationHandler;-><init>()V use(s):
           Lcom/android/systemui/pip/phone/PipMotionHelper;-><init>(Landroid/content/Context;Landroid/app/IActivityManager;Landroid/app/IActivityTaskManager;Lcom/android/systemui/pip/phone/PipMenuActivityController;Lcom/android/internal/policy/PipSnapAlgorithm;Lcom/android/systemui/statusbar/FlingAnimationUtils;)V
    
    #1332: Reflection greylist Landroid/app/Activity;->mMainThread use(s):
           Landroidx/core/app/ActivityRecreator;->getMainThreadField()Ljava/lang/reflect/Field;
    

โปรดดูรายละเอียดเกี่ยวกับการใช้ Veridex ที่หัวข้อทดสอบโดยใช้เครื่องมือ Veridex

ขั้นตอนที่ 6: อัปเดต device.mk

หลังจากแก้ไขข้อผิดพลาดทั้งหมดเกี่ยวกับบิลด์และรันไทม์ และยืนยันว่าลักษณะการทํางานของรันไทม์เป็นไปตามที่คาดไว้แล้ว ให้ตั้งค่าต่อไปนี้ใน device.mk

  • PRODUCT_PRODUCT_VNDK_VERSION := current
  • PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true