Android 11 จะแยกพาร์ติชัน product
ออก ทำให้พาร์ติชันนี้ไม่ขึ้นอยู่กับพาร์ติชัน system
และ vendor
การเปลี่ยนแปลงเหล่านี้ทำให้คุณควบคุมการเข้าถึงอินเทอร์เฟซแบบเนทีฟและ Java ของพาร์ติชัน product
ได้แล้ว (ซึ่งคล้ายกับวิธีบังคับใช้อินเทอร์เฟซสำหรับพาร์ติชัน 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 ) |
core
(รวม /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 |
ไม่มี | core, product, vendor |
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 | |||||
@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 | กำหนดไฟล์ Make ของระบบของคุณเองซึ่งระบุแพ็กเกจสำหรับพาร์ติชัน system จากนั้นตั้งค่าการตรวจสอบข้อกำหนดของเส้นทางอาร์ติแฟกต์ใน device.mk (เพื่อป้องกันไม่ให้ติดตั้งโมดูลที่ไม่ใช่ระบบลงในพาร์ติชัน system ) |
ไม่ใช่ |
2 | ล้างรายการที่อนุญาต | ไม่ใช่ |
3 | บังคับใช้อินเทอร์เฟซแบบเนทีฟและระบุลิงก์รันไทม์ที่ไม่สำเร็จ (สามารถทำงานควบคู่กับการบังคับใช้ Java ได้) | Y |
4 | บังคับใช้อินเทอร์เฟซ Java และยืนยันลักษณะการทํางานของรันไทม์ (ทํางานควบคู่กับการบังคับใช้แบบดั้งเดิมได้) | Y |
5 | ตรวจสอบลักษณะการทํางานของรันไทม์ | Y |
6 | อัปเดต device.mk ด้วยการบังคับใช้อินเทอร์เฟซผลิตภัณฑ์ |
Y |
ขั้นตอนที่ 1: สร้างไฟล์ Make และเปิดใช้การตรวจสอบเส้นทางอาร์ติแฟกต์
ในขั้นตอนนี้ คุณจะต้องกำหนด system
makefile
สร้างไฟล์ make ที่กําหนดแพ็กเกจสําหรับพาร์ติชัน
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
ระบบบิลด์จะป้องกันไม่ให้แพ็กเกจที่ระบุในไฟล์แต่งอื่นๆ ติดตั้งไปยังเส้นทางที่กำหนดไว้ใน require-artifacts-in-path
และป้องกันไม่ให้แพ็กเกจที่กำหนดไว้ในไฟล์ตรวจสอบปัจจุบันติดตั้งอาร์ติแฟกต์นอกเส้นทางที่กำหนดไว้ใน require-artifacts-in-path
ในตัวอย่างข้างต้น เมื่อตั้งค่า PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
เป็น strict
ไฟล์ Make ภายนอก oem_system.mk
จะรวมโมดูลที่ติดตั้งไว้ในพาร์ติชัน root
หรือ system
ไม่ได้ หากต้องการรวมโมดูลเหล่านี้ คุณต้องกำหนดโมดูลเหล่านี้ในไฟล์ oem_system.mk
โดยตรงหรือในไฟล์บิลด์ที่รวมไว้
การพยายามติดตั้งโมดูลไปยังเส้นทางที่ไม่อนุญาตจะทำให้บิลด์หยุดทำงาน หากต้องการแก้ไขการหยุดพัก ให้ทําอย่างใดอย่างหนึ่งต่อไปนี้
ตัวเลือกที่ 1: ใส่โมดูลระบบในไฟล์ยี่ห้อที่รวมไว้ใน
oem_system.mk
ซึ่งจะทำให้เป็นไปตามข้อกำหนดของเส้นทางอาร์ติแฟกต์ (เนื่องจากตอนนี้โมดูลอยู่ในไฟล์ make ที่รวมไว้) จึงอนุญาตให้ติดตั้งไปยังชุดเส้นทางใน "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
จากนั้นมองหาข้อผิดพลาดเกี่ยวกับบิลด์และรันไทม์ แล้วแก้ไขข้อผิดพลาดเหล่านั้น วิธีตรวจสอบการบูตและบันทึกของอุปกรณ์ รวมถึงค้นหาและแก้ไขการลิงก์รันไทม์ที่ไม่สำเร็จ
ตั้งค่า
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 ไม่มีไฟล์ที่ต้องพึ่งพา (และไม่ได้บันทึกไว้เมื่อสร้าง) - หากต้องการตรวจสอบจากระบบบิลด์ ให้เพิ่มไลบรารีที่จำเป็นลงในช่อง
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 ที่มองเห็นได้ (ไม่ใช่แบบซ่อนอยู่) หรือหาวิธีอื่น ตัวอย่างข้อผิดพลาด
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