การตรวจสอบ Dexpreopt และ <uses-library>

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)

เส้นทางการย้ายข้อมูล

ทำตามขั้นตอนต่อไปนี้เพื่อแก้ไขบิลด์ที่เสียหาย

  1. ปิดใช้การตรวจสอบในระหว่างการบิลด์สำหรับผลิตภัณฑ์หนึ่งๆ ทั่วโลกโดยตั้งค่า

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    ในไฟล์ Makefile ของผลิตภัณฑ์ การดำเนินการนี้จะแก้ไขข้อผิดพลาดในการบิลด์ (ยกเว้นกรณีพิเศษ ที่ระบุไว้ในส่วนการแก้ไขความเสียหาย) อย่างไรก็ตาม นี่เป็นวิธีแก้ปัญหาชั่วคราว และอาจทำให้ CLC ในระหว่างการบูตไม่ตรงกันตามด้วย dexopt

  2. แก้ไขโมดูลที่ล้มเหลวก่อนที่คุณจะปิดใช้การตรวจสอบในระหว่างการบิลด์ทั่วโลก โดยเพิ่มข้อมูล <uses-library> ที่จำเป็น ลงในไฟล์บิลด์ (ดูรายละเอียดในส่วน การแก้ไขความเสียหาย) สำหรับโมดูลส่วนใหญ่ การดำเนินการนี้ต้องเพิ่มโค้ด 2-3 บรรทัดใน Android.bp หรือใน Android.mk

  3. ปิดใช้การตรวจสอบในระหว่างการบิลด์และ dexpreopt สำหรับกรณีที่มีปัญหา โดยทำทีละโมดูล ปิดใช้ dexpreopt เพื่อไม่ให้เสียเวลาในการบิลด์และพื้นที่เก็บข้อมูลกับอาร์ติแฟกต์ที่ถูกปฏิเสธในระหว่างการบูต

  4. เปิดใช้การตรวจสอบในระหว่างการบิลด์อีกครั้งทั่วโลกโดยยกเลิกการตั้งค่า PRODUCT_BROKEN_VERIFY_USES_LIBRARIES ที่ตั้งค่าไว้ในขั้นตอนที่ 1 บิลด์ไม่ควรล้มเหลวหลังจากการเปลี่ยนแปลงนี้ (เนื่องจากขั้นตอนที่ 2 และ 3)

  5. แก้ไขโมดูลที่คุณปิดใช้ในขั้นตอนที่ 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

  1. มองหาไลบรารีที่ขาดหายไปในพร็อพเพอร์ตี้ libs ของโมดูล หากมีอยู่ Soong จะเพิ่มไลบรารีดังกล่าวโดยอัตโนมัติ ยกเว้นในกรณีพิเศษต่อไปนี้

    • ไลบรารีไม่ใช่ไลบรารี SDK (กำหนดเป็น java_library แทนที่จะเป็น java_sdk_library)
    • ไลบรารีมีชื่อไลบรารี (ในไฟล์ Manifest) แตกต่างจากชื่อโมดูล (ในระบบบิลด์)

    หากต้องการแก้ไขปัญหานี้ชั่วคราว ให้เพิ่ม provides_uses_lib: "<library-name>" ใน Android.bp คำจำกัดความของไลบรารี หากต้องการแก้ปัญหาในระยะยาว ให้แก้ไขปัญหาพื้นฐานโดยแปลงไลบรารีเป็นไลบรารี SDK หรือเปลี่ยนชื่อโมดูล

  2. หากขั้นตอนก่อนหน้าไม่ได้ให้วิธีแก้ปัญหา ให้เพิ่ม uses_libs: ["<library-module-name>"] สำหรับไลบรารีที่จำเป็น หรือ optional_uses_libs: ["<library-module-name>"] สำหรับไลบรารีที่ไม่บังคับลงใน คำจำกัดความ Android.bp ของโมดูล พร็อพเพอร์ตี้เหล่านี้ยอมรับรายการชื่อโมดูล ลำดับสัมพัทธ์ของไลบรารีในรายการต้องเหมือนกับลำดับในไฟล์ Manifest

สำหรับโมดูล Android.mk

  1. ตรวจสอบว่าไลบรารีมีชื่อไลบรารี (ในไฟล์ Manifest) แตกต่างจากชื่อโมดูล (ในระบบบิลด์) หรือไม่ หากมี ให้แก้ไขปัญหานี้ชั่วคราวโดยเพิ่ม LOCAL_PROVIDES_USES_LIBRARY := <library-name> ในไฟล์ Android.mk ของ ไลบรารี หรือเพิ่ม provides_uses_lib: "<library-name>" ในAndroid.bp ไฟล์ของไลบรารี (ทั้ง 2 กรณีเป็นไปได้เนื่องจากโมดูล Android.mk อาจ ขึ้นต่อกันกับไลบรารี Android.bp) หากต้องการแก้ปัญหาในระยะยาว ให้แก้ไขปัญหาพื้นฐานโดยเปลี่ยนชื่อโมดูลไลบรารี

  2. เพิ่ม 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> ใหม่ แอปทั้งหมดจะต้องได้รับการ อัปเดต ซึ่งเป็นการดำเนินการที่ดูแลรักษายาก