Android 11 จะแยกproduct
พาร์ติชันออกจากกัน ทำให้product
พาร์ติชันไม่ขึ้นอยู่กับsystem
และvendor
พาร์ติชัน ส่วนหนึ่งของการเปลี่ยนแปลงเหล่านี้คือ
ตอนนี้คุณสามารถควบคุมการเข้าถึงอินเทอร์เฟซดั้งเดิมและ Java ของพาร์ติชัน product
ได้แล้ว (ซึ่งคล้ายกับวิธีที่การบังคับใช้อินเทอร์เฟซทำงานสำหรับพาร์ติชัน 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 สำหรับ Linker ของ Bionic จะไม่อนุญาตให้กระบวนการของระบบใช้ไลบรารี product
ซึ่งจะสร้างส่วน product
สำหรับกระบวนการ product
ที่ลิงก์กับไลบรารีภายนอกพาร์ติชัน product
ไม่ได้ (อย่างไรก็ตาม กระบวนการดังกล่าวจะลิงก์กับไลบรารี VNDK ได้) การพยายามละเมิดการกำหนดค่าลิงก์รันไทม์จะทำให้กระบวนการล้มเหลวและสร้างข้อความแสดงข้อผิดพลาด CANNOT LINK EXECUTABLE
บังคับใช้อินเทอร์เฟซ Java
หากต้องการเปิดใช้การบังคับใช้อินเทอร์เฟซ Java ให้ตั้งค่า
PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE
เป็น true
(ระบบจะตั้งค่าเป็น true
โดยอัตโนมัติเมื่อระดับ Shipping API สำหรับเป้าหมายสูงกว่า 29) เมื่อเปิดใช้แล้ว การบังคับใช้จะอนุญาตหรือไม่อนุญาตให้เข้าถึงสิ่งต่อไปนี้
API | /system | /system_ext | /product | /vendor | /data |
---|---|---|---|---|---|
Public API | |||||
@SystemApi | |||||
@hide 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 | กำหนดไฟล์ Makefile ของระบบของคุณเองซึ่งระบุแพ็กเกจสำหรับพาร์ติชัน system จากนั้นตั้งค่าการตรวจสอบข้อกำหนดเส้นทางอาร์ติแฟกต์ใน device.mk (เพื่อป้องกันไม่ให้โมดูลที่ไม่ใช่ระบบติดตั้งลงในพาร์ติชัน system ) |
N |
2 | ล้างรายการที่อนุญาต | N |
3 | บังคับใช้อินเทอร์เฟซดั้งเดิมและระบุลิงก์รันไทม์ที่ล้มเหลว (สามารถเรียกใช้ควบคู่กับการบังคับใช้ Java) | Y |
4 | บังคับใช้อินเทอร์เฟซ Java และยืนยันลักษณะการทำงานของรันไทม์ (สามารถเรียกใช้แบบขนาน กับการบังคับใช้แบบเนทีฟ) | Y |
5 | ตรวจสอบลักษณะการทำงานของรันไทม์ | Y |
6 | อัปเดต device.mk ด้วยการบังคับใช้อินเทอร์เฟซผลิตภัณฑ์ |
Y |
ขั้นตอนที่ 1: สร้าง Makefile และเปิดใช้การตรวจสอบเส้นทางอาร์ติแฟกต์
ในขั้นตอนนี้ คุณจะกำหนด system
makefile
สร้างไฟล์ 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
ระบบบิลด์จะป้องกันไม่ให้แพ็กเกจที่กำหนดไว้ใน Makefile อื่นๆ ติดตั้งใน
เส้นทางที่กำหนดไว้ใน require-artifacts-in-path
และป้องกันไม่ให้แพ็กเกจ
ที่กำหนดไว้ใน Makefile ปัจจุบันติดตั้งอาร์ติแฟกต์นอกเส้นทาง
ที่กำหนดไว้ใน require-artifacts-in-path
ในตัวอย่างด้านบน เมื่อตั้งค่า PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
เป็น
strict
makefile นอก oem_system.mk
จะรวมโมดูลที่ติดตั้งในพาร์ติชัน root
หรือ system
ไม่ได้ หากต้องการรวมโมดูลเหล่านี้ คุณต้อง
กำหนดโมดูลในไฟล์ oem_system.mk
เองหรือในไฟล์ Makefile ที่รวมไว้
การพยายามติดตั้งโมดูลไปยังเส้นทางที่ไม่ได้รับอนุญาตจะทำให้การสร้างหยุดชะงัก หากต้องการแก้ไข
การหยุดชะงัก ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้
ตัวเลือกที่ 1: รวมโมดูลระบบไว้ในไฟล์ Make ที่รวมอยู่ใน
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
หรือเพิ่มโมดูลไปยัง system
makefile ขั้นตอนนี้ไม่บังคับเนื่องจากไม่จำเป็นต้องกำหนดรูปภาพ system
ทั่วไปเพื่อเปิดใช้การบังคับใช้อินเทอร์เฟซผลิตภัณฑ์ อย่างไรก็ตาม การล้างรายการที่อนุญาตจะช่วยในการกำหนดsystem
ขอบเขตด้วย system_ext
ขั้นตอนที่ 3: บังคับใช้อินเทอร์เฟซเนทีฟ
ในขั้นตอนนี้ คุณจะตั้งค่า PRODUCT_PRODUCT_VNDK_VERSION := current
จากนั้นมองหา
ข้อผิดพลาดในการสร้างและรันไทม์ แล้วแก้ไข วิธีตรวจสอบการบูตอุปกรณ์และบันทึก
รวมถึงค้นหาและแก้ไขลิงก์รันไทม์ที่ล้มเหลว
ตั้งค่า
PRODUCT_PRODUCT_VNDK_VERSION := current
สร้างอุปกรณ์และมองหาข้อผิดพลาดในการสร้าง คุณอาจเห็นการหยุดสร้าง 2-3 ครั้งเนื่องจากไม่มีผลิตภัณฑ์ย่อยหรือผลิตภัณฑ์ย่อยหลัก ช่วงพักที่พบบ่อย ได้แก่
hidl_interface
โมดูลที่มีproduct_specific: true
จะไม่พร้อมใช้งานสำหรับโมดูลระบบ หากต้องการแก้ไข ให้แทนที่product_specific: true
ด้วยsystem_ext_specific: true
- โมดูลอาจไม่มีผลิตภัณฑ์ย่อยที่จำเป็นสำหรับโมดูลผลิตภัณฑ์
หากต้องการแก้ไข ให้ทำให้โมดูลนั้นพร้อมใช้งานในพาร์ติชัน
product
โดย ตั้งค่าproduct_available: true
หรือย้ายโมดูลไปยังพาร์ติชันproduct
โดยตั้งค่าproduct_specific: true
แก้ไขข้อผิดพลาดในการสร้างและตรวจสอบว่าสร้างอุปกรณ์สำเร็จแล้ว
แฟลชอิมเมจและมองหาข้อผิดพลาดขณะรันไทม์ในการบูตและบันทึกของอุปกรณ์
- หากแท็ก
linker
จากบันทึกของกรณีทดสอบแสดงCANNOT LINK EXECUTABLE
ข้อความ แสดงว่าไฟล์ Make ไม่มีทรัพยากร Dependency (และไม่ได้บันทึกไว้ในเวลา สร้าง) - หากต้องการตรวจสอบจากระบบบิลด์ ให้เพิ่มไลบรารีที่จำเป็นลงในฟิลด์
shared_libs:
หรือrequired:
- หากแท็ก
แก้ไขการขึ้นต่อกันที่ขาดหายไปโดยใช้คำแนะนำที่ระบุไว้ด้านบน
ขั้นตอนที่ 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 ที่มองเห็นได้ (ไม่ใช่ 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