Android 12 มีการเปลี่ยนแปลงระบบบิลด์เป็นการคอมไพล์ AOT
ของไฟล์ DEX (dexpreopt) สำหรับโมดูล Java ที่มี <uses-library>
ทรัพยากร Dependency ในบางกรณี การเปลี่ยนแปลงระบบบิลด์เหล่านี้อาจทำให้บิลด์เสียหายได้ ใช้หน้านี้เพื่อเตรียมพร้อมรับมือกับความเสียหาย และทำตามสูตรในหน้านี้เพื่อแก้ไขและลดผลกระทบ
Dexpreopt คือกระบวนการคอมไพล์ล่วงหน้าของไลบรารีและแอป Java Dexpreopt เกิดขึ้นในโฮสต์ในระหว่างเวลาบิลด์ (ต่างจาก dexopt ซึ่งเกิดขึ้นในอุปกรณ์) โครงสร้างทรัพยากร Dependency ของไลบรารีที่ใช้ร่วมกันซึ่งโมดูล Java (ไลบรารีหรือแอป) ใช้เรียกว่า บริบทของ Class Loader (CLC) CLC ในระหว่างการบิลด์และในระหว่างรันไทม์ต้องตรงกันเพื่อให้แน่ใจว่า dexpreopt จะทำงานได้อย่างถูกต้อง CLC ในระหว่างการบิลด์คือสิ่งที่คอมไพเลอร์ dex2oat ใช้ในระหว่าง dexpreopt (บันทึกไว้ในไฟล์ ODEX) และ CLC ในระหว่างรันไทม์คือบริบทที่โหลดโค้ดที่คอมไพล์ล่วงหน้าในอุปกรณ์
CLC ในระหว่างการบิลด์และในระหว่างรันไทม์ต้องตรงกันทั้งในด้านความถูกต้องและประสิทธิภาพ ในด้านความถูกต้อง จำเป็นต้องจัดการคลาสที่ซ้ำกัน หากทรัพยากร Dependency ของไลบรารีที่ใช้ร่วมกันในระหว่างรันไทม์แตกต่างจากทรัพยากร Dependency ที่ใช้ในการคอมไพล์ คลาสบางคลาสอาจได้รับการแก้ไขแตกต่างกัน ซึ่งทำให้เกิดข้อบกพร่องเล็กน้อยในระหว่างรันไทม์ ประสิทธิภาพยังได้รับผลกระทบจากการตรวจสอบคลาสที่ซ้ำกันในระหว่างรันไทม์ด้วย
กรณีการใช้งานที่ได้รับผลกระทบ
การบูตครั้งแรกเป็นกรณีการใช้งานหลักที่ได้รับผลกระทบจากการเปลี่ยนแปลงเหล่านี้ หาก ART ตรวจพบว่า CLC ในระหว่างการบิลด์และในระหว่างรันไทม์ไม่ตรงกัน ระบบจะปฏิเสธอาร์ติแฟกต์ dexpreopt และเรียกใช้ dexopt แทน การบูตครั้งต่อๆ ไปจะไม่มีปัญหาเนื่องจากระบบสามารถ dexopt แอปในเบื้องหลังและจัดเก็บไว้ในดิสก์ได้
ส่วนต่างๆ ของ Android ที่ได้รับผลกระทบ
การเปลี่ยนแปลงนี้ส่งผลต่อแอปและไลบรารี Java ทั้งหมดที่มีทรัพยากร Dependency ในระหว่างรันไทม์ในไลบรารี Java อื่นๆ Android มีแอปนับพันแอป และมีแอปหลายร้อยแอปที่ใช้ไลบรารีที่ใช้ร่วมกัน พาร์ทเนอร์ก็ได้รับผลกระทบเช่นกันเนื่องจากมีไลบรารีและแอปของตนเอง
การเปลี่ยนแปลงที่ส่งผลกับส่วนอื่นในระบบ
ระบบบิลด์ต้องทราบทรัพยากร Dependency <uses-library> ก่อนที่จะ
สร้างกฎบิลด์ dexpreopt อย่างไรก็ตาม ระบบบิลด์ไม่สามารถเข้าถึงไฟล์ Manifest โดยตรง
และอ่านแท็ก <uses-library>
ในไฟล์ได้ เนื่องจากระบบบิลด์ไม่ได้รับอนุญาตให้อ่านไฟล์ใดๆ เมื่อ
สร้างกฎบิลด์ (ด้วยเหตุผลด้านประสิทธิภาพ) นอกจากนี้ ไฟล์ Manifest อาจอยู่ในแพ็กเกจภายใน APK หรือไฟล์ที่คอมไพล์ล่วงหน้า ดังนั้น <uses-library>
ข้อมูลต้องอยู่ในไฟล์บิลด์ (Android.bp หรือ Android.mk)
ก่อนหน้านี้ ART เคยใช้วิธีแก้ปัญหาชั่วคราวที่ละเว้นทรัพยากร Dependency ของไลบรารีที่ใช้ร่วมกัน (known
as the &-classpath) ซึ่งไม่ปลอดภัยและทำให้เกิดข้อบกพร่องเล็กน้อย ดังนั้นจึงมีการนำวิธีแก้ปัญหาชั่วคราว
นี้ออกใน Android 12
ด้วยเหตุนี้ โมดูล Java ที่ไม่ได้ให้ข้อมูล <uses-library>
ที่ถูกต้องในไฟล์บิลด์อาจทำให้บิลด์เสียหาย (เกิดจาก
CLC ในระหว่างการบิลด์ไม่ตรงกัน) หรือการถดถอยของเวลาในการบูตครั้งแรก (เกิดจาก CLC ในระหว่างการบูต
ไม่ตรงกันตามด้วย dexopt)
เส้นทางการย้ายข้อมูล
ทำตามขั้นตอนต่อไปนี้เพื่อแก้ไขบิลด์ที่เสียหาย
ปิดใช้การตรวจสอบในระหว่างการบิลด์สำหรับผลิตภัณฑ์หนึ่งๆ ทั่วโลกโดยตั้งค่า
PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := trueในไฟล์ Makefile ของผลิตภัณฑ์ การดำเนินการนี้จะแก้ไขข้อผิดพลาดในการบิลด์ (ยกเว้นกรณีพิเศษ ที่ระบุไว้ในส่วนการแก้ไขความเสียหาย) อย่างไรก็ตาม นี่เป็นวิธีแก้ปัญหาชั่วคราว และอาจทำให้ 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 (แยก
ไฟล์ 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ในไฟล์ Makefile ของผลิตภัณฑ์ ระบบจะยังคงทำการตรวจสอบความสอดคล้องกันในระหว่างการบิลด์ แต่การตรวจสอบล้มเหลวไม่ได้หมายความว่าบิลด์จะล้มเหลว แต่การตรวจสอบล้มเหลวจะทำให้ระบบบิลด์ลดระดับตัวกรองคอมไพเลอร์ 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
ข้อผิดพลาดในการบิลด์: เส้นทางไลบรารีที่ไม่รู้จัก
หากระบบบิลด์ไม่พบเส้นทางไปยังไฟล์ JAR DEX ของ <uses-library> (ทั้งเส้นทางในโฮสต์ในระหว่างการบิลด์หรือเส้นทางการติดตั้งในอุปกรณ์) โดยปกติแล้วระบบจะทำให้บิลด์ล้มเหลว การค้นหาเส้นทางไม่พบอาจบ่งบอกว่ามีการกำหนดค่าไลบรารีในลักษณะที่ไม่คาดคิด แก้ไขบิลด์ชั่วคราวโดยปิดใช้ dexpreopt สำหรับโมดูลที่มีปัญหา
Android.bp (พร็อพเพอร์ตี้โมดูล)
enforce_uses_libs: false,
dex_preopt: {
enabled: false,
},
Android.mk (ตัวแปรโมดูล)
LOCAL_ENFORCE_USES_LIBRARIES := false
LOCAL_DEX_PREOPT := false
รายงานข้อบกพร่องเพื่อตรวจสอบสถานการณ์ที่ไม่รองรับ
ข้อผิดพลาดในการบิลด์: ทรัพยากร Dependency ของไลบรารีขาดหายไป
การพยายามเพิ่ม <uses-library> X จากไฟล์ Manifest ของโมดูล Y ลงในไฟล์บิลด์
สำหรับ Y อาจทำให้เกิดข้อผิดพลาดในการบิลด์เนื่องจากทรัพยากร Dependency X ขาดหายไป
นี่คือข้อความแสดงข้อผิดพลาดตัวอย่างสำหรับโมดูล 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
สาเหตุทั่วไปของข้อผิดพลาดดังกล่าวคือการตั้งชื่อไลบรารีแตกต่างจากการตั้งชื่อโมดูลที่เกี่ยวข้องในระบบบิลด์ เช่น หากรายการ
<uses-library> ในไฟล์ Manifest คือ 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 อื่น ไม่ใช่ไลบรารี) ระบบบิลด์ไม่รองรับทุกกรณี เนื่องจากในระหว่างเวลาบิลด์เป็นไปไม่ได้ที่จะทราบอย่างแน่ชัดว่าแอปจะโหลดอะไรในระหว่างรันไทม์
บริบทของ Class Loader
CLC เป็นโครงสร้างคล้ายแผนผังที่อธิบายลำดับชั้นของ Class Loader ระบบบิลด์ใช้ CLC ในความหมายแคบ (ครอบคลุมเฉพาะไลบรารี ไม่ใช่ APK หรือ
Class Loader ที่กำหนดเอง) โดยเป็นแผนผังไลบรารีที่แสดงการปิดแบบทรานซิทีฟของทรัพยากร Dependency <uses-library> ทั้งหมดของไลบรารีหรือแอป องค์ประกอบระดับบนสุดของ CLC คือทรัพยากร Dependency <uses-library> โดยตรงที่ระบุไว้ในไฟล์ Manifest (Classpath) แต่ละโหนดของแผนผัง CLC เป็นโหนด
<uses-library> ที่อาจมีโหนดย่อย <uses-library> ของตัวเอง
เนื่องจากทรัพยากร Dependency <uses-library> เป็นกราฟแบบมีทิศทางและไม่มีวงจร และไม่
จำเป็นต้องเป็นแผนผัง CLC จึงอาจมีแผนผังย่อยหลายรายการสำหรับไลบรารีเดียวกัน กล่าวอีกนัยหนึ่ง CLC คือกราฟทรัพยากร Dependency ที่ "คลี่" ออกเป็นแผนผัง การทำซ้ำเกิดขึ้นในระดับตรรกะเท่านั้น Class Loader พื้นฐานจริงไม่ได้ทำซ้ำ (ในระหว่างรันไทม์จะมีอินสแตนซ์ Class Loader เดียวสำหรับแต่ละไลบรารี)
CLC กำหนดลำดับการค้นหาไลบรารีเมื่อแก้ไขคลาส Java ที่ไลบรารีหรือแอปใช้ ลำดับการค้นหามีความสำคัญเนื่องจากไลบรารีอาจมีคลาสที่ซ้ำกัน และระบบจะแก้ไขคลาสให้ตรงกับรายการแรก
CLC ในอุปกรณ์ (ในระหว่างรันไทม์)
PackageManager (ใน frameworks/base) สร้าง CLC เพื่อโหลดโมดูล Java ในอุปกรณ์ โดยจะเพิ่มไลบรารีที่ระบุไว้ในแท็ก <uses-library> ในไฟล์ Manifest ของโมดูล
เป็นองค์ประกอบ CLC ระดับบนสุด
สำหรับไลบรารีที่ใช้แต่ละรายการ PackageManager จะรับทรัพยากร <uses-library>
Dependency ทั้งหมดของไลบรารีนั้น (ระบุเป็นแท็กในไฟล์ Manifest ของไลบรารีนั้น) และเพิ่ม CLC ที่ซ้อนกันสำหรับทรัพยากร Dependency แต่ละรายการ กระบวนการนี้จะทำซ้ำแบบเรียกตัวเองจนกว่า
โหนดลีฟทั้งหมดของแผนผัง CLC ที่สร้างขึ้นจะเป็นไลบรารีที่ไม่มี<uses-library>
ทรัพยากร Dependency
PackageManager รู้จักเฉพาะไลบรารีที่ใช้ร่วมกัน คำจำกัดความของ "ใช้ร่วมกัน" ในการใช้งานนี้แตกต่างจากความหมายปกติ (เช่น ใช้ร่วมกันเทียบกับแบบคงที่) ใน Android ไลบรารี Java ที่ใช้ร่วมกันคือไลบรารีที่ระบุไว้ในการกำหนดค่า XML ที่ติดตั้งในอุปกรณ์ (/system/etc/permissions/platform.xml) แต่ละรายการจะมีชื่อของไลบรารีที่ใช้ร่วมกัน เส้นทางไปยังไฟล์ JAR DEX และรายการทรัพยากร Dependency (ไลบรารีที่ใช้ร่วมกันอื่นๆ ที่ไลบรารีนี้ใช้ในระหว่างรันไทม์ และระบุไว้ในแท็ก <uses-library> ในไฟล์ Manifest)
กล่าวอีกนัยหนึ่ง มีแหล่งข้อมูล 2 แหล่งที่ช่วยให้ PackageManager
สร้าง CLC ในระหว่างรันไทม์ได้ ได้แก่ แท็ก <uses-library> ในไฟล์ Manifest และ
ทรัพยากร Dependency ของไลบรารีที่ใช้ร่วมกันในการกำหนดค่า XML
CLC ในโฮสต์ (ในระหว่างการบิลด์)
CLC ไม่ได้จำเป็นเฉพาะเมื่อโหลดไลบรารีหรือแอปเท่านั้น แต่ยังจำเป็นเมื่อคอมไพล์ไลบรารีหรือแอปด้วย การคอมไพล์อาจเกิดขึ้นในอุปกรณ์ (dexopt) หรือในระหว่างการบิลด์ (dexpreopt) เนื่องจาก dexopt เกิดขึ้นในอุปกรณ์ จึงมีข้อมูลเหมือนกับ PackageManager (ไฟล์ Manifest และทรัพยากร Dependency ของไลบรารีที่ใช้ร่วมกัน)
อย่างไรก็ตาม dexpreopt เกิดขึ้นในโฮสต์และในสภาพแวดล้อมที่แตกต่างกันโดยสิ้นเชิง และต้องรับข้อมูลเดียวกันจากระบบบิลด์
ดังนั้น CLC ในระหว่างการบิลด์ที่ dexpreopt ใช้และ CLC ในระหว่างรันไทม์ที่ PackageManager ใช้จึงเป็นสิ่งเดียวกัน แต่คำนวณด้วยวิธีที่แตกต่างกัน 2 วิธี
CLC ในระหว่างการบิลด์และในระหว่างรันไทม์ ต้อง ตรงกัน ไม่เช่นนั้นโค้ดที่คอมไพล์ AOT ซึ่งสร้างโดย dexpreopt จะถูกปฏิเสธ คอมไพเลอร์ dex2oat จะบันทึก CLC ในระหว่างการบิลด์ในไฟล์ *.odex (ในช่อง classpath ของส่วนหัวไฟล์ OAT) เพื่อตรวจสอบความเท่ากันของ CLC ในระหว่างการบิลด์และในระหว่างรันไทม์ หากต้องการค้นหา CLC ที่จัดเก็บไว้ ให้ใช้คำสั่งต่อไปนี้
oatdump --oat-file=<FILE> | grep '^classpath = '
ระบบจะรายงาน CLC ในระหว่างการบิลด์และในระหว่างรันไทม์ไม่ตรงกันใน logcat ในระหว่างการบูต ค้นหาด้วยคำสั่งต่อไปนี้
logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch'
การไม่ตรงกันส่งผลเสียต่อประสิทธิภาพ เนื่องจากบังคับให้ไลบรารีหรือแอปต้องได้รับการ dexopt หรือทำงานโดยไม่มีการเพิ่มประสิทธิภาพ (เช่น ระบบอาจต้องแยกโค้ดของแอปออกจาก APK ในหน่วยความจำ ซึ่งเป็นการดำเนินการที่ใช้ทรัพยากรมาก)
ไลบรารีที่ใช้ร่วมกันอาจเป็นแบบไม่บังคับหรือบังคับ จากมุมมองของ dexpreopt ไลบรารีที่บังคับต้องมีอยู่ในระหว่างเวลาบิลด์ (หากไม่มีจะทำให้เกิดข้อผิดพลาดในการบิลด์) ไลบรารีที่ไม่บังคับอาจมีหรือไม่มีอยู่ในระหว่างเวลาบิลด์ก็ได้ หากมี ระบบจะเพิ่มไลบรารีนั้นลงใน CLC ส่งไปยัง dex2oat และบันทึกไว้ในไฟล์ *.odex หากไม่มีไลบรารีที่ไม่บังคับ ระบบจะข้ามและไม่เพิ่มลงใน CLC หากสถานะในระหว่างการบิลด์และในระหว่างรันไทม์ไม่ตรงกัน (ไลบรารีที่ไม่บังคับมีอยู่ในกรณีหนึ่ง แต่ไม่มีอยู่ในอีกกรณีหนึ่ง) CLC ในระหว่างการบิลด์และในระหว่างรันไทม์จะไม่ตรงกัน และโค้ดที่คอมไพล์จะถูกปฏิเสธ
รายละเอียดระบบบิลด์ขั้นสูง (ตัวแก้ไขไฟล์ Manifest)
บางครั้งแท็ก <uses-library> อาจขาดหายไปจากไฟล์ Manifest ต้นฉบับของ
ไลบรารีหรือแอป ซึ่งอาจเกิดขึ้นได้ เช่น หากทรัพยากร Dependency แบบทรานซิทีฟรายการใดรายการหนึ่ง
ของไลบรารีหรือแอปเริ่มใช้แท็ก <uses-library> อื่น และไฟล์
Manifest ของไลบรารีหรือแอปไม่ได้อัปเดตให้รวมแท็กนั้น
Soong สามารถคำนวณแท็ก <uses-library> ที่ขาดหายไปบางรายการสำหรับไลบรารี
หรือแอปหนึ่งๆ โดยอัตโนมัติ เนื่องจากไลบรารี SDK อยู่ในการปิดแบบทรานซิทีฟของทรัพยากร Dependency
ของไลบรารีหรือแอป จำเป็นต้องมีการปิดเนื่องจากไลบรารี (หรือแอป) อาจ
ขึ้นต่อกันกับไลบรารีแบบคงที่ที่ขึ้นต่อกันกับไลบรารี SDK และอาจ
ขึ้นต่อกันแบบทรานซิทีฟอีกครั้งผ่านไลบรารีอื่น
ระบบไม่สามารถคำนวณแท็ก <uses-library> ทั้งหมดด้วยวิธีนี้ แต่หากทำได้ เราขอแนะนำให้ Soong เพิ่มรายการไฟล์ Manifest โดยอัตโนมัติ เนื่องจากมีโอกาสเกิดข้อผิดพลาดน้อยกว่าและช่วยให้การบำรุงรักษาง่ายขึ้น เช่น เมื่อแอปจำนวนมากใช้ไลบรารีแบบคงที่
ที่เพิ่มทรัพยากร Dependency <uses-library> ใหม่ แอปทั้งหมดจะต้องได้รับการ
อัปเดต ซึ่งเป็นการดำเนินการที่ดูแลรักษายาก