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

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

Dexpreopt เป็นกระบวนการคอมไพล์ไลบรารี Java และแอปแบบล่วงหน้า Dexpreopt จะเกิดขึ้นบนโฮสต์เมื่อถึงเวลาสร้าง (ต่างจาก dexopt ซึ่งเกิดขึ้นในอุปกรณ์) โครงสร้างของทรัพยากร Dependency ของไลบรารีที่ใช้ร่วมกันซึ่งโมดูล Java (ไลบรารีหรือแอป) ใช้เรียกว่าบริบทตัวโหลดคลาส (CLC) CLC เวลาบิลด์และรันไทม์ต้องสอดคล้องกันเพื่อรับประกันความถูกต้องของ dexpreopt CLC ขณะสร้างคือสิ่งที่คอมไพเลอร์ dex2oat ใช้ ณ เวลา dexpreopt (บันทึกไว้ในไฟล์ ODEX) และ CLC ขณะรันไทม์คือบริบทที่โหลดโค้ดที่คอมไพล์ไว้ล่วงหน้าในอุปกรณ์

CLC ที่เวลาบิลด์และรันไทม์เหล่านี้ต้องสอดคล้องกันด้วยเหตุผลทั้งในแง่ความถูกต้องและประสิทธิภาพ คุณต้องจัดการกับชั้นเรียนที่ซ้ำกันเพื่อให้ถูกต้อง หากทรัพยากร Dependency ของไลบรารีที่ใช้ร่วมกันระหว่างรันไทม์ต่างจากทรัพยากร Dependency ที่ใช้สำหรับการคอมไพล์ คลาสบางคลาสอาจได้รับการแก้ไขแตกต่างกันไป ซึ่งทำให้เกิดข้อบกพร่องเล็กๆ น้อยๆ เกี่ยวกับรันไทม์ ประสิทธิภาพยังได้รับผลกระทบจากการตรวจสอบรันไทม์เพื่อหาคลาสที่ซ้ำกันด้วย

กรณีการใช้งานที่ได้รับผลกระทบ

การเปิดเครื่องครั้งแรกเป็นกรณีการใช้งานหลักที่ได้รับผลกระทบจากการเปลี่ยนแปลงเหล่านี้ โดยหาก ART ตรวจพบว่าเวลาบิลด์กับ CLC เวลาบิลด์กับรันไทม์ไม่ตรงกัน ก็จะปฏิเสธอาร์ติแฟกต์ dexpreopt แล้วเรียกใช้ dexopt แทน สำหรับการเปิดเครื่องครั้งต่อๆ ไปนั้นไม่เป็นไร เพราะคุณสามารถถอดรหัสแอปในเบื้องหลังและจัดเก็บไว้ในดิสก์ได้

พื้นที่ที่ได้รับผลกระทบของ Android

ซึ่งจะส่งผลต่อแอปและไลบรารี Java ทั้งหมดที่ต้องใช้ไลบรารี Java อื่นๆ ในรันไทม์ Android มีแอปหลายพันแอป และหลายร้อยแอปใช้ไลบรารีที่แชร์ พาร์ทเนอร์ก็ได้รับผลกระทบด้วย เนื่องจากมีพาร์ทเนอร์ไลบรารีและแอปของตนเอง

การเปลี่ยนแปลงช่วงพัก

ระบบบิลด์จำเป็นต้องรู้ทรัพยากร Dependency ของ <uses-library> ก่อนที่จะสร้างกฎบิลด์ Dexpreopt แต่ไฟล์เข้าถึงไฟล์ Manifest โดยตรงและอ่านแท็ก <uses-library> ในไฟล์ไม่ได้เนื่องจากระบบไม่ได้รับอนุญาตให้อ่านไฟล์ที่กำหนดเองเมื่อสร้างกฎการสร้าง (เพื่อเหตุผลด้านประสิทธิภาพ) ยิ่งไปกว่านั้น ไฟล์ Manifest อาจอยู่ในแพ็กเกจที่อยู่ใน APK หรือแบบที่สร้างไว้ล่วงหน้า ดังนั้นข้อมูล <uses-library> จึงต้องอยู่ในไฟล์บิลด์ (Android.bp หรือ Android.mk)

ก่อนหน้านี้ ART ใช้วิธีแก้ปัญหาที่ละเว้นการพึ่งพาไลบรารีที่ใช้ร่วมกัน (หรือที่เรียกว่า &-classpath) ซึ่งไม่ปลอดภัยและทำให้เกิดข้อบกพร่องเล็กๆ น้อยๆ เราจึงนำวิธีแก้ปัญหานี้ออกใน Android 12

ดังนั้นโมดูล Java ที่ไม่ได้ให้ข้อมูล <uses-library> ที่ถูกต้องในไฟล์บิลด์อาจทำให้เกิดการขัดข้องของบิลด์ (เกิดจาก CLC เวลาบิลด์ไม่ตรงกัน) หรือการถดถอยของเวลาเปิดเครื่องครั้งแรก (เกิดจากเวลา CLC ไม่ตรงกันตามด้วย dexopt)

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

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

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

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    ในไฟล์ยี่ห้อผลิตภัณฑ์ ซึ่งจะแก้ไขข้อผิดพลาดของบิลด์ (ยกเว้นบางกรณีพิเศษที่ระบุไว้ในส่วนการแก้ไขข้อขัดข้อง) อย่างไรก็ตาม นี่เป็นวิธีแก้ปัญหาชั่วคราว และอาจทำให้ 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 ได้ (ดึงข้อมูลจาก 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:

  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

ข้อผิดพลาดของบิลด์: เส้นทางไลบรารีที่ไม่รู้จัก

หากระบบบิลด์ไม่พบเส้นทางไปยังไฟล์ <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

รายงานข้อบกพร่องเพื่อตรวจสอบสถานการณ์ที่ไม่รองรับ

ข้อผิดพลาดของบิลด์: ไม่มีทรัพยากร 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 อื่น ไม่ใช่ไลบรารี) ระบบบิลด์ไม่สามารถจัดการกับทุกกรณีได้ เนื่องจากในขั้นตอนการบิลด์ เราไม่อาจทราบได้อย่างแน่ชัดว่าแอปจะโหลดอะไรในรันไทม์

บริบทของตัวโหลดชั้นเรียน

CLC เป็นโครงสร้างแบบต้นไม้ที่อธิบายลําดับชั้นของ Class Loader ระบบบิลด์ใช้ CLC ในความหมายที่แคบ (ครอบคลุมเฉพาะไลบรารี ไม่ใช่ APK หรือโปรแกรมโหลดคลาสที่กำหนดเอง) ซึ่งเป็นต้นไม้ของไลบรารีที่แสดงการปิดแบบทรานซิทีฟของ <uses-library> ทั้งหมดที่ไลบรารีหรือแอปต้องใช้ องค์ประกอบระดับบนสุดของ CLC คือ <uses-library> โดยตรงที่ระบุไว้ในไฟล์ Manifest (คลาสพาธ) แต่ละโหนดของแผนผัง 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 ที่ซ้อนกันสำหรับทรัพยากร Dependency แต่ละรายการ กระบวนการนี้จะทําซ้ำแบบย้อนกลับจนกว่าโหนดใบทั้งหมดของต้นไม้ CLC ที่สร้างขึ้นจะเป็นไลบรารีที่ไม่มี<uses-library>ข้อกําหนด

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 จะถูกปฏิเสธ ในการตรวจสอบความเท่าเทียมกันของ CLC ที่เวลาบิลด์และรันไทม์ คอมไพเลอร์ dex2oat จะบันทึก CLC เวลาที่บิลด์ในไฟล์ *.odex (ในช่อง classpath ของส่วนหัวของไฟล์ OAT) หากต้องการค้นหา CLC ที่เก็บไว้ ให้ใช้คำสั่งนี้

oatdump --oat-file=<FILE> | grep '^classpath = '

CLC ที่เวลาบิลด์และรันไทม์ไม่ตรงกันใน Logcat ระหว่างการเปิดเครื่อง ค้นหาโดยใช้คําสั่งนี้

logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch'

การไม่ตรงกันจะทำให้ประสิทธิภาพการทำงานไม่ตรงกัน เนื่องจากจะบังคับให้ไลบรารีหรือแอปต้องถอดรหัสหรือทำงานโดยไม่มีการเพิ่มประสิทธิภาพ (เช่น อาจต้องแยกโค้ดของแอปออกจาก 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> ใหม่ แอปทั้งหมดจะต้องได้รับการอัปเดต จึงดูแลยาก