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

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

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

หากต้องการเปิดใช้การบังคับใช้อินเทอร์เฟซเนทีฟ ให้ตั้งค่า PRODUCT_PRODUCT_VNDK_VERSION ไปยัง current (ระบบจะตั้งค่าเวอร์ชันเป็น current โดยอัตโนมัติเมื่อจัดส่ง ระดับ 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 สร้างตัวแปรแล้ว
ก่อนบังคับใช้ หลังบังคับใช้
ค่าเริ่มต้น (ไม่มี) แกนกลางร่างกาย
(รวม /system, /system_ext และ /product)
แกนกลางร่างกาย
(รวม /system และ /system_ext แต่ไม่รวม /product)
system_ext_specific: true แกนกลางร่างกาย แกนกลางร่างกาย
product_specific: true แกนกลางร่างกาย ผลิตภัณฑ์
vendor: true ผู้จำหน่าย ผู้จำหน่าย
vendor_available: true หลัก, ผู้ให้บริการ หลัก, ผู้ให้บริการ
product_available: true ไม่มี แกน, ผลิตภัณฑ์
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) เมื่อเปิดใช้ การบังคับใช้จะอนุญาตหรือไม่อนุญาตสิ่งต่อไปนี้ access:

API /system /system_ext /product /vendor /data
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 กำหนดไฟล์จำนวนมากของระบบของคุณเองซึ่งระบุแพ็กเกจสำหรับ system พาร์ติชัน แล้วตั้งค่าการตรวจสอบข้อกำหนดของเส้นทางอาร์ติแฟกต์ ใน device.mk (เพื่อป้องกันการติดตั้งโมดูลที่ไม่ใช่ระบบ ลงในพาร์ติชัน system) ไม่ใช่
2 ล้างรายการที่อนุญาต ไม่ใช่
3 บังคับใช้อินเทอร์เฟซที่มาพร้อมเครื่องและระบุความล้มเหลวของลิงก์รันไทม์ (ทำงานใน ควบคู่ไปกับการบังคับใช้ Java) Y
4 บังคับใช้อินเทอร์เฟซ Java และตรวจสอบลักษณะรันไทม์ (เรียกใช้ได้พร้อมกัน ด้วยการบังคับใช้แบบดั้งเดิม) Y
5 ตรวจสอบลักษณะการทำงานของรันไทม์ Y
6 อัปเดต device.mk ให้มีการบังคับใช้อินเทอร์เฟซผลิตภัณฑ์ Y

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

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

  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 ให้รับค่า getfile ทั่วไปสำหรับ 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 เองหรือในไฟล์บิลด์ที่รวมไว้ การพยายามติดตั้งโมดูลไปยังเส้นทางที่ไม่อนุญาตจะทำให้บิลด์หยุดทำงาน วิธีแก้ไข หยุดพัก ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้

  • ตัวเลือกที่ 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 ไฟล์สร้างไม่มีการอ้างอิง (และไม่ได้บันทึกไว้ เวลาบิลด์)
    • ในการตรวจสอบจากระบบบิลด์ ให้เพิ่มไลบรารีที่จำเป็นลงใน shared_libs: หรือ required:
  5. แก้ไขทรัพยากร Dependency ที่ขาดหายไปโดยใช้คำแนะนำที่ให้ไว้ด้านบน

ขั้นตอนที่ 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