Android 12 มีการเปลี่ยนแปลงระบบการสร้างสำหรับการคอมไพล์ AOT ของไฟล์ DEX (dexpreopt) สําหรับโมดูล Java ที่มี<uses-library>
Dependency ในบางกรณี การเปลี่ยนแปลงระบบบิลด์เหล่านี้อาจทำให้บิลด์ใช้งานไม่ได้ ใช้หน้านี้เพื่อเตรียมพร้อมสำหรับการหยุดชะงัก และทําตามวิธีการในหน้านี้เพื่อแก้ไขและบรรเทาปัญหา
Dexpreopt คือกระบวนการคอมไพล์ไลบรารีและแอป Java ล่วงหน้า Dexpreopt จะเกิดขึ้นบนโฮสต์เมื่อถึงเวลาสร้าง (ต่างจาก dexopt ซึ่งเกิดขึ้นในอุปกรณ์) โครงสร้างของทรัพยากร Dependency ของไลบรารีที่ใช้ร่วมกันซึ่งโมดูล Java (ไลบรารีหรือแอป) ใช้เรียกว่าบริบทตัวโหลดคลาส (CLC) CLC ของช่วงสร้างและช่วงรันไทม์ต้องตรงกันเพื่อรับประกันความถูกต้องของ dexpreopt CLC ขณะสร้างคือสิ่งที่คอมไพเลอร์ dex2oat ใช้ ณ เวลา dexpreopt (บันทึกไว้ในไฟล์ ODEX) และ CLC ขณะรันไทม์คือบริบทที่โหลดโค้ดที่คอมไพล์ไว้ล่วงหน้าในอุปกรณ์
CLC ของช่วงสร้างและช่วงรันไทม์เหล่านี้ต้องตรงกันเพื่อเหตุผลด้านความถูกต้องและประสิทธิภาพ คุณต้องจัดการกับชั้นเรียนที่ซ้ำกันเพื่อให้ถูกต้อง หากความเกี่ยวข้องของไลบรารีที่แชร์ในรันไทม์แตกต่างจากที่ใช้สำหรับการคอมไพล์ คลาสบางคลาสอาจได้รับการแก้ไขแตกต่างกันไป ซึ่งทำให้เกิดข้อบกพร่องเล็กๆ น้อยๆ ในรันไทม์ ประสิทธิภาพยังได้รับผลกระทบจากการตรวจสอบรันไทม์เพื่อหาคลาสที่ซ้ำกันด้วย
กรณีการใช้งานที่ได้รับผลกระทบ
การบูตครั้งแรกเป็น Use Case หลักที่ได้รับผลกระทบจากการเปลี่ยนแปลงเหล่านี้: หาก ART ตรวจพบความไม่ตรงกันระหว่าง CLC ของช่วงสร้างและช่วงรันไทม์ ระบบจะปฏิเสธอาร์ติแฟกต์ dexpreopt และเรียกใช้ dexopt แทน สำหรับการบูตครั้งต่อๆ ไป การดำเนินการนี้จะไม่มีปัญหาเนื่องจากแอปสามารถถอด Dex ออกในเบื้องหลังและจัดเก็บไว้ในดิสก์ได้
พื้นที่ใน Android ที่ได้รับผลกระทบ
ซึ่งจะส่งผลต่อแอปและไลบรารี Java ทั้งหมดที่ต้องใช้ไลบรารี Java อื่นๆ ในรันไทม์ Android มีแอปหลายพันแอป และหลายร้อยแอปใช้ไลบรารีที่แชร์ พาร์ทเนอร์ก็ได้รับผลกระทบด้วย เนื่องจากมีพาร์ทเนอร์ไลบรารีและแอปของตนเอง
การเปลี่ยนแปลงที่ส่งผลกับส่วนอื่นในระบบ
ระบบบิลด์ต้องทราบข้อมูลเกี่ยวกับไลบรารี <uses-library>
ก่อนสร้างกฎการสร้าง dexpreopt อย่างไรก็ตาม ระบบจะไม่สามารถเข้าถึงไฟล์ Manifest โดยตรงและอ่านแท็ก <uses-library>
ในไฟล์ดังกล่าวได้ เนื่องจากระบบบิลด์ไม่ได้รับอนุญาตให้อ่านไฟล์ใดก็ได้เมื่อสร้างกฎการสร้าง (เพื่อเหตุผลด้านประสิทธิภาพ) นอกจากนี้ ไฟล์ Manifest อาจรวมอยู่ใน APK หรือไฟล์ที่สร้างไว้ล่วงหน้า ดังนั้น ข้อมูล <uses-library>
ต้องอยู่ในไฟล์บิลด์ (Android.bp
หรือ Android.mk
)
ก่อนหน้านี้ ART ใช้วิธีแก้ปัญหาที่ละเว้นการพึ่งพาไลบรารีที่ใช้ร่วมกัน (หรือที่เรียกว่า &-classpath
) ซึ่งไม่ปลอดภัยและทำให้เกิดข้อบกพร่องเล็กๆ น้อยๆ เราจึงนำวิธีแก้ปัญหานี้ออกใน Android 12
ด้วยเหตุนี้ โมดูล Java ที่ไม่ได้ให้<uses-library>
ข้อมูลในไฟล์บิลด์ที่ถูกต้องอาจทําให้การบิลด์ใช้งานไม่ได้ (เกิดจาก CLC ที่ไม่ตรงกันขณะสร้าง) หรือเวลาในการบูตครั้งแรกช้าลง (เกิดจาก CLC ที่ไม่ตรงกันขณะบูตตามด้วย dexopt)
เส้นทางการย้ายข้อมูล
ทำตามขั้นตอนต่อไปนี้เพื่อแก้ไขบิลด์ที่ไม่ทำงาน
ปิดใช้การตรวจสอบเวลาสร้างสำหรับผลิตภัณฑ์ที่เฉพาะเจาะจงทั่วโลกโดยการตั้งค่า
PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true
ในไฟล์ Make ของผลิตภัณฑ์ ซึ่งจะแก้ไขข้อผิดพลาดของบิลด์ (ยกเว้นบางกรณีพิเศษที่ระบุไว้ในส่วนการแก้ไขข้อขัดข้อง) อย่างไรก็ตาม วิธีนี้เป็นวิธีแก้ปัญหาชั่วคราวและอาจทําให้ CLC ที่ไม่ตรงกันในเวลาบูตตามด้วย dexopt
แก้ไขโมดูลที่ไม่ผ่านการตรวจสอบก่อนที่คุณปิดใช้การตรวจสอบเวลาสร้างทั่วโลกโดยเพิ่มข้อมูล
<uses-library>
ที่จำเป็นลงในไฟล์บิลด์ (ดูรายละเอียดที่การแก้ไขข้อขัดข้อง) สําหรับข้อบังคับส่วนใหญ่ คุณต้องเพิ่มบรรทัด 2-3 บรรทัดในAndroid.bp
หรือในAndroid.mk
ปิดใช้การตรวจสอบเวลาสร้างและ dexpreopt สำหรับกรณีที่มีปัญหา โดยแยกเป็นโมดูล ปิดใช้ dexpreopt เพื่อไม่ให้เสียเวลาสร้างและพื้นที่เก็บข้อมูลกับอาร์ติแฟกต์ที่ถูกปฏิเสธเมื่อบูต
เปิดใช้การตรวจสอบเวลาสร้างอีกครั้งโดยยกเลิกการตั้งค่า
PRODUCT_BROKEN_VERIFY_USES_LIBRARIES
ที่ตั้งไว้ในขั้นตอนที่ 1 การสร้างไม่ควรล้มเหลวหลังจากการเปลี่ยนแปลงนี้ (เนื่องจากขั้นตอนที่ 2 และ 3)แก้ไขแต่ละข้อบังคับที่คุณปิดใช้ในขั้นตอนที่ 3 แล้วเปิดใช้ مجدد dexpreopt และการตรวจสอบ
<uses-library>
รายงานข้อบกพร่องหากจำเป็น
ระบบจะบังคับใช้การตรวจสอบ <uses-library>
ขณะสร้างใน Android 12
แก้ไขข้อบกพร่อง
ส่วนต่อไปนี้จะบอกวิธีแก้ไขข้อบกพร่องบางประเภท
ข้อผิดพลาดในการสร้าง: CLC ไม่ตรงกัน
ระบบบิลด์จะตรวจสอบความสอดคล้องกันของเวลาสร้างระหว่างข้อมูลในไฟล์ Android.bp
หรือ Android.mk
กับไฟล์ Manifest ระบบบิลด์อ่านไฟล์ Manifest ไม่ได้ แต่สามารถสร้างกฎการสร้างเพื่ออ่านไฟล์ Manifest (ดึงข้อมูลจาก APK หากจำเป็น) และเปรียบเทียบแท็ก <uses-library>
ในไฟล์ Manifest กับข้อมูล <uses-library>
ในไฟล์บิลด์ หากการตรวจสอบไม่สำเร็จ ข้อผิดพลาดจะมีลักษณะดังนี้
error: mismatch in the <uses-library> tags between the build system and the manifest:
- required libraries in build system: []
vs. in the manifest: [org.apache.http.legacy]
- optional libraries in build system: []
vs. in the manifest: [com.x.y.z]
- tags in the manifest (.../X_intermediates/manifest/AndroidManifest.xml):
<uses-library android:name="com.x.y.z"/>
<uses-library android:name="org.apache.http.legacy"/>
note: the following options are available:
- to temporarily disable the check on command line, rebuild with RELAX_USES_LIBRARY_CHECK=true (this will set compiler filter "verify" and disable AOT-compilation in dexpreopt)
- to temporarily disable the check for the whole product, set PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true in the product makefiles
- to fix the check, make build system properties coherent with the manifest
- see build/make/Changes.md for details
ดังที่ข้อความแสดงข้อผิดพลาดแนะนำ ปัญหานี้มีหลายวิธีแก้ไข ทั้งนี้ขึ้นอยู่กับความเร่งด่วน
- สําหรับการแก้ไขแบบชั่วคราวสำหรับทั้งผลิตภัณฑ์ ให้ตั้งค่า
PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true
ในไฟล์ Make ของผลิตภัณฑ์ ระบบจะยังคงตรวจสอบความสอดคล้องกันของเวลาสร้าง แต่การตรวจสอบไม่สําเร็จไม่ได้หมายความว่าการสร้างไม่สําเร็จ แต่การตรวจสอบที่ไม่สําเร็จจะทำให้ระบบบิลด์ดาวน์เกรดตัวกรองคอมไพเลอร์ dex2oat เป็นverify
ใน dexpreopt ซึ่งจะปิดใช้การคอมไพล์ AOT ทั้งหมดสําหรับโมดูลนี้ - หากต้องการการแก้ไขแบบด่วนในบรรทัดคำสั่งแบบทั่วเว็บไซต์ ให้ใช้ตัวแปรสภาพแวดล้อม
RELAX_USES_LIBRARY_CHECK=true
ซึ่งมีผลเหมือนกับPRODUCT_BROKEN_VERIFY_USES_LIBRARIES
แต่มีไว้สำหรับใช้กับบรรทัดคำสั่ง ตัวแปรสภาพแวดล้อมจะลบล้างตัวแปรผลิตภัณฑ์ - หากต้องการทราบวิธีแก้ไขที่ต้นเหตุของข้อผิดพลาด ให้แจ้งให้ระบบบิลด์ทราบถึงแท็ก
<uses-library>
ในไฟล์ Manifest การตรวจสอบข้อความแสดงข้อผิดพลาดจะแสดงว่าไลบรารีใดทำให้เกิดปัญหา (เช่นเดียวกับการตรวจสอบAndroidManifest.xml
หรือไฟล์ Manifest ภายใน APK ที่ตรวจสอบได้ด้วยaapt dump badging $APK | grep uses-library
)
สำหรับโมดูล Android.bp
มองหาไลบรารีที่หายไปในพร็อพเพอร์ตี้
libs
ของโมดูล หากมี ปกติแล้ว Soong จะเพิ่มไลบรารีดังกล่าวโดยอัตโนมัติ ยกเว้นในกรณีพิเศษต่อไปนี้- ไลบรารีไม่ใช่ไลบรารี SDK (มีการกําหนดเป็น
java_library
แทนjava_sdk_library
) - ไลบรารีมีชื่อไลบรารี (ในไฟล์ Manifest) แตกต่างจากชื่อโมดูล (ในระบบบิลด์)
หากต้องการแก้ไขปัญหานี้ชั่วคราว ให้เพิ่ม
provides_uses_lib: "<library-name>"
ในคำจำกัดความของไลบรารีAndroid.bp
หากต้องการแก้ปัญหาในระยะยาว ให้แก้ไขปัญหาพื้นฐาน เช่น แปลงไลบรารีเป็นไลบรารี SDK หรือเปลี่ยนชื่อโมดูล- ไลบรารีไม่ใช่ไลบรารี SDK (มีการกําหนดเป็น
หากขั้นตอนก่อนหน้าไม่ได้ช่วยแก้ปัญหา ให้เพิ่ม
uses_libs: ["<library-module-name>"]
สำหรับไลบรารีที่ต้องระบุ หรือoptional_uses_libs: ["<library-module-name>"]
สำหรับไลบรารีที่ไม่บังคับลงในคําจํากัดความAndroid.bp
ของโมดูล พร็อพเพอร์ตี้เหล่านี้ยอมรับรายการชื่อโมดูล ลำดับสัมพัทธ์ของคลังในรายการต้องเหมือนกับลำดับในไฟล์ Manifest
สำหรับโมดูล Android.mk
ตรวจสอบว่าไลบรารีมีชื่อไลบรารี (ในไฟล์ Manifest) แตกต่างจากชื่อโมดูล (ในระบบบิลด์) หรือไม่ หากใช่ ให้แก้ไขชั่วคราวโดยเพิ่ม
LOCAL_PROVIDES_USES_LIBRARY := <library-name>
ในไฟล์Android.mk
ของไลบรารี หรือเพิ่มprovides_uses_lib: "<library-name>"
ในไฟล์Android.bp
ของไลบรารี (ทั้ง 2 กรณีเป็นไปได้เนื่องจากโมดูลAndroid.mk
อาจขึ้นอยู่กับไลบรารีAndroid.bp
) สำหรับการแก้ปัญหาในระยะยาว ให้แก้ไขปัญหาพื้นฐานซึ่งก็คือเปลี่ยนชื่อโมดูลไลบรารีเพิ่ม
LOCAL_USES_LIBRARIES := <library-module-name>
สำหรับไลบรารีที่ต้องระบุ และเพิ่มLOCAL_OPTIONAL_USES_LIBRARIES := <library-module-name>
สำหรับไลบรารีที่ไม่บังคับลงในคําจํากัดความAndroid.mk
ของข้อบังคับ พร็อพเพอร์ตี้เหล่านี้ยอมรับรายการชื่อโมดูล ลำดับสัมพัทธ์ของคลังในรายการต้องเหมือนกับในไฟล์ Manifest
ข้อผิดพลาดในการสร้าง: เส้นทางคลังที่ไม่รู้จัก
หากระบบบิลด์ไม่พบเส้นทางไปยังไฟล์ <uses-library>
DEX jar (เส้นทางเวลาสร้างในโฮสต์หรือเส้นทางการติดตั้งในอุปกรณ์) โดยปกติแล้วระบบจะสร้างบิลด์ไม่สำเร็จ หากไม่พบเส้นทาง แสดงว่าไลบรารีได้รับการกําหนดค่าในลักษณะที่ไม่คาดคิด แก้ไขบิลด์ชั่วคราวโดยปิดใช้ dexpreopt สําหรับข้อบังคับที่มีปัญหา
Android.bp (พร็อพเพอร์ตี้โมดูล):
enforce_uses_libs: false,
dex_preopt: {
enabled: false,
},
Android.mk (ตัวแปรโมดูล):
LOCAL_ENFORCE_USES_LIBRARIES := false
LOCAL_DEX_PREOPT := false
รายงานข้อบกพร่องเพื่อตรวจสอบสถานการณ์ที่ไม่รองรับ
ข้อผิดพลาดในการสร้าง: ไม่มีไลบรารีที่ต้องพึ่งพา
การพยายามเพิ่ม <uses-library>
X จากไฟล์ Manifest ของโมดูล Y ไปยังไฟล์บิลด์ของ Y อาจส่งผลให้เกิดข้อผิดพลาดในการบิลด์เนื่องจากไม่มี X ซึ่งเป็น Dependency
ตัวอย่างข้อความแสดงข้อผิดพลาดสำหรับโมดูล Android.bp มีดังนี้
"Y" depends on undefined module "X"
ตัวอย่างข้อความแสดงข้อผิดพลาดสำหรับโมดูล Android.mk มีดังนี้
'.../JAVA_LIBRARIES/com.android.X_intermediates/dexpreopt.config', needed by '.../APPS/Y_intermediates/enforce_uses_libraries.status', missing and no known rule to make it
แหล่งที่มาที่พบบ่อยของข้อผิดพลาดดังกล่าวคือเมื่อตั้งชื่อไลบรารีแตกต่างจากชื่อโมดูลที่เกี่ยวข้องในระบบบิลด์ ตัวอย่างเช่น หากรายการไฟล์ Manifest<uses-library>
คือ com.android.X
แต่ชื่อของโมดูลไลบรารีคือ X
เท่านั้น ระบบจะแสดงข้อผิดพลาด วิธีแก้ปัญหานี้คือ บอกระบบบิลด์ว่า X
มี <uses-library>
ชื่อ com.android.X
ต่อไปนี้คือตัวอย่างไลบรารี Android.bp
(พร็อพเพอร์ตี้โมดูล)
provides_uses_lib: “com.android.X”,
ตัวอย่างคลัง Android.mk (ตัวแปรโมดูล) มีดังนี้
LOCAL_PROVIDES_USES_LIBRARY := com.android.X
CLC ของเวลาบูตไม่ตรงกัน
เมื่อบูตครั้งแรก ให้ค้นหาข้อความที่เกี่ยวข้องกับ CLC ไม่ตรงกันจาก logcat ดังที่แสดงด้านล่าง
$ adb wait-for-device && adb logcat \
| grep -E 'ClassLoaderContext [a-z ]+ mismatch' -A1
เอาต์พุตอาจมีข้อความในรูปแบบที่แสดงที่นี่
[...] W system_server: ClassLoaderContext shared library size mismatch Expected=..., found=... (PCL[]... | PCL[]...)
[...] I PackageDexOptimizer: Running dexopt (dexoptNeeded=1) on: ...
หากได้รับคำเตือนการจับคู่ CLC ไม่ตรงกัน ให้มองหาคำสั่ง dexopt สำหรับข้อบกพร่องของข้อบังคับ หากต้องการแก้ไขปัญหานี้ ให้ตรวจสอบว่าการตรวจสอบเวลาสร้างสําหรับโมดูลผ่าน หากไม่ได้ผล แสดงว่ากรณีของคุณอาจเป็นกรณีพิเศษที่ระบบบิลด์ไม่รองรับ (เช่น แอปที่โหลด APK อื่น ไม่ใช่ไลบรารี) ระบบบิลด์ไม่สามารถจัดการกับทุกกรณีได้ เนื่องจากในขั้นตอนการบิลด์ เราไม่อาจทราบได้อย่างแน่ชัดว่าแอปจะโหลดอะไรในรันไทม์
บริบทของโปรแกรมโหลดคลาส
CLC เป็นโครงสร้างแบบต้นไม้ที่อธิบายลําดับชั้นของ Class Loader ระบบบิลด์ใช้ CLC ในความหมายที่แคบ (ครอบคลุมเฉพาะไลบรารี ไม่ใช่ APK หรือโปรแกรมโหลดคลาสที่กำหนดเอง) ซึ่งเป็นต้นไม้ของไลบรารีที่แสดงการปิดแบบทรานซิทีฟของ <uses-library>
Dependency ทั้งหมดของไลบรารีหรือแอป องค์ประกอบระดับบนสุดของ CLC คือ <uses-library>
Dependency โดยตรงที่ระบุไว้ในไฟล์ Manifest (Classpath) โหนดแต่ละโหนดของต้นไม้ CLC คือโหนด <uses-library>
ที่อาจมีโหนดย่อย <uses-library>
ของตัวเอง
เนื่องจาก <uses-library>
Dependency เป็นกราฟแบบมีทิศทางที่ไม่เป็นวงจร และไม่จำเป็นต้องเป็นต้นไม้ CLC จึงมีซับต้นไม้หลายรายการสำหรับไลบรารีเดียวกันได้ กล่าวคือ CLC คือกราฟทรัพยากร Dependency ที่ "กางออก" เป็นต้นไม้ การซ้ำกันนี้เกิดขึ้นที่ระดับตรรกะเท่านั้น ไม่ได้มีการซ้ำกันของคลาสโหลดเดอร์ที่แท้จริงที่อยู่เบื้องหลัง (ที่รันไทม์จะมีอินสแตนซ์ของคลาสโหลดเดอร์เพียงอินสแตนซ์เดียวสำหรับไลบรารีแต่ละรายการ)
CLC จะกำหนดลําดับการค้นหาของไลบรารีเมื่อแก้ไขคลาส Java ที่ใช้โดยไลบรารีหรือแอป ลําดับการค้นหามีความสําคัญเนื่องจากไลบรารีอาจมีคลาสที่ซ้ำกัน และระบบจะแก้ไขคลาสให้ตรงกับรายการแรกที่พบ
CLC ในอุปกรณ์ (รันไทม์)
PackageManager
(ใน frameworks/base
) สร้าง CLC เพื่อโหลดข้อบังคับ Java ในอุปกรณ์ โดยจะเพิ่มไลบรารีที่แสดงอยู่ในแท็ก <uses-library>
ในไฟล์ Manifest ของข้อบังคับเป็นองค์ประกอบ CLC ระดับบนสุด
สําหรับไลบรารีที่ใช้แต่ละรายการ PackageManager
จะรับ<uses-library>
ข้อกําหนดทั้งหมด (ระบุเป็นแท็กในไฟล์ Manifest ของไลบรารีนั้น) และเพิ่ม CLC ที่ฝังอยู่สําหรับข้อกําหนดแต่ละรายการ กระบวนการนี้จะทําซ้ำแบบย้อนกลับจนกว่าโหนดใบทั้งหมดของต้นไม้ CLC ที่สร้างขึ้นจะเป็นไลบรารีที่ไม่มี<uses-library>
ข้อกําหนด
PackageManager
รับรู้เฉพาะไลบรารีที่ใช้ร่วมกัน คําจํากัดความของ "แชร์" ในการใช้งานนี้แตกต่างจากความหมายปกติ (เช่น แชร์กับคงที่) ใน Android นั้น ไลบรารีที่แชร์ของ Java คือไลบรารีที่แสดงอยู่ในการกำหนดค่า XML ที่ติดตั้งในอุปกรณ์ (/system/etc/permissions/platform.xml
) แต่ละรายการจะมีชื่อของไลบรารีที่แชร์ เส้นทางไปยังไฟล์ JAR ของ DEX และรายการ Dependency (ไลบรารีที่แชร์อื่นๆ ที่ใช้ไลบรารีนี้ในขณะรันไทม์ และระบุไว้ในแท็ก <uses-library>
ในไฟล์ Manifest)
กล่าวคือ แหล่งข้อมูล 2 แหล่งที่ช่วยให้ PackageManager
สามารถสร้าง CLC ในรันไทม์ ได้แก่ แท็ก <uses-library>
ในไฟล์ Manifest และไลบรารีที่ใช้ร่วมกันในการกำหนดค่า XML
CLC ในโฮสต์ (เวลาสร้าง)
CLC ไม่เพียงจำเป็นเมื่อโหลดไลบรารีหรือแอปเท่านั้น แต่ยังจำเป็นเมื่อคอมไพล์แอปด้วย การคอมไพล์อาจเกิดขึ้นในอุปกรณ์ (dexopt) หรือระหว่างการสร้าง (dexpreopt) เนื่องจาก DexOpt ทำงานในอุปกรณ์ จึงมีข้อมูลเหมือนกับ PackageManager
(ไฟล์ Manifest และทรัพยากร Dependency ของไลบรารีที่ใช้ร่วมกัน)
อย่างไรก็ตาม Dexpreopt จะทำงานบนโฮสต์และในสภาพแวดล้อมที่แตกต่างออกไปโดยสิ้นเชิง และจะต้องได้รับข้อมูลเดียวกันจากระบบบิลด์
ดังนั้น CLC ของเวลาสร้างที่ใช้โดย dexpreopt และ CLC ของเวลารันไทม์ที่ใช้โดย
PackageManager
จึงเป็นสิ่งเดียวกัน แต่คํานวณด้วยวิธีที่แตกต่างกัน 2 วิธี
CLC ของช่วงสร้างและช่วงรันไทม์ต้องตรงกัน มิฉะนั้นระบบจะปฏิเสธโค้ดที่คอมไพล์ AOT ซึ่งสร้างขึ้นโดย dexpreopt หากต้องการตรวจสอบความเท่าเทียมของ CLC รันไทม์และ CLC เวลาสร้าง ผู้คอมไพล์ dex2oat จะบันทึก CLC เวลาสร้างไว้ในไฟล์ *.odex
(ในช่อง classpath
ของส่วนหัวไฟล์ OAT) หากต้องการค้นหา CLC ที่เก็บไว้ ให้ใช้คำสั่งนี้
oatdump --oat-file=<FILE> | grep '^classpath = '
ระบบจะรายงาน CLC ที่ไม่ตรงกันระหว่างเวลาสร้างและเวลารันใน logcat ระหว่างการบูต ค้นหาโดยใช้คําสั่งนี้
logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch'
การจับคู่ไม่ตรงกันส่งผลเสียต่อประสิทธิภาพ เนื่องจากจะบังคับให้ไลบรารีหรือแอปต้องได้รับการแยกไฟล์ DeX หรือทํางานโดยไม่ได้รับการเพิ่มประสิทธิภาพ (เช่น อาจมีต้องดึงข้อมูลโค้ดของแอปในหน่วยความจําจาก APK ซึ่งเป็นการดำเนินการที่สิ้นเปลืองทรัพยากรมาก)
ไลบรารีที่ใช้ร่วมกันอาจเป็นแบบไม่บังคับหรือแบบบังคับก็ได้ จากมุมมองของ dexpreopt ไลบรารีที่จำเป็นต้องแสดงขึ้นขณะที่บิลด์ (หากไม่มี จะเป็นข้อผิดพลาดของบิลด์) ไลบรารีที่ไม่บังคับอาจมีหรือไม่มีก็ได้ ณ เวลาสร้าง หากมี ระบบจะเพิ่มลงใน CLC, ส่งไปยัง dex2oat และบันทึกไว้ในไฟล์ *.odex
หากไม่มีคลังที่ไม่บังคับ ระบบจะข้ามและไม่เพิ่มคลังนั้นลงใน CLC หากสถานะเวลาสร้างและเวลารันไทม์ไม่ตรงกัน (มีไลบรารีที่ไม่บังคับในบางกรณี แต่ไม่มีในอีกกรณีหนึ่ง) แสดงว่า CLC ของเวลาสร้างและเวลารันไทม์ไม่ตรงกันและโค้ดที่คอมไพล์จะไม่ได้รับอนุมัติ
รายละเอียดระบบการสร้างขั้นสูง (เครื่องมือแก้ไขไฟล์ Manifest)
บางครั้งแท็ก <uses-library>
อาจไม่อยู่ในไฟล์ Manifest ต้นทางของไลบรารีหรือแอป กรณีนี้อาจเกิดขึ้นได้ เช่น หาก Dependency แบบทรานซิทีฟรายการใดรายการหนึ่งของไลบรารีหรือแอปเริ่มใช้แท็ก <uses-library>
อื่น และไฟล์ Manifest ของไลบรารีหรือแอปไม่ได้รับการอัปเดตให้รวมแท็กดังกล่าว
Soong สามารถคํานวณแท็ก <uses-library>
ที่ขาดหายไปบางรายการสําหรับไลบรารีหรือแอปหนึ่งๆ โดยอัตโนมัติ เนื่องจากไลบรารี SDK ใน Closure ของ Dependency แบบทรานซิทีฟของไลบรารีหรือแอปนั้นๆ จำเป็นต้องใช้ Closure เนื่องจากไลบรารี (หรือแอป) อาจขึ้นอยู่กับไลบรารีแบบคงที่ซึ่งขึ้นอยู่กับไลบรารี SDK และอาจขึ้นอยู่กับไลบรารีอื่นแบบทรานซิทีฟอีกครั้ง
แท็ก <uses-library>
บางรายการไม่สามารถคํานวณด้วยวิธีนี้ได้ แต่หากเป็นไปได้ เราขอแนะนำให้ Soong เพิ่มรายการไฟล์ Manifest โดยอัตโนมัติ เนื่องจากจะลดข้อผิดพลาดและทําให้การดูแลรักษาง่ายขึ้น ตัวอย่างเช่น เมื่อแอปหลายแอปใช้ไลบรารีแบบคงที่ซึ่งเพิ่ม<uses-library>
Dependency ใหม่ แอปทั้งหมดจะต้องอัปเดต ซึ่งทำให้ดูแลรักษาได้ยาก