Dexpreopt और <uses-library> की जांच

Android 12 में, Java मॉड्यूल के लिए DEX फ़ाइलों (dexpreopt) के एओटी कंपाइलेशन के बिल्ड सिस्टम में बदलाव किए गए हैं. इन मॉड्यूल में <uses-library> डिपेंडेंसी होती हैं. कुछ मामलों में, बिल्ड सिस्टम में किए गए इन बदलावों की वजह से बिल्ड टूट सकते हैं. इस पेज पर दिए गए निर्देशों का पालन करके, टूट-फूट की समस्या से निपटने की तैयारी करें. साथ ही, इस पेज पर दिए गए तरीके अपनाकर, इन समस्याओं को ठीक करें और इनसे होने वाले नुकसान को कम करें.

Dexpreopt, Java लाइब्रेरी और ऐप्लिकेशन को पहले से कंपाइल करने की प्रोसेस है. Dexpreopt, बिल्ड टाइम में होस्ट पर होता है. यह dexopt से अलग है, जो डिवाइस पर होता है. Java मॉड्यूल (कोई लाइब्रेरी या ऐप्लिकेशन) में इस्तेमाल की गई शेयर की गई लाइब्रेरी डिपेंडेंसी के स्ट्रक्चर को क्लास लोडर कॉन्टेक्स्ट (सीएलसी) कहा जाता है. dexpreopt के सही होने की गारंटी देने के लिए, बिल्ड-टाइम और रन-टाइम CLC एक जैसे होने चाहिए. बिल्ड-टाइम सीएलसी का इस्तेमाल dex2oat कंपाइलर, dexpreopt के समय करता है. इसे ODEX फ़ाइलों में रिकॉर्ड किया जाता है. रन-टाइम सीएलसी वह कॉन्टेक्स्ट होता है जिसमें डिवाइस पर पहले से कंपाइल किया गया कोड लोड होता है.

बिल्ड-टाइम और रन-टाइम के ये सीएलसी, सही होने के साथ-साथ परफ़ॉर्मेंस के हिसाब से भी एक जैसे होने चाहिए. सही तरीके से काम करने के लिए, डुप्लीकेट क्लास को मैनेज करना ज़रूरी है. अगर रनटाइम के दौरान शेयर की गई लाइब्रेरी की डिपेंडेंसी, कंपाइल करने के लिए इस्तेमाल की गई डिपेंडेंसी से अलग हैं, तो हो सकता है कि कुछ क्लास अलग तरीके से हल हो जाएं. इससे रनटाइम में मामूली गड़बड़ियां हो सकती हैं. परफ़ॉर्मेंस पर, डुप्लीकेट क्लास के लिए रनटाइम चेक का भी असर पड़ता है.

इस्तेमाल के वे उदाहरण जिन पर असर पड़ा है

इन बदलावों से, पहली बार बूट होने की प्रोसेस पर असर पड़ता है. अगर ART को बिल्ड-टाइम और रन-टाइम सीएलसी के बीच कोई अंतर मिलता है, तो वह dexpreopt आर्टफ़ैक्ट को अस्वीकार कर देता है और dexopt को चलाता है. इसके बाद बूट करने पर, यह ठीक काम करता है. ऐसा इसलिए, क्योंकि ऐप्लिकेशन को बैकग्राउंड में dexopt किया जा सकता है और डिस्क पर सेव किया जा सकता है.

Android के वे हिस्से जिन पर असर पड़ा है

इससे उन सभी Java ऐप्लिकेशन और लाइब्रेरी पर असर पड़ता है जिनमें रनटाइम डिपेंडेंसी होती है. Android पर हज़ारों ऐप्लिकेशन उपलब्ध हैं. इनमें से सैकड़ों ऐप्लिकेशन, शेयर की गई लाइब्रेरी का इस्तेमाल करते हैं. पार्टनर पर भी इसका असर पड़ता है, क्योंकि उनके पास अपनी लाइब्रेरी और ऐप्लिकेशन होते हैं.

नुकसान पहुंचाने वाले बदलाव

dexpreopt बिल्ड के नियम जनरेट करने से पहले, बिल्ड सिस्टम को <uses-library> डिपेंडेंसी के बारे में पता होना चाहिए. हालांकि, यह सीधे तौर पर मेनिफ़ेस्ट को ऐक्सेस नहीं कर सकता और इसमें मौजूद <uses-library> टैग को नहीं पढ़ सकता. ऐसा इसलिए, क्योंकि परफ़ॉर्मेंस की वजह से, बिल्ड सिस्टम को बिल्ड के नियम जनरेट करते समय, किसी भी फ़ाइल को पढ़ने की अनुमति नहीं होती. इसके अलावा, मेनिफ़ेस्ट को किसी APK या पहले से बने हुए ऐप्लिकेशन में पैकेज किया जा सकता है. इसलिए, <uses-library> जानकारी, बिल्ड फ़ाइलों (Android.bp या Android.mk) में मौजूद होनी चाहिए.

इससे पहले, एआरटी एक ऐसे समाधान का इस्तेमाल करता था जो शेयर की गई लाइब्रेरी की डिपेंडेंसी को अनदेखा करता था. इसे &-classpath के तौर पर जाना जाता है. यह समाधान सुरक्षित नहीं था और इससे मामूली बग आते थे. इसलिए, Android 12 में इस समाधान को हटा दिया गया था.

इस वजह से, ऐसे Java मॉड्यूल की वजह से बिल्ड में गड़बड़ियां हो सकती हैं जो अपनी बिल्ड फ़ाइलों में सही <uses-library> जानकारी नहीं देते. ऐसा बिल्ड-टाइम CLC के मेल न खाने की वजह से होता है. इसके अलावा, पहले बूट के समय में रिग्रेशन हो सकता है. ऐसा बूट-टाइम CLC के मेल न खाने और उसके बाद dexopt की वजह से होता है.

माइग्रेशन पाथ

बिल्ड में गड़बड़ी ठीक करने के लिए, यह तरीका अपनाएं:

  1. किसी प्रॉडक्ट के लिए, बिल्ड-टाइम की जांच को पूरी तरह से बंद करने के लिए, यह सेटिंग करें

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    प्रॉडक्ट के मेकफ़ाइल में. इससे बिल्ड से जुड़ी गड़बड़ियां ठीक हो जाती हैं. हालांकि, ब्रेकेज ठीक करना सेक्शन में दिए गए खास मामलों में ऐसा नहीं होता. हालांकि, यह एक अस्थायी समाधान है. इससे बूट-टाइम सीएलसी में अंतर आ सकता है. इसके बाद, dexopt की प्रोसेस शुरू हो सकती है.

  2. ग्लोबल तौर पर बिल्ड-टाइम की जांच बंद करने से पहले, उन मॉड्यूल को ठीक करें जिनमें गड़बड़ी हुई है. इसके लिए, उनकी बिल्ड फ़ाइलों में ज़रूरी <uses-library> जानकारी जोड़ें. ज़्यादा जानकारी के लिए, गड़बड़ियों को ठीक करना लेख पढ़ें. ज़्यादातर मॉड्यूल के लिए, Android.bp या Android.mk में कुछ लाइनें जोड़नी होती हैं.

  3. हर मॉड्यूल के हिसाब से, समस्या वाले मामलों के लिए बिल्ड-टाइम की जांच और dexpreopt को बंद करें. dexpreopt को बंद करें, ताकि बूट के समय अस्वीकार किए गए आर्टफ़ैक्ट पर बिल्ड टाइम और स्टोरेज बर्बाद न हो.

  4. पहले चरण में सेट किए गए PRODUCT_BROKEN_VERIFY_USES_LIBRARIES को अनसेट करके, बिल्ड-टाइम की जांच को फिर से चालू करें. इस बदलाव के बाद, बिल्ड फ़ेल नहीं होना चाहिए (दूसरे और तीसरे चरण की वजह से).

  5. तीसरे चरण में बंद किए गए मॉड्यूल को एक-एक करके ठीक करें. इसके बाद, dexpreopt और <uses-library> की जांच को फिर से चालू करें. अगर ज़रूरी हो, तो गड़बड़ियों की शिकायत करें.

Android 12 में, बिल्ड-टाइम <uses-library> जांच लागू की जाती हैं.

टूट-फूट ठीक करना

यहां दिए गए सेक्शन में, अलग-अलग तरह की गड़बड़ियों को ठीक करने का तरीका बताया गया है.

बिल्ड से जुड़ी गड़बड़ी: सीएलसी मेल नहीं खा रहा है

बिल्ड सिस्टम, बिल्ड टाइम के दौरान Android.bp या Android.mk फ़ाइलों में मौजूद जानकारी और मेनिफ़ेस्ट के बीच तालमेल की जांच करता है. बिल्ड सिस्टम, मेनिफ़ेस्ट को नहीं पढ़ सकता. हालांकि, यह मेनिफ़ेस्ट को पढ़ने के लिए बिल्ड के नियम जनरेट कर सकता है. अगर ज़रूरी हो, तो इसे APK से एक्सट्रैक्ट किया जा सकता है. साथ ही, यह मेनिफ़ेस्ट में मौजूद <uses-library> टैग की तुलना, बिल्ड फ़ाइलों में मौजूद <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 सेट करें. बिल्ड-टाइम कोहेरेंस की जांच अब भी की जाती है. हालांकि, जांच में गड़बड़ी होने का मतलब यह नहीं है कि बिल्ड नहीं हो पाएगा. इसके बजाय, जांच पूरी न होने पर बिल्ड सिस्टम, dex2oat कंपाइलर फ़िल्टर को dexpreopt में verify पर डाउनग्रेड कर देता है. इससे इस मॉड्यूल के लिए, एओटी-कंपाइलेशन पूरी तरह से बंद हो जाता है.
  • कमांड-लाइन से जुड़ी समस्या को तुरंत और सभी के लिए ठीक करने के लिए, एनवायरमेंट वैरिएबल RELAX_USES_LIBRARY_CHECK=true का इस्तेमाल करें. इसका असर PRODUCT_BROKEN_VERIFY_USES_LIBRARIES जैसा ही होता है. हालांकि, इसका इस्तेमाल कमांड-लाइन पर किया जाता है. एनवायरमेंट वैरिएबल, प्रॉडक्ट वैरिएबल को बदल देता है.
  • गड़बड़ी को जड़ से ठीक करने के लिए, बिल्ड सिस्टम को मेनिफ़ेस्ट में मौजूद <uses-library> टैग के बारे में बताएं. गड़बड़ी के मैसेज की जांच करने से पता चलता है कि कौनसी लाइब्रेरी की वजह से समस्या आ रही है. AndroidManifest.xml या APK के अंदर मौजूद मेनिफ़ेस्ट की जांच करने से भी यह पता चलता है. इसकी जांच `aapt dump badging $APK | grep uses-library` से की जा सकती है.

Android.bp मॉड्यूल के लिए:

  1. मॉड्यूल की libs प्रॉपर्टी में जाकर, वह लाइब्रेरी ढूंढें जो मौजूद नहीं है. अगर यह मौजूद है, तो Soong आम तौर पर ऐसी लाइब्रेरी अपने-आप जोड़ देता है. हालांकि, इन खास मामलों में ऐसा नहीं होता:

    • लाइब्रेरी, एसडीके लाइब्रेरी नहीं है. इसे java_sdk_library के बजाय java_library के तौर पर तय किया गया है.
    • लाइब्रेरी के मेनिफ़ेस्ट में मौजूद लाइब्रेरी का नाम, उसके मॉड्यूल के नाम (बिल्ड सिस्टम में) से अलग है.

    इस समस्या को कुछ समय के लिए ठीक करने के लिए, Android.bp लाइब्रेरी की परिभाषा में provides_uses_lib: "<library-name>" जोड़ें. समस्या को हमेशा के लिए ठीक करने के लिए, इसकी वजह को ठीक करें: लाइब्रेरी को एसडीके लाइब्रेरी में बदलें या उसके मॉड्यूल का नाम बदलें.

  2. अगर पिछले चरण से समस्या हल नहीं हुई, तो ज़रूरी लाइब्रेरी के लिए uses_libs: ["<library-module-name>"] या वैकल्पिक लाइब्रेरी के लिए optional_uses_libs: ["<library-module-name>"] को मॉड्यूल की Android.bp परिभाषा में जोड़ें. ये प्रॉपर्टी, मॉड्यूल के नामों की सूची स्वीकार करती हैं. सूची में शामिल लाइब्रेरी का क्रम, मेनिफ़ेस्ट में दिए गए क्रम के मुताबिक होना चाहिए.

Android.mk मॉड्यूल के लिए:

  1. देखें कि लाइब्रेरी का नाम, मेनिफ़ेस्ट में मौजूद नाम से अलग तो नहीं है. साथ ही, देखें कि लाइब्रेरी का नाम, बिल्ड सिस्टम में मौजूद नाम से अलग तो नहीं है. अगर ऐसा होता है, तो लाइब्रेरी की Android.mk फ़ाइल में LOCAL_PROVIDES_USES_LIBRARY := <library-name> जोड़कर, इस समस्या को कुछ समय के लिए ठीक करें. इसके अलावा, लाइब्रेरी की Android.bp फ़ाइल में provides_uses_lib: "<library-name>" जोड़कर भी इस समस्या को ठीक किया जा सकता है. दोनों ही तरीके इस्तेमाल किए जा सकते हैं, क्योंकि हो सकता है कि Android.mk मॉड्यूल, Android.bp लाइब्रेरी पर निर्भर हो. इस समस्या को हमेशा के लिए ठीक करने के लिए, इसकी वजह को ठीक करें: लाइब्रेरी मॉड्यूल का नाम बदलें.

  2. ज़रूरी लाइब्रेरी के लिए LOCAL_USES_LIBRARIES := <library-module-name> जोड़ें. साथ ही, मॉड्यूल की Android.mk डेफ़िनिशन में वैकल्पिक लाइब्रेरी के लिए LOCAL_OPTIONAL_USES_LIBRARIES := <library-module-name> जोड़ें. ये प्रॉपर्टी, मॉड्यूल के नामों की सूची स्वीकार करती हैं. सूची में लाइब्रेरी का क्रम, मेनिफ़ेस्ट फ़ाइल में दिए गए क्रम के मुताबिक होना चाहिए.

बिल्ड करने में गड़बड़ी: लाइब्रेरी का पाथ नहीं मिला

अगर बिल्ड सिस्टम को <uses-library> DEX जार का पाथ नहीं मिलता है, तो आम तौर पर बिल्ड पूरा नहीं हो पाता. पाथ, होस्ट पर बिल्ड-टाइम पाथ या डिवाइस पर इंस्टॉल पाथ हो सकता है. रास्ता न मिलने का मतलब यह हो सकता है कि लाइब्रेरी को किसी अनचाहे तरीके से कॉन्फ़िगर किया गया है. समस्या वाले मॉड्यूल के लिए dexpreopt को बंद करके, बिल्ड को कुछ समय के लिए ठीक करें.

Android.bp (मॉड्यूल प्रॉपर्टी):

enforce_uses_libs: false,
dex_preopt: {
    enabled: false,
},

Android.mk (मॉड्यूल वैरिएबल):

LOCAL_ENFORCE_USES_LIBRARIES := false
LOCAL_DEX_PREOPT := false

काम न करने वाले किसी भी उदाहरण की जांच करने के लिए, गड़बड़ी की रिपोर्ट दर्ज करें.

बिल्ड करने में गड़बड़ी: लाइब्रेरी की डिपेंडेंसी मौजूद नहीं है

मॉड्यूल Y के मेनिफ़ेस्ट से <uses-library> X को Y के बिल्ड फ़ाइल में जोड़ने की कोशिश करने पर, बिल्ड में गड़बड़ी हो सकती है. ऐसा इसलिए, क्योंकि 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> एंट्री com.android.X है, लेकिन लाइब्रेरी मॉड्यूल का नाम सिर्फ़ X है, तो इससे गड़बड़ी होती है. इस समस्या को हल करने के लिए, बिल्ड सिस्टम को बताएं कि X नाम वाला मॉड्यूल, com.android.X नाम का <uses-library> उपलब्ध कराता है.

यह Android.bp लाइब्रेरी (मॉड्यूल प्रॉपर्टी) का उदाहरण है:

provides_uses_lib: “com.android.X”,

यह Android.mk लाइब्रेरी (मॉड्यूल वैरिएबल) का उदाहरण है:

LOCAL_PROVIDES_USES_LIBRARY := com.android.X

बूट-टाइम सीएलसी मेल नहीं खाता

पहले बूट पर, 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: ...

अगर आपको सीएलसी के मेल न खाने की चेतावनी मिलती है, तो गड़बड़ी वाले मॉड्यूल के लिए dexopt कमांड ढूंढें. इसे ठीक करने के लिए, पक्का करें कि मॉड्यूल के लिए बिल्ड-टाइम की जांच पास हो गई हो. अगर इससे समस्या ठीक नहीं होती है, तो हो सकता है कि आपका ऐप्लिकेशन ऐसा हो जो बिल्ड सिस्टम के साथ काम नहीं करता. जैसे, ऐसा ऐप्लिकेशन जो लाइब्रेरी के बजाय किसी दूसरे APK को लोड करता है. बिल्ड सिस्टम सभी मामलों को हैंडल नहीं करता है, क्योंकि बिल्ड टाइम पर यह पता नहीं लगाया जा सकता कि ऐप्लिकेशन, रनटाइम पर क्या लोड करता है.

क्लास लोडर कॉन्टेक्स्ट

सीएलसी, ट्री जैसी संरचना होती है. यह क्लास-लोडर हैरारकी के बारे में बताता है. बिल्ड सिस्टम, CLC का इस्तेमाल सीमित तौर पर करता है. इसमें सिर्फ़ लाइब्रेरी शामिल होती हैं, APK या कस्टम-क्लास लोडर नहीं. यह लाइब्रेरी का एक ट्री होता है, जो किसी लाइब्रेरी या ऐप्लिकेशन की सभी <uses-library> डिपेंडेंसी के ट्रांज़िटिव क्लोज़र को दिखाता है. CLC के टॉप लेवल के एलिमेंट, मेनिफ़ेस्ट (क्लाथपाथ) में बताई गई डायरेक्ट <uses-library> डिपेंडेंसी होती हैं. सीएलसी ट्री का हर नोड एक <uses-library> नोड होता है. इसमें अपने <uses-library> सब-नोड हो सकते हैं.

<uses-library> डिपेंडेंसी, डायरेक्टेड एसाइक्लिक ग्राफ़ होती हैं. ये ज़रूरी नहीं कि ट्री हों. इसलिए, सीएलसी में एक ही लाइब्रेरी के लिए कई सबट्री हो सकते हैं. दूसरे शब्दों में कहें, तो सीएलसी, डिपेंडेंसी ग्राफ़ को "अनफ़ोल्ड" करके ट्री में बदलता है. डुप्लीकेट सिर्फ़ लॉजिकल लेवल पर होता है. असल क्लास लोडर डुप्लीकेट नहीं होते. रनटाइम में, हर लाइब्रेरी के लिए एक क्लास लोडर इंस्टेंस होता है.

सीएलसी, लाइब्रेरी या ऐप्लिकेशन के ज़रिए इस्तेमाल की जाने वाली Java क्लास को हल करते समय, लाइब्रेरी के लुकअप ऑर्डर को तय करता है. लुकअप ऑर्डर इसलिए ज़रूरी है, क्योंकि लाइब्रेरी में डुप्लीकेट क्लास हो सकती हैं. साथ ही, क्लास को पहले मैच के हिसाब से हल किया जाता है.

डिवाइस पर (रन-टाइम) सीएलसी

PackageManager (frameworks/base में) एक सीएलसी बनाता है, ताकि डिवाइस पर Java मॉड्यूल लोड किया जा सके. यह मॉड्यूल के मेनिफ़ेस्ट में मौजूद <uses-library> टैग में दी गई लाइब्रेरी को टॉप-लेवल के सीएलसी एलिमेंट के तौर पर जोड़ता है.

इस्तेमाल की गई हर लाइब्रेरी के लिए, PackageManager को उसकी सभी <uses-library> डिपेंडेंसी मिलती हैं. ये डिपेंडेंसी, उस लाइब्रेरी के मेनिफ़ेस्ट में टैग के तौर पर तय की जाती हैं. साथ ही, PackageManager हर डिपेंडेंसी के लिए एक नेस्ट किया गया सीएलसी जोड़ता है. यह प्रोसेस तब तक दोहराई जाती है, जब तक कि बनाए गए सीएलसी ट्री के सभी लीफ़ नोड, <uses-library> डिपेंडेंसी के बिना लाइब्रेरी न बन जाएं.

PackageManager को सिर्फ़ शेयर की गई लाइब्रेरी के बारे में पता होता है. इस इस्तेमाल में शेयर किए गए का मतलब, इसके सामान्य मतलब (जैसे, शेयर किया गया बनाम स्टैटिक) से अलग है. Android में, Java की शेयर की गई लाइब्रेरी वे होती हैं जो XML कॉन्फ़िगरेशन में शामिल होती हैं. इन्हें डिवाइस पर इंस्टॉल किया जाता है (/system/etc/permissions/platform.xml). हर एंट्री में, शेयर की गई लाइब्रेरी का नाम, उसके DEX जार फ़ाइल का पाथ, और डिपेंडेंसी की सूची होती है. ये ऐसी शेयर की गई लाइब्रेरी होती हैं जिनका इस्तेमाल यह लाइब्रेरी रनटाइम में करती है. साथ ही, यह अपने मेनिफ़ेस्ट में <uses-library> टैग में इसकी जानकारी देती है.

दूसरे शब्दों में कहें, तो PackageManager के पास दो सोर्स से जानकारी मिलती है. इससे वह रनटाइम के दौरान सीएलसी बना पाता है: मेनिफ़ेस्ट में मौजूद <uses-library> टैग और एक्सएमएल कॉन्फ़िगरेशन में शेयर की गई लाइब्रेरी की डिपेंडेंसी.

होस्ट पर (बिल्ड-टाइम) सीएलसी

सीएलसी की ज़रूरत सिर्फ़ लाइब्रेरी या ऐप्लिकेशन लोड करते समय नहीं होती, बल्कि इसे कंपाइल करते समय भी होती है. कंपाइलेशन, डिवाइस पर (dexopt) या बिल्ड के दौरान (dexpreopt) हो सकता है. dexopt की प्रोसेस डिवाइस पर होती है. इसलिए, इसके पास PackageManager (मेनिफ़ेस्ट और शेयर की गई लाइब्रेरी की डिपेंडेंसी) जैसी ही जानकारी होती है. हालांकि, Dexpreopt की प्रोसेस होस्ट पर और पूरी तरह से अलग एनवायरमेंट में होती है. साथ ही, इसे बिल्ड सिस्टम से वही जानकारी मिलती है.

इसलिए, dexpreopt के ज़रिए इस्तेमाल किया गया बिल्ड-टाइम सीएलसी और PackageManager के ज़रिए इस्तेमाल किया गया रन-टाइम सीएलसी एक ही चीज़ है. हालांकि, इनकी गिनती दो अलग-अलग तरीकों से की जाती है.

बिल्ड-टाइम और रन-टाइम CLC एक जैसे होने चाहिए. ऐसा न होने पर, dexpreopt से बनाया गया AOT-कंपाइल किया गया कोड अस्वीकार कर दिया जाता है. बिल्ड-टाइम और रन-टाइम CLC की समानता की जांच करने के लिए, dex2oat कंपाइलर, *.odex फ़ाइलों में बिल्ड-टाइम CLC रिकॉर्ड करता है. यह OAT फ़ाइल हेडर के classpath फ़ील्ड में होता है. सेव किया गया सीएलसी ढूंढने के लिए, इस कमांड का इस्तेमाल करें:

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

बूट के दौरान, logcat में बिल्ड-टाइम और रन-टाइम सीएलसी के मेल न खाने की जानकारी दी जाती है. इसे खोजने के लिए, यह निर्देश इस्तेमाल करें:

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

बेमेल होने से परफ़ॉर्मेंस पर बुरा असर पड़ता है. ऐसा इसलिए, क्योंकि इससे लाइब्रेरी या ऐप्लिकेशन को या तो dexopted करना पड़ता है या बिना ऑप्टिमाइज़ेशन के चलाना पड़ता है. उदाहरण के लिए, ऐप्लिकेशन के कोड को APK से मेमोरी में एक्सट्रैक्ट करना पड़ सकता है, जो एक बहुत महंगा ऑपरेशन है.

शेयर की गई लाइब्रेरी, ज़रूरी या वैकल्पिक हो सकती है. dexpreopt के हिसाब से, ज़रूरी लाइब्रेरी को बिल्ड टाइम में मौजूद होना चाहिए. अगर ऐसा नहीं होता है, तो बिल्ड में गड़बड़ी होती है. बिल्ड के समय, कोई वैकल्पिक लाइब्रेरी मौजूद हो भी सकती है और नहीं भी. अगर मौजूद है, तो उसे सीएलसी में जोड़ा जाता है, dex2oat को पास किया जाता है, और *.odex फ़ाइल में रिकॉर्ड किया जाता है. अगर कोई वैकल्पिक लाइब्रेरी मौजूद नहीं है, तो उसे छोड़ दिया जाता है और CLC में नहीं जोड़ा जाता. अगर बिल्ड-टाइम और रन-टाइम की स्थिति में अंतर होता है (वैकल्पिक लाइब्रेरी एक मामले में मौजूद है, लेकिन दूसरे में नहीं), तो बिल्ड-टाइम और रन-टाइम के सीएलसी मेल नहीं खाते. साथ ही, कंपाइल किए गए कोड को अस्वीकार कर दिया जाता है.

एडवांस बिल्ड सिस्टम की जानकारी (मेनिफ़ेस्ट ठीक करने वाला टूल)

कभी-कभी, लाइब्रेरी या ऐप्लिकेशन के सोर्स मेनिफ़ेस्ट में <uses-library> टैग मौजूद नहीं होते. ऐसा तब हो सकता है, जब लाइब्रेरी या ऐप्लिकेशन की ट्रांज़िटिव डिपेंडेंसी में से कोई एक, किसी दूसरे <uses-library> टैग का इस्तेमाल करना शुरू कर दे. साथ ही, लाइब्रेरी या ऐप्लिकेशन के मेनिफ़ेस्ट को अपडेट न किया गया हो, ताकि उसमें वह टैग शामिल किया जा सके.

Soong, किसी लाइब्रेरी या ऐप्लिकेशन के लिए कुछ छूटे हुए <uses-library> टैग अपने-आप कंप्यूट कर सकता है. ऐसा इसलिए, क्योंकि लाइब्रेरी या ऐप्लिकेशन की ट्रांज़िटिव डिपेंडेंसी क्लोज़र में एसडीके लाइब्रेरी मौजूद होती हैं. क्लोज़र की ज़रूरत इसलिए होती है, क्योंकि लाइब्रेरी (या ऐप्लिकेशन) किसी ऐसी स्टैटिक लाइब्रेरी पर निर्भर हो सकती है जो एसडीके लाइब्रेरी पर निर्भर होती है. साथ ही, यह भी हो सकता है कि वह किसी दूसरी लाइब्रेरी के ज़रिए ट्रांज़िटिव तौर पर फिर से निर्भर हो.

सभी <uses-library> टैग को इस तरह से नहीं जोड़ा जा सकता. हालांकि, जब ऐसा करना मुमकिन हो, तो Soong को मेनिफ़ेस्ट एंट्री अपने-आप जोड़ने की अनुमति देना बेहतर होता है. इससे गड़बड़ी होने की आशंका कम हो जाती है और रखरखाव आसान हो जाता है. उदाहरण के लिए, जब कई ऐप्लिकेशन ऐसी स्टैटिक लाइब्रेरी का इस्तेमाल करते हैं जो नई <uses-library> डिपेंडेंसी जोड़ती है, तो सभी ऐप्लिकेशन को अपडेट करना ज़रूरी होता है. हालांकि, ऐसा करना मुश्किल होता है.