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 libs ได้
ตารางต่อไปนี้สรุปคุณสมบัติ Android.bp
ที่ใช้ในการสร้างรูปแบบรูปภาพ
คุณสมบัติใน Android.bp | สร้างสายพันธุ์แล้ว | |
---|---|---|
ก่อนบังคับใช้ | ภายหลังการบังคับใช้ | |
ค่าเริ่มต้น (ไม่มี) | แกนกลาง (รวมถึง | แกนกลาง (รวมถึง |
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
อื่น ๆ เท่านั้น การพยายามลิงก์ไปยังโมดูลใดๆ นอกเหนือจากนี้จะทำให้ระบบบิลด์สร้างข้อผิดพลาดในการตรวจสอบประเภทลิงก์
การบังคับใช้รันไทม์
เมื่อเปิดใช้งานการบังคับใช้อินเทอร์เฟซดั้งเดิม การกำหนดค่าตัวเชื่อมโยงสำหรับตัวเชื่อมโยงไบโอนิคจะไม่อนุญาตให้กระบวนการของระบบใช้ไลบรารี product
การสร้างส่วน product
สำหรับกระบวนการ product
ที่ไม่สามารถลิงก์ไปยังไลบรารีภายนอกพาร์ติชัน product
(อย่างไรก็ตาม กระบวนการดังกล่าวสามารถทำได้ เชื่อมโยงไปยังห้องสมุด VNDK) ความพยายามที่จะละเมิดการกำหนดค่าลิงก์รันไทม์ทำให้กระบวนการล้มเหลวและสร้างข้อความแสดงข้อผิดพลาด CANNOT LINK EXECUTABLE
การบังคับใช้อินเทอร์เฟซ Java
หากต้องการเปิดใช้งานการบังคับใช้อินเทอร์เฟซ Java ให้ตั้งค่า PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE
เป็น true
(ค่าจะถูกตั้งค่าเป็น true
โดยอัตโนมัติเมื่อระดับ API การจัดส่งสำหรับเป้าหมายมากกว่า 29) เมื่อเปิดใช้งาน การบังคับใช้จะอนุญาต/ไม่อนุญาตการเข้าถึงต่อไปนี้
เอพีไอ | /ระบบ | /system_ext | /ผลิตภัณฑ์ | /ผู้ขาย | /ข้อมูล |
---|---|---|---|---|---|
API สาธารณะ | |||||
@SystemApi | |||||
@ซ่อน API |
เช่นเดียวกับในพาร์ติชัน vendor
แอปหรือไลบรารี Java ในพาร์ติชัน product
ได้รับอนุญาตให้ใช้เฉพาะ API สาธารณะและของระบบเท่านั้น ไม่อนุญาตให้ลิงก์ไปยังไลบรารีที่ใช้ API ที่ซ่อนอยู่ ข้อจำกัดนี้รวมถึงการลิงก์ ณ เวลาบิลด์และการสะท้อนกลับในรันไทม์
สร้างการบังคับใช้เวลา
ณ เวลาสร้าง Make และ Soong จะตรวจสอบว่าโมดูล Java ในพาร์ติชัน product
ไม่ได้ใช้ API ที่ซ่อนอยู่โดยการตรวจสอบฟิลด์ platform_apis
และ sdk_version
sdk_version
ของแอปในพาร์ติชัน product
จะต้องเต็มไปด้วย API เวอร์ชัน current
, system_current
หรือตัวเลข และฟิลด์ platform_apis
จะต้องว่างเปล่า
การบังคับใช้รันไทม์
รันไทม์ของ Android จะตรวจสอบว่าแอปในพาร์ติชัน product
ไม่ได้ใช้ API ที่ซ่อนอยู่รวมถึงการสะท้อนกลับด้วย สำหรับรายละเอียด โปรดดู ข้อจำกัดเกี่ยวกับอินเทอร์เฟซที่ไม่ใช่ SDK
การเปิดใช้งานการบังคับใช้อินเทอร์เฟซผลิตภัณฑ์
ใช้ขั้นตอนในส่วนนี้เพื่อเปิดใช้งานการบังคับใช้อินเทอร์เฟซผลิตภัณฑ์
ขั้นตอน | งาน | ที่จำเป็น |
---|---|---|
1 | กำหนด makefile ระบบของคุณเองที่ระบุแพ็คเกจสำหรับพาร์ติชัน system จากนั้นตั้งค่าการตรวจสอบข้อกำหนดพาธของอาร์ติแฟกต์ใน device.mk (เพื่อป้องกันไม่ให้โมดูลที่ไม่ใช่ระบบติดตั้งลงในพาร์ติชัน system ) | เอ็น |
2 | ทำความสะอาดรายการที่อนุญาต | เอ็น |
3 | บังคับใช้อินเทอร์เฟซดั้งเดิมและระบุความล้มเหลวของลิงก์รันไทม์ (สามารถทำงานคู่ขนานกับการบังคับใช้ Java) | ย |
4 | บังคับใช้อินเทอร์เฟซ Java และตรวจสอบพฤติกรรมรันไทม์ (สามารถทำงานคู่ขนานกับการบังคับใช้ดั้งเดิม) | ย |
5 | ตรวจสอบพฤติกรรมรันไทม์ | ย |
6 | อัปเดต device.mk ด้วยการบังคับใช้อินเทอร์เฟซผลิตภัณฑ์ | ย |
ขั้นตอนที่ 1: สร้าง makefile และเปิดใช้งานการตรวจสอบเส้นทางสิ่งประดิษฐ์
ในขั้นตอนนี้ คุณกำหนด makefile system
สร้าง makefile ที่กำหนดแพ็คเกจสำหรับพาร์ติชัน
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),)
ในไฟล์
device.mk
ให้สืบทอด makefile ทั่วไปสำหรับพาร์ติชัน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
ระบบบิลด์จะป้องกันไม่ให้แพ็คเกจที่กำหนดใน makefiles อื่นติดตั้งไปยังพาธที่กำหนดใน require-artifacts-in-path
และ ป้องกันแพ็คเกจที่กำหนดใน makefile ปัจจุบันจากการติดตั้งส่วนนอกพาธที่กำหนดใน require-artifacts-in-path
ในตัวอย่างข้างต้น เมื่อตั้งค่า PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
เป็น strict
แล้ว makefiles ภายนอก oem_system.mk
จะไม่สามารถรวมโมดูลที่ติดตั้งไว้ที่ root
หรือพาร์ติชัน system
ได้ หากต้องการรวมโมดูลเหล่านี้ คุณต้องกำหนดโมดูลเหล่านั้นในไฟล์ oem_system.mk
เองหรือใน makefile ที่รวมไว้ ความพยายามที่จะติดตั้งโมดูลไปยังเส้นทางที่ไม่ได้รับอนุญาตทำให้เกิดการหยุดทำงานของบิลด์ หากต้องการแก้ไขการหยุดพัก ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้:
อ็อพชันที่ 1: รวมโมดูลระบบใน makefiles ที่รวมอยู่ใน
oem_system.mk
สิ่งนี้ทำให้เป็นไปตามข้อกำหนดเส้นทางสิ่งประดิษฐ์ (เนื่องจากโมดูลมีอยู่ใน makefile ที่รวมไว้แล้ว) และอนุญาตให้ติดตั้งชุดของเส้นทางใน `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
หรือเพิ่มลงในไฟล์ make system
ขั้นตอนนี้เป็นทางเลือกเนื่องจากไม่จำเป็นต้องกำหนดอิมเมจ system
ทั่วไปเพื่อเปิดใช้งานการบังคับใช้อินเทอร์เฟซผลิตภัณฑ์ อย่างไรก็ตาม การล้างรายการที่อนุญาตจะเป็นประโยชน์ในการกำหนดขอบเขต system
ด้วย system_ext
ขั้นตอนที่ 3: บังคับใช้อินเทอร์เฟซดั้งเดิม
ในขั้นตอนนี้ คุณจะต้องตั้งค่า PRODUCT_PRODUCT_VNDK_VERSION := current
จากนั้นค้นหาข้อผิดพลาดของบิลด์และรันไทม์และแก้ไข หากต้องการตรวจสอบการบูตและบันทึกของอุปกรณ์ ตลอดจนค้นหาและแก้ไขความล้มเหลวของลิงก์รันไทม์ ให้ทำดังนี้
ตั้งค่า
PRODUCT_PRODUCT_VNDK_VERSION := current
สร้างอุปกรณ์และค้นหาข้อผิดพลาดในการสร้าง คุณมีแนวโน้มที่จะเห็นการแตกของบิลด์เล็กน้อยเนื่องจากตัวเลือกสินค้าหรือตัวเลือกสินค้าหลักหายไป การหยุดพักโดยทั่วไปได้แก่:
- โมดูล
hidl_interface
ใดๆ ที่มีproduct_specific: true
จะไม่สามารถใช้ได้สำหรับโมดูลระบบ หากต้องการแก้ไข ให้แทนที่product_specific: true
ด้วยsystem_ext_specfic: true
- โมดูลอาจขาดตัวเลือกสินค้าที่จำเป็นสำหรับโมดูลผลิตภัณฑ์ ในการแก้ไข ให้ทำให้โมดูลนั้นพร้อมใช้งานสำหรับพาร์ติชัน
product
โดยการตั้งค่าproduct_available: true
หรือย้ายโมดูลไปยังพาร์ติชันproduct
โดยการตั้งproduct_specific: true
- โมดูล
แก้ไขข้อผิดพลาดในการสร้างและตรวจสอบให้แน่ใจว่าอุปกรณ์สร้างได้สำเร็จ
แฟลชรูปภาพและค้นหาข้อผิดพลาดรันไทม์ในการบูตอุปกรณ์และบันทึก
- หากแท็ก
linker
จากบันทึกกรณีทดสอบแสดงข้อความCANNOT LINK EXECUTABLE
แสดงว่าไฟล์ make ขาดการอ้างอิง (และไม่ได้บันทึกไว้ในขณะสร้าง) - หากต้องการตรวจสอบจากระบบบิลด์ ให้เพิ่มไลบรารีที่จำเป็นลงในฟิลด์
shared_libs:
หรือrequired:
- หากแท็ก
แก้ไขการขึ้นต่อกันที่ขาดหายไปโดยใช้คำแนะนำที่ให้ไว้ข้างต้น
ขั้นตอนที่ 4: บังคับใช้อินเทอร์เฟซ Java
ในขั้นตอนนี้ คุณตั้งค่า PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true
จากนั้นค้นหาและแก้ไขข้อผิดพลาดในการสร้างผลลัพธ์ ค้นหาข้อผิดพลาดเฉพาะสองประเภท:
ข้อผิดพลาดประเภทลิงก์ ข้อผิดพลาดนี้บ่งชี้ว่าแอปลิงก์ไปยังโมดูล 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}
ตัวอย่างผลการตรวจสอบ:
#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