Dexpreopt و <uses-library> چک ها

اندروید 12 دارای تغییرات سیستمی برای کامپایل AOT از فایل های DEX (dexpreopt) برای ماژول های جاوا است که وابستگی های <uses-library> دارند. در برخی موارد، این تغییرات سیستم ساخت می‌تواند ساخت‌ها را خراب کند. از این صفحه برای آماده شدن برای شکستگی ها استفاده کنید و دستور العمل های موجود در این صفحه را برای رفع و کاهش آنها دنبال کنید.

Dexpreopt فرآیند جمع‌آوری پیش از موعد کتابخانه‌ها و برنامه‌های جاوا است. Dexpreopt در زمان ساخت روی هاست اتفاق می افتد (برخلاف دکسوپت که روی دستگاه اتفاق می افتد). ساختار وابستگی های کتابخانه مشترک که توسط یک ماژول جاوا (یک کتابخانه یا یک برنامه) استفاده می شود، به عنوان زمینه بارگذار کلاس (CLC) شناخته می شود. برای تضمین صحت dexpreopt، CLC های زمان ساخت و زمان اجرا باید مطابقت داشته باشند. Build-time CLC چیزی است که کامپایلر dex2oat در زمان dexpreopt استفاده می‌کند (در فایل‌های ODEX ثبت می‌شود)، و CLC زمان اجرا، زمینه‌ای است که در آن کد از پیش کامپایل شده روی دستگاه بارگذاری می‌شود.

این CLC های زمان ساخت و زمان اجرا باید به دلایل صحت و عملکرد مطابقت داشته باشند. برای صحت، لازم است که کلاس های تکراری را مدیریت کنید. اگر وابستگی‌های کتابخانه مشترک در زمان اجرا با وابستگی‌های مورد استفاده برای کامپایل متفاوت باشد، ممکن است برخی از کلاس‌ها به روشی متفاوت حل شوند و باعث ایجاد باگ‌های ظریف در زمان اجرا شوند. عملکرد همچنین تحت تأثیر بررسی های زمان اجرا برای کلاس های تکراری قرار می گیرد.

موارد استفاده تحت تأثیر

اولین بوت مورد استفاده اصلی است که تحت تأثیر این تغییرات قرار می گیرد: اگر ART عدم تطابق بین CLC های زمان ساخت و زمان اجرا را تشخیص دهد، آرتیفکت های dexpreopt را رد می کند و به جای آن dexopt را اجرا می کند. برای بوت های بعدی این کار خوب است زیرا برنامه ها را می توان در پس زمینه حذف کرد و روی دیسک ذخیره کرد.

مناطق آسیب دیده اندروید

این روی همه برنامه‌ها و کتابخانه‌های جاوا که وابستگی زمان اجرا به سایر کتابخانه‌های جاوا دارند، تأثیر می‌گذارد. اندروید هزاران برنامه دارد و صدها مورد از آنها از کتابخانه های مشترک استفاده می کنند. شرکا نیز تحت تأثیر قرار می گیرند، زیرا آنها کتابخانه ها و برنامه های خود را دارند.

تغییرات را بشکنید

سیستم ساخت قبل از ایجاد قوانین ساخت dexpreopt باید وابستگی های <uses-library> را بداند. با این حال، نمی‌تواند مستقیماً به مانیفست دسترسی داشته باشد و تگ‌های <uses-library> را در آن بخواند، زیرا سیستم ساخت اجازه ندارد فایل‌های دلخواه را هنگام ایجاد قوانین ساخت (به دلایل عملکرد) بخواند. علاوه بر این، مانیفست ممکن است در داخل یک APK یا یک پیش ساخته بسته بندی شود. بنابراین، اطلاعات <uses-library> باید در فایل های ساخت ( Android.bp یا Android.mk ) وجود داشته باشد.

قبلاً ART از راه‌حلی استفاده می‌کرد که وابستگی‌های کتابخانه مشترک (معروف به &-classpath ) را نادیده می‌گرفت. این ناامن بود و باگ‌های ظریفی را ایجاد می‌کرد، بنابراین راه‌حل در Android 12 حذف شد.

در نتیجه، ماژول‌های جاوا که اطلاعات <uses-library> صحیح را در فایل‌های ساخت خود ارائه نمی‌کنند، می‌توانند باعث خرابی ساخت (ناشی از عدم تطابق CLC در زمان ساخت) یا رگرسیون زمان اولین راه‌اندازی (ناشی از CLC در زمان بوت) شوند. عدم تطابق و به دنبال آن دکسوپت).

مسیر مهاجرت

مراحل زیر را برای تعمیر یک ساختمان شکسته دنبال کنید:

  1. با تنظیم، بررسی زمان ساخت را برای یک محصول خاص غیرفعال کنید

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    در فایل ساخت محصول این کار خطاهای ساخت (به جز موارد خاص که در بخش Fixing breakages ذکر شده است) را برطرف می کند. با این حال، این یک راه‌حل موقت است و می‌تواند باعث عدم تطابق CLC در زمان راه‌اندازی و سپس dexopt شود.

  2. با افزودن اطلاعات <uses-library> لازم به فایل‌های ساخت آن‌ها، ماژول‌هایی را که قبل از غیرفعال کردن سراسری بررسی زمان ساخت شکست خورده‌اند، برطرف کنید (برای جزئیات به رفع شکستگی‌ها مراجعه کنید). برای اکثر ماژول ها این نیاز به افزودن چند خط در Android.bp یا Android.mk دارد.

  3. بررسی زمان ساخت را غیرفعال کنید و موارد مشکل‌ساز را بر اساس هر ماژول بازپس بگیرید. dexpreopt را غیرفعال کنید تا زمان ساخت و ذخیره سازی را برای مصنوعاتی که در هنگام بوت رد می شوند هدر ندهید.

  4. با لغو تنظیمات PRODUCT_BROKEN_VERIFY_USES_LIBRARIES که در مرحله 1 تنظیم شده بود، بررسی زمان ساخت را مجدداً فعال کنید. ساخت نباید بعد از این تغییر (به دلیل مراحل 2 و 3) شکست بخورد.

  5. ماژول هایی را که در مرحله 3 غیرفعال کرده اید، یکی یکی برطرف کنید، سپس dexpreopt و تیک <uses-library> را دوباره فعال کنید. در صورت لزوم باگ ها را پر کنید.

بررسی‌های <uses-library> در زمان ساخت در Android 12 اعمال می‌شوند.

شکستگی ها را برطرف کنید

بخش های زیر به شما می گویند که چگونه انواع خاصی از شکستگی را برطرف کنید.

خطای ساخت: عدم تطابق CLC

سیستم ساخت یک بررسی هماهنگی زمان ساخت بین اطلاعات موجود در فایل‌های 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 را برای verify در dexpreopt کاهش دهد، که کامپایل AOT را به طور کامل برای این ماژول غیرفعال می‌کند.
  • برای رفع سریع و کلی خط فرمان ، از متغیر محیطی 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 معمولاً چنین کتابخانه‌هایی را به‌طور خودکار اضافه می‌کند، مگر در موارد خاص:

    • این کتابخانه یک کتابخانه SDK نیست (به جای java_sdk_library به عنوان java_library تعریف شده است).
    • کتابخانه نام کتابخانه متفاوتی (در مانیفست) با نام ماژول خود (در سیستم ساخت) دارد.

    برای رفع موقت این مشکل، provides_uses_lib: "<library-name>" را در تعریف کتابخانه Android.bp اضافه کنید. برای یک راه حل طولانی مدت، مشکل اساسی را برطرف کنید: کتابخانه را به کتابخانه SDK تبدیل کنید یا ماژول آن را تغییر نام دهید.

  2. اگر مرحله قبل وضوحی ارائه نکرد، uses_libs: ["<library-module-name>"] را برای کتابخانه های مورد نیاز، یا optional_uses_libs: ["<library-module-name>"] را برای کتابخانه های اختیاری به Android.bp تعریف ماژول. این ویژگی ها لیستی از نام ماژول ها را می پذیرند. ترتیب نسبی کتابخانه‌های موجود در فهرست باید مانند ترتیب در مانیفست باشد.

برای ماژول های Android.mk :

  1. بررسی کنید که آیا کتابخانه نام کتابخانه متفاوتی (در مانیفست) با نام ماژول آن (در سیستم ساخت) دارد یا خیر. اگر این کار را کرد، با افزودن LOCAL_PROVIDES_USES_LIBRARY := <library-name> در فایل Android.mk کتابخانه، موقتاً این مشکل را برطرف کنید، یا provides_uses_lib: "<library-name>" در فایل Android.bp کتابخانه (هر دو مورد) این امکان وجود دارد زیرا یک ماژول Android.mk ممکن است به کتابخانه Android.bp بستگی داشته باشد. برای یک راه حل طولانی مدت، مشکل اساسی را برطرف کنید: نام ماژول کتابخانه را تغییر دهید.

  2. LOCAL_USES_LIBRARIES := <library-module-name> را برای کتابخانه های مورد نیاز اضافه کنید. LOCAL_OPTIONAL_USES_LIBRARIES := <library-module-name> را برای کتابخانه های اختیاری به تعریف Android.mk ماژول اضافه کنید. این ویژگی ها لیستی از نام ماژول ها را می پذیرند. ترتیب نسبی کتابخانه ها در لیست باید مانند مانیفست باشد.

خطای ساخت: مسیر کتابخانه ناشناخته

اگر سیستم ساخت نتواند مسیری برای یک <uses-library> jar DEX پیدا کند (یا مسیر زمان ساخت در میزبان یا مسیر نصب روی دستگاه)، معمولاً ساخت را با شکست مواجه می‌کند. عدم یافتن مسیر می تواند نشان دهنده پیکربندی کتابخانه به روشی غیرمنتظره باشد. با غیرفعال کردن 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 از مانیفست ماژول Y به فایل ساخت 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 یک <uses-library> به نام com.android.X را ارائه می دهد.

این یک مثال برای کتابخانه های Android.bp (ویژگی ماژول) است:

provides_uses_lib: “com.android.X”,

این یک مثال برای کتابخانه های Android.mk (متغیر ماژول) است:

LOCAL_PROVIDES_USES_LIBRARY := com.android.X

عدم تطابق CLC در زمان راه اندازی

در ابتدا، logcat را برای پیام های مربوط به عدم تطابق CLC جستجو کنید، همانطور که در زیر نشان داده شده است:

$ 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 یک ساختار درخت مانند است که سلسله مراتب کلاس-لودر را توصیف می کند. سیستم ساخت از CLC به معنای محدود استفاده می‌کند (فقط کتابخانه‌ها را پوشش می‌دهد، نه APK یا بارکننده‌های کلاس سفارشی): این درختی از کتابخانه‌ها است که بسته شدن موقت همه وابستگی‌های <uses-library> یک کتابخانه یا برنامه را نشان می‌دهد. عناصر سطح بالای یک CLC وابستگی های مستقیم <uses-library> هستند که در مانیفست (مسیر کلاس) مشخص شده اند. هر گره درخت CLC یک گره <uses-library> است که ممکن است زیرگره های <uses-library> خود را داشته باشد.

از آنجا که وابستگی‌های <uses-library> یک گراف غیر چرخه‌ای جهت‌دار هستند و لزوماً یک درخت نیستند، CLC می‌تواند شامل چندین زیردرخت برای یک کتابخانه باشد. به عبارت دیگر، CLC نمودار وابستگی است که به یک درخت "باز شده" است. تکرار فقط در سطح منطقی است. بارگذارهای کلاس اصلی واقعی تکراری نیستند (در زمان اجرا یک نمونه بارکننده کلاس برای هر کتابخانه وجود دارد).

CLC ترتیب جستجوی کتابخانه ها را هنگام حل کلاس های جاوا که توسط کتابخانه یا برنامه استفاده می شود را تعیین می کند. ترتیب جستجو مهم است زیرا کتابخانه ها می توانند دارای کلاس های تکراری باشند و کلاس به اولین تطابق حل می شود.

روی دستگاه (زمان اجرا) CLC

PackageManager (در frameworks/base ) یک CLC برای بارگذاری یک ماژول جاوا بر روی دستگاه ایجاد می کند. کتابخانه های فهرست شده در تگ های <uses-library> در مانیفست ماژول را به عنوان عناصر CLC سطح بالا اضافه می کند.

برای هر کتابخانه استفاده شده، PackageManager تمام وابستگی های <uses-library> خود را دریافت می کند (که به عنوان برچسب در مانیفست آن کتابخانه مشخص شده است) و یک CLC تودرتو برای هر وابستگی اضافه می کند. این فرآیند به صورت بازگشتی ادامه می‌یابد تا زمانی که تمام گره‌های برگ درخت CLC ساخته شده، کتابخانه‌هایی بدون وابستگی <uses-library> باشند.

PackageManager فقط از کتابخانه های مشترک آگاه است. تعریف اشتراک‌گذاری در این کاربرد با معنای معمول آن (مانند اشتراک‌گذاری در مقابل استاتیک) متفاوت است. در Android، کتابخانه‌های مشترک جاوا آنهایی هستند که در پیکربندی‌های XML فهرست شده‌اند که روی دستگاه نصب می‌شوند ( /system/etc/permissions/platform.xml ). هر ورودی حاوی نام یک کتابخانه مشترک، مسیری به فایل jar DEX آن، و لیستی از وابستگی ها است (دیگر کتابخانه های مشترکی که این یکی در زمان اجرا استفاده می کند، و در تگ های <uses-library> در مانیفست خود مشخص می کند).

به عبارت دیگر، دو منبع اطلاعاتی وجود دارد که به PackageManager اجازه می‌دهد تا CLC را در زمان اجرا بسازد: تگ‌های <uses-library> در مانیفست، و وابستگی‌های کتابخانه مشترک در تنظیمات XML.

CLC روی میزبان (زمان ساخت).

CLC نه تنها هنگام بارگذاری یک کتابخانه یا یک برنامه مورد نیاز است، بلکه در هنگام کامپایل نیز مورد نیاز است. کامپایل می تواند روی دستگاه (dexopt) یا در حین ساخت (dexpreopt) اتفاق بیفتد. از آنجایی که dexopt روی دستگاه انجام می‌شود، اطلاعاتی مشابه با PackageManager (وابستگی‌های کتابخانه‌ای آشکار و مشترک) دارد. با این حال، Dexpreopt روی هاست و در محیطی کاملاً متفاوت انجام می شود و باید همان اطلاعات را از سیستم ساخت دریافت کند.

بنابراین، CLC زمان ساخت که توسط dexpreopt استفاده می‌شود و CLC زمان اجرا که توسط PackageManager استفاده می‌شود یکسان هستند، اما به دو روش متفاوت محاسبه می‌شوند.

CLC های زمان ساخت و زمان اجرا باید مطابق باشند، در غیر این صورت کد کامپایل شده توسط AOT ایجاد شده توسط dexpreopt رد می شود. برای بررسی برابری CLC های زمان ساخت و زمان اجرا، کامپایلر dex2oat CLC زمان ساخت را در فایل های *.odex (در قسمت classpath سربرگ فایل OAT) ثبت می کند. برای پیدا کردن CLC ذخیره شده، از این دستور استفاده کنید:

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

عدم تطابق CLC زمان ساخت و زمان اجرا در logcat در هنگام بوت گزارش می شود. با این دستور آن را جستجو کنید:

logcat | grep -E 'ClassLoaderContext [az ]+ mismatch'

عدم تطابق برای عملکرد بد است، زیرا کتابخانه یا برنامه را مجبور می‌کند که حذف شود یا بدون بهینه‌سازی اجرا شود (برای مثال، ممکن است نیاز باشد کد برنامه در حافظه از APK استخراج شود، یک عملیات بسیار گران‌قیمت).

یک کتابخانه مشترک می تواند اختیاری یا ضروری باشد. از نقطه نظر dexpreopt، یک کتابخانه مورد نیاز باید در زمان ساخت وجود داشته باشد (عدم وجود آن یک خطای ساخت است). یک کتابخانه اختیاری می تواند در زمان ساخت وجود داشته باشد یا وجود نداشته باشد: در صورت وجود، به CLC اضافه می شود، به dex2oat منتقل می شود و در فایل *.odex ثبت می شود. اگر یک کتابخانه اختیاری وجود نداشته باشد، از آن صرفنظر می شود و به CLC اضافه نمی شود. اگر بین وضعیت زمان ساخت و زمان اجرا عدم تطابق وجود داشته باشد (کتابخانه اختیاری در یک مورد وجود دارد، اما در مورد دیگر وجود ندارد)، CLC های زمان ساخت و زمان اجرا مطابقت ندارند و کد کامپایل شده رد می شود.

جزئیات سیستم ساخت پیشرفته (تعیین کننده مانیفست)

گاهی اوقات تگ های <uses-library> در مانیفست منبع کتابخانه یا برنامه وجود ندارد. برای مثال، اگر یکی از وابستگی‌های گذرای کتابخانه یا برنامه شروع به استفاده از تگ <uses-library> دیگری کند و مانیفست کتابخانه یا برنامه برای گنجاندن آن به‌روزرسانی نشود، این اتفاق می‌افتد.

Soong می‌تواند برخی از برچسب‌های <uses-library> گمشده را برای یک کتابخانه یا برنامه به طور خودکار محاسبه کند، همانطور که کتابخانه‌های SDK در بسته شدن وابستگی انتقالی کتابخانه یا برنامه. بسته شدن لازم است زیرا ممکن است کتابخانه (یا برنامه) به کتابخانه ایستا وابسته به کتابخانه SDK بستگی داشته باشد، و احتمالاً ممکن است دوباره به صورت گذرا از طریق کتابخانه دیگری وابسته باشد.

همه تگ‌های <uses-library> را نمی‌توان با این روش محاسبه کرد، اما در صورت امکان، ترجیح داده می‌شود به Soong اجازه دهید ورودی‌های مانیفست را به صورت خودکار اضافه کند. کمتر مستعد خطا است و تعمیر و نگهداری را ساده می کند. به عنوان مثال، هنگامی که بسیاری از برنامه‌ها از یک کتابخانه ثابت استفاده می‌کنند که یک وابستگی جدید <uses-library> اضافه می‌کند، همه برنامه‌ها باید به‌روزرسانی شوند، که نگهداری آن دشوار است.

،

اندروید 12 دارای تغییرات سیستمی برای کامپایل AOT از فایل های DEX (dexpreopt) برای ماژول های جاوا است که وابستگی های <uses-library> دارند. در برخی موارد، این تغییرات سیستم ساخت می‌تواند ساخت‌ها را خراب کند. از این صفحه برای آماده شدن برای شکستگی ها استفاده کنید و دستور العمل های موجود در این صفحه را برای رفع و کاهش آنها دنبال کنید.

Dexpreopt فرآیند جمع‌آوری پیش از موعد کتابخانه‌ها و برنامه‌های جاوا است. Dexpreopt در زمان ساخت روی هاست اتفاق می افتد (برخلاف دکسوپت که روی دستگاه اتفاق می افتد). ساختار وابستگی های کتابخانه مشترک که توسط یک ماژول جاوا (یک کتابخانه یا یک برنامه) استفاده می شود، به عنوان زمینه بارگذار کلاس (CLC) شناخته می شود. برای تضمین صحت dexpreopt، CLC های زمان ساخت و زمان اجرا باید مطابقت داشته باشند. Build-time CLC چیزی است که کامپایلر dex2oat در زمان dexpreopt استفاده می‌کند (در فایل‌های ODEX ثبت می‌شود)، و CLC زمان اجرا، زمینه‌ای است که در آن کد از پیش کامپایل شده روی دستگاه بارگذاری می‌شود.

این CLC های زمان ساخت و زمان اجرا باید به دلایل صحت و عملکرد مطابقت داشته باشند. برای صحت، لازم است که کلاس های تکراری را مدیریت کنید. اگر وابستگی‌های کتابخانه مشترک در زمان اجرا با وابستگی‌های مورد استفاده برای کامپایل متفاوت باشد، ممکن است برخی از کلاس‌ها به روشی متفاوت حل شوند و باعث ایجاد باگ‌های ظریف در زمان اجرا شوند. عملکرد همچنین تحت تأثیر بررسی های زمان اجرا برای کلاس های تکراری قرار می گیرد.

موارد استفاده تحت تأثیر

اولین بوت مورد استفاده اصلی است که تحت تأثیر این تغییرات قرار می گیرد: اگر ART عدم تطابق بین CLC های زمان ساخت و زمان اجرا را تشخیص دهد، آرتیفکت های dexpreopt را رد می کند و به جای آن dexopt را اجرا می کند. برای بوت های بعدی این کار خوب است زیرا برنامه ها را می توان در پس زمینه حذف کرد و روی دیسک ذخیره کرد.

مناطق آسیب دیده اندروید

این روی همه برنامه‌ها و کتابخانه‌های جاوا که وابستگی زمان اجرا به سایر کتابخانه‌های جاوا دارند، تأثیر می‌گذارد. اندروید هزاران برنامه دارد و صدها مورد از آنها از کتابخانه های مشترک استفاده می کنند. شرکا نیز تحت تأثیر قرار می گیرند، زیرا آنها کتابخانه ها و برنامه های خود را دارند.

تغییرات را بشکنید

سیستم ساخت قبل از ایجاد قوانین ساخت dexpreopt باید وابستگی های <uses-library> را بداند. با این حال، نمی‌تواند مستقیماً به مانیفست دسترسی داشته باشد و تگ‌های <uses-library> را در آن بخواند، زیرا سیستم ساخت اجازه ندارد فایل‌های دلخواه را هنگام ایجاد قوانین ساخت (به دلایل عملکرد) بخواند. علاوه بر این، مانیفست ممکن است در داخل یک APK یا یک پیش ساخته بسته بندی شود. بنابراین، اطلاعات <uses-library> باید در فایل های ساخت ( Android.bp یا Android.mk ) وجود داشته باشد.

قبلاً ART از راه‌حلی استفاده می‌کرد که وابستگی‌های کتابخانه مشترک (معروف به &-classpath ) را نادیده می‌گرفت. این ناامن بود و باگ‌های ظریفی را ایجاد می‌کرد، بنابراین راه‌حل در Android 12 حذف شد.

در نتیجه، ماژول‌های جاوا که اطلاعات <uses-library> صحیح را در فایل‌های ساخت خود ارائه نمی‌کنند، می‌توانند باعث خرابی ساخت (ناشی از عدم تطابق CLC در زمان ساخت) یا رگرسیون زمان اولین راه‌اندازی (ناشی از CLC در زمان بوت) شوند. عدم تطابق و به دنبال آن دکسوپت).

مسیر مهاجرت

مراحل زیر را برای تعمیر یک ساختمان شکسته دنبال کنید:

  1. با تنظیم، بررسی زمان ساخت را برای یک محصول خاص غیرفعال کنید

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    در فایل ساخت محصول این کار خطاهای ساخت (به جز موارد خاص که در بخش Fixing breakages ذکر شده است) را برطرف می کند. با این حال، این یک راه‌حل موقت است و می‌تواند باعث عدم تطابق CLC در زمان راه‌اندازی و سپس dexopt شود.

  2. با افزودن اطلاعات <uses-library> لازم به فایل‌های ساخت آن‌ها، ماژول‌هایی را که قبل از غیرفعال کردن سراسری بررسی زمان ساخت شکست خورده‌اند، برطرف کنید (برای جزئیات به رفع شکستگی‌ها مراجعه کنید). برای اکثر ماژول ها این نیاز به افزودن چند خط در Android.bp یا Android.mk دارد.

  3. بررسی زمان ساخت را غیرفعال کنید و موارد مشکل‌ساز را بر اساس هر ماژول بازپس بگیرید. dexpreopt را غیرفعال کنید تا زمان ساخت و ذخیره سازی را برای مصنوعاتی که در هنگام بوت رد می شوند هدر ندهید.

  4. با لغو تنظیمات PRODUCT_BROKEN_VERIFY_USES_LIBRARIES که در مرحله 1 تنظیم شده بود، بررسی زمان ساخت را مجدداً فعال کنید. ساخت نباید بعد از این تغییر (به دلیل مراحل 2 و 3) شکست بخورد.

  5. ماژول هایی را که در مرحله 3 غیرفعال کرده اید، یکی یکی برطرف کنید، سپس dexpreopt و تیک <uses-library> را دوباره فعال کنید. در صورت لزوم باگ ها را پر کنید.

بررسی‌های <uses-library> در زمان ساخت در Android 12 اعمال می‌شوند.

شکستگی ها را رفع کنید

بخش های زیر به شما می گویند که چگونه انواع خاصی از شکستگی را برطرف کنید.

خطای ساخت: عدم تطابق CLC

سیستم ساخت یک بررسی هماهنگی زمان ساخت بین اطلاعات موجود در فایل‌های 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 را برای verify در dexpreopt کاهش دهد، که کامپایل AOT را به طور کامل برای این ماژول غیرفعال می‌کند.
  • برای رفع سریع و کلی خط فرمان ، از متغیر محیطی 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 معمولاً چنین کتابخانه‌هایی را به‌طور خودکار اضافه می‌کند، مگر در موارد خاص:

    • این کتابخانه یک کتابخانه SDK نیست (به جای java_sdk_library به عنوان java_library تعریف شده است).
    • کتابخانه نام کتابخانه متفاوتی (در مانیفست) با نام ماژول خود (در سیستم ساخت) دارد.

    برای رفع موقت این مشکل، provides_uses_lib: "<library-name>" را در تعریف کتابخانه Android.bp اضافه کنید. برای یک راه حل طولانی مدت، مشکل اساسی را برطرف کنید: کتابخانه را به کتابخانه SDK تبدیل کنید یا ماژول آن را تغییر نام دهید.

  2. اگر مرحله قبل وضوحی ارائه نکرد، uses_libs: ["<library-module-name>"] را برای کتابخانه های مورد نیاز، یا optional_uses_libs: ["<library-module-name>"] را برای کتابخانه های اختیاری به Android.bp تعریف ماژول. این ویژگی ها لیستی از نام ماژول ها را می پذیرند. ترتیب نسبی کتابخانه‌های موجود در فهرست باید مانند ترتیب در مانیفست باشد.

برای ماژول های Android.mk :

  1. بررسی کنید که آیا کتابخانه نام کتابخانه متفاوتی (در مانیفست) با نام ماژول آن (در سیستم ساخت) دارد یا خیر. اگر این کار را کرد، با افزودن LOCAL_PROVIDES_USES_LIBRARY := <library-name> در فایل Android.mk کتابخانه، موقتاً این مشکل را برطرف کنید، یا provides_uses_lib: "<library-name>" در فایل Android.bp کتابخانه (هر دو مورد) این امکان وجود دارد زیرا یک ماژول Android.mk ممکن است به کتابخانه Android.bp بستگی داشته باشد. برای یک راه حل طولانی مدت، مشکل اساسی را برطرف کنید: نام ماژول کتابخانه را تغییر دهید.

  2. LOCAL_USES_LIBRARIES := <library-module-name> را برای کتابخانه های مورد نیاز اضافه کنید. LOCAL_OPTIONAL_USES_LIBRARIES := <library-module-name> را برای کتابخانه های اختیاری به تعریف Android.mk ماژول اضافه کنید. این ویژگی ها لیستی از نام ماژول ها را می پذیرند. ترتیب نسبی کتابخانه ها در لیست باید مانند مانیفست باشد.

خطای ساخت: مسیر کتابخانه ناشناخته

اگر سیستم ساخت نتواند مسیری برای یک <uses-library> jar DEX پیدا کند (یا مسیر زمان ساخت در میزبان یا مسیر نصب روی دستگاه)، معمولاً ساخت را با شکست مواجه می‌کند. عدم یافتن یک مسیر می تواند نشان دهنده این باشد که کتابخانه به روشی غیرمنتظره پیکربندی شده است. با غیرفعال کردن 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 از مانیفست ماژول Y به فایل ساخت 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 یک <uses-library> به نام com.android.X را ارائه می دهد.

این یک مثال برای کتابخانه های Android.bp (ویژگی ماژول) است:

provides_uses_lib: “com.android.X”,

این یک مثال برای کتابخانه های Android.mk (متغیر ماژول) است:

LOCAL_PROVIDES_USES_LIBRARY := com.android.X

عدم تطابق CLC در زمان راه اندازی

در ابتدا، logcat را برای پیام های مربوط به عدم تطابق CLC جستجو کنید، همانطور که در زیر نشان داده شده است:

$ 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 یک ساختار درخت مانند است که سلسله مراتب کلاس-لودر را توصیف می کند. سیستم ساخت از CLC به معنای محدود استفاده می‌کند (فقط کتابخانه‌ها را پوشش می‌دهد، نه APK یا بارکننده‌های کلاس سفارشی): این درختی از کتابخانه‌ها است که بسته شدن موقت همه وابستگی‌های <uses-library> یک کتابخانه یا برنامه را نشان می‌دهد. عناصر سطح بالای یک CLC وابستگی های مستقیم <uses-library> هستند که در مانیفست (مسیر کلاس) مشخص شده اند. هر گره درخت CLC یک گره <uses-library> است که ممکن است زیرگره های <uses-library> خود را داشته باشد.

از آنجا که وابستگی‌های <uses-library> یک گراف غیر چرخه‌ای جهت‌دار هستند و لزوماً یک درخت نیستند، CLC می‌تواند شامل چندین زیردرخت برای یک کتابخانه باشد. به عبارت دیگر، CLC نمودار وابستگی است که به یک درخت "باز شده" است. تکرار فقط در سطح منطقی است. بارگذارهای کلاس اصلی واقعی تکراری نیستند (در زمان اجرا یک نمونه بارکننده کلاس برای هر کتابخانه وجود دارد).

CLC ترتیب جستجوی کتابخانه ها را هنگام حل کلاس های جاوا که توسط کتابخانه یا برنامه استفاده می شود را تعیین می کند. ترتیب جستجو مهم است زیرا کتابخانه ها می توانند دارای کلاس های تکراری باشند و کلاس به اولین تطابق حل می شود.

روی دستگاه (زمان اجرا) CLC

PackageManager (در frameworks/base ) یک CLC برای بارگذاری یک ماژول جاوا بر روی دستگاه ایجاد می کند. کتابخانه های فهرست شده در تگ های <uses-library> در مانیفست ماژول را به عنوان عناصر CLC سطح بالا اضافه می کند.

برای هر کتابخانه استفاده شده، PackageManager تمام وابستگی های <uses-library> خود را دریافت می کند (که به عنوان برچسب در مانیفست آن کتابخانه مشخص شده است) و یک CLC تودرتو برای هر وابستگی اضافه می کند. این فرآیند به صورت بازگشتی ادامه می‌یابد تا زمانی که تمام گره‌های برگ درخت CLC ساخته شده، کتابخانه‌هایی بدون وابستگی <uses-library> باشند.

PackageManager فقط از کتابخانه های مشترک آگاه است. تعریف اشتراک‌گذاری در این کاربرد با معنای معمول آن (مانند اشتراک‌گذاری در مقابل استاتیک) متفاوت است. در Android، کتابخانه‌های مشترک جاوا آنهایی هستند که در پیکربندی‌های XML فهرست شده‌اند که روی دستگاه نصب می‌شوند ( /system/etc/permissions/platform.xml ). هر ورودی حاوی نام یک کتابخانه مشترک، مسیری به فایل jar DEX آن، و لیستی از وابستگی ها است (دیگر کتابخانه های مشترکی که این یکی در زمان اجرا استفاده می کند، و در تگ های <uses-library> در مانیفست خود مشخص می کند).

به عبارت دیگر، دو منبع اطلاعاتی وجود دارد که به PackageManager اجازه می‌دهد تا CLC را در زمان اجرا بسازد: تگ‌های <uses-library> در مانیفست، و وابستگی‌های کتابخانه مشترک در تنظیمات XML.

CLC روی میزبان (زمان ساخت).

CLC نه تنها هنگام بارگذاری یک کتابخانه یا یک برنامه مورد نیاز است، بلکه در هنگام کامپایل نیز مورد نیاز است. کامپایل می تواند روی دستگاه (dexopt) یا در حین ساخت (dexpreopt) اتفاق بیفتد. از آنجایی که dexopt روی دستگاه انجام می‌شود، اطلاعاتی مشابه با PackageManager (وابستگی‌های کتابخانه‌ای آشکار و مشترک) دارد. با این حال، Dexpreopt روی هاست و در محیطی کاملاً متفاوت انجام می شود و باید همان اطلاعات را از سیستم ساخت دریافت کند.

بنابراین، CLC زمان ساخت که توسط dexpreopt استفاده می‌شود و CLC زمان اجرا که توسط PackageManager استفاده می‌شود یکسان هستند، اما به دو روش متفاوت محاسبه می‌شوند.

CLC های زمان ساخت و زمان اجرا باید مطابق باشند، در غیر این صورت کد کامپایل شده توسط AOT ایجاد شده توسط dexpreopt رد می شود. برای بررسی برابری CLC های زمان ساخت و زمان اجرا، کامپایلر dex2oat CLC زمان ساخت را در فایل های *.odex (در قسمت classpath سربرگ فایل OAT) ثبت می کند. برای پیدا کردن CLC ذخیره شده، از این دستور استفاده کنید:

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

عدم تطابق CLC زمان ساخت و زمان اجرا در logcat در هنگام بوت گزارش می شود. با این دستور آن را جستجو کنید:

logcat | grep -E 'ClassLoaderContext [az ]+ mismatch'

عدم تطابق برای عملکرد بد است، زیرا کتابخانه یا برنامه را مجبور می‌کند که حذف شود یا بدون بهینه‌سازی اجرا شود (برای مثال، ممکن است نیاز باشد کد برنامه در حافظه از APK استخراج شود، یک عملیات بسیار گران‌قیمت).

یک کتابخانه مشترک می تواند اختیاری یا ضروری باشد. از نقطه نظر dexpreopt، یک کتابخانه مورد نیاز باید در زمان ساخت وجود داشته باشد (عدم وجود آن یک خطای ساخت است). یک کتابخانه اختیاری می تواند در زمان ساخت وجود داشته باشد یا وجود نداشته باشد: در صورت وجود، به CLC اضافه می شود، به dex2oat منتقل می شود و در فایل *.odex ثبت می شود. اگر یک کتابخانه اختیاری وجود نداشته باشد، از آن صرفنظر می شود و به CLC اضافه نمی شود. اگر بین وضعیت زمان ساخت و زمان اجرا عدم تطابق وجود داشته باشد (کتابخانه اختیاری در یک مورد وجود دارد، اما در مورد دیگر وجود ندارد)، CLC های زمان ساخت و زمان اجرا مطابقت ندارند و کد کامپایل شده رد می شود.

جزئیات سیستم ساخت پیشرفته (تعیین کننده مانیفست)

گاهی اوقات تگ های <uses-library> در مانیفست منبع کتابخانه یا برنامه وجود ندارد. برای مثال، اگر یکی از وابستگی‌های گذرای کتابخانه یا برنامه شروع به استفاده از تگ <uses-library> دیگری کند و مانیفست کتابخانه یا برنامه برای گنجاندن آن به‌روزرسانی نشود، این اتفاق می‌افتد.

Soong می‌تواند برخی از برچسب‌های <uses-library> گمشده را برای یک کتابخانه یا برنامه به طور خودکار محاسبه کند، همانطور که کتابخانه‌های SDK در بسته شدن وابستگی انتقالی کتابخانه یا برنامه. بسته شدن لازم است زیرا ممکن است کتابخانه (یا برنامه) به کتابخانه ایستا وابسته به کتابخانه SDK بستگی داشته باشد، و احتمالاً ممکن است دوباره به صورت گذرا از طریق کتابخانه دیگری وابسته باشد.

همه تگ‌های <uses-library> را نمی‌توان با این روش محاسبه کرد، اما در صورت امکان، ترجیح داده می‌شود به Soong اجازه دهید ورودی‌های مانیفست را به صورت خودکار اضافه کند. کمتر مستعد خطا است و تعمیر و نگهداری را ساده می کند. به عنوان مثال، هنگامی که بسیاری از برنامه‌ها از یک کتابخانه ثابت استفاده می‌کنند که یک وابستگی جدید <uses-library> اضافه می‌کند، همه برنامه‌ها باید به‌روزرسانی شوند، که نگهداری آن دشوار است.

،

اندروید 12 دارای تغییرات سیستمی برای کامپایل AOT از فایل های DEX (dexpreopt) برای ماژول های جاوا است که وابستگی های <uses-library> دارند. در برخی موارد، این تغییرات سیستم ساخت می‌تواند ساخت‌ها را خراب کند. از این صفحه برای آماده شدن برای شکستگی ها استفاده کنید و دستور العمل های موجود در این صفحه را برای رفع و کاهش آنها دنبال کنید.

Dexpreopt فرآیند جمع‌آوری پیش از موعد کتابخانه‌ها و برنامه‌های جاوا است. Dexpreopt در زمان ساخت روی هاست اتفاق می افتد (برخلاف دکسوپت که روی دستگاه اتفاق می افتد). ساختار وابستگی های کتابخانه مشترک که توسط یک ماژول جاوا (یک کتابخانه یا یک برنامه) استفاده می شود، به عنوان زمینه بارگذار کلاس (CLC) شناخته می شود. برای تضمین صحت dexpreopt، CLC های زمان ساخت و زمان اجرا باید مطابقت داشته باشند. Build-time CLC چیزی است که کامپایلر dex2oat در زمان dexpreopt استفاده می‌کند (در فایل‌های ODEX ثبت می‌شود)، و CLC زمان اجرا، زمینه‌ای است که در آن کد از پیش کامپایل شده روی دستگاه بارگذاری می‌شود.

این CLC های زمان ساخت و زمان اجرا باید به دلایل صحت و عملکرد مطابقت داشته باشند. برای صحت، لازم است که کلاس های تکراری را مدیریت کنید. اگر وابستگی‌های کتابخانه مشترک در زمان اجرا با وابستگی‌های مورد استفاده برای کامپایل متفاوت باشد، ممکن است برخی از کلاس‌ها به روشی متفاوت حل شوند و باعث ایجاد باگ‌های ظریف در زمان اجرا شوند. عملکرد همچنین تحت تأثیر بررسی های زمان اجرا برای کلاس های تکراری قرار دارد.

موارد استفاده تحت تأثیر

اولین چکمه مورد اصلی استفاده است که تحت تأثیر این تغییرات قرار می گیرد: اگر هنر عدم تطابق بین CLC های ساخت و سازه زمان را تشخیص دهد ، مصنوعات Dexpreopt را رد می کند و به جای آن Dexopt را اجرا می کند. برای چکمه های بعدی این خوب است زیرا برنامه ها می توانند در پس زمینه ریخته شوند و روی دیسک ذخیره شوند.

مناطق تحت تأثیر اندروید

این همه برنامه های جاوا و کتابخانه هایی را که وابستگی به زمان اجرا به سایر کتابخانه های جاوا دارند ، تحت تأثیر قرار می دهد. Android هزاران برنامه دارد و صدها نفر از آنها از کتابخانه های مشترک استفاده می کنند. شرکا نیز تحت تأثیر قرار می گیرند ، زیرا کتابخانه ها و برنامه های خاص خود را دارند.

تغییرات شکستن

سیستم ساخت باید قبل از تولید قوانین ساخت Dexpreopt ، وابستگی های <uses-library> را بشناسد. با این حال ، نمی تواند به طور مستقیم به مانیفست دسترسی پیدا کند و برچسب های <uses-library> موجود در آن را بخواند ، زیرا سیستم ساخت مجاز به خواندن پرونده های دلخواه در هنگام ایجاد قوانین (به دلایل عملکرد) نیست. علاوه بر این ، مانیفست ممکن است در داخل یک APK یا یک پیش ساخته بسته بندی شود. بنابراین ، اطلاعات <uses-library> باید در Files Build ( Android.bp یا Android.mk ) موجود باشد.

پیش از این هنر از یک راه حل استفاده می کرد که وابستگی های مشترک کتابخانه ای را نادیده می گرفت (معروف به &-classpath ). این ناامن بود و باعث ایجاد اشکالات ظریف شد ، بنابراین این راه حل در اندروید 12 برداشته شد.

در نتیجه ، ماژول های جاوا که اطلاعات صحیح را در مورد <uses-library> در پرونده های ساخت خود ارائه نمی دهند ، می توانند باعث ایجاد شکستگی (ناشی از عدم تطابق CLC در زمان ساخت) یا رگرسیون زمان بوت اول شوند (ناشی از CLC بوت زمان عدم تطابق به دنبال Dexopt).

مسیر مهاجرت

این مراحل را برای رفع یک ساختمان شکسته دنبال کنید:

  1. در سطح جهانی با تنظیم یک محصول خاص برای یک محصول خاص غیرفعال کنید

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    در محصول Makefile. این خطاها را برطرف می کند (به جز موارد خاص ، که در بخش رفع شکست ذکر شده است). با این حال ، این یک راه حل موقت است ، و می تواند باعث عدم تطابق CLC بوت زمان و پس از آن Dexopt شود.

  2. ماژول هایی را که قبل از غیرفعال کردن در سطح جهانی غیرفعال کرده اید ، با افزودن اطلاعات لازم <uses-library> به پرونده های ساخت خود ، برطرف کنید (برای جزئیات بیشتر به رفع مشکلات مراجعه کنید). برای اکثر ماژول ها این نیاز به اضافه کردن چند خط در Android.bp یا در Android.mk دارد.

  3. چک کردن زمان ساخت و Dexpreopt را برای موارد مشکل ساز ، بر اساس هر ماژول غیرفعال کنید. Dexpreopt را غیرفعال کنید ، بنابراین شما وقت و ذخیره سازی را بر روی مصنوعاتی که در بوت رد می شوند ، هدر نمی دهید.

  4. در سطح جهانی با استفاده از PRODUCT_BROKEN_VERIFY_USES_LIBRARIES که در مرحله 1 تنظیم شده است ، بررسی زمان ساخت را دوباره فعال کنید. ساخت نباید پس از این تغییر شکست بخورد (به دلیل مراحل 2 و 3).

  5. ماژول هایی را که در مرحله 3 ، یک بار غیرفعال کرده اید ، برطرف کنید ، سپس دوباره DexPreopt و Check <uses-library> را دوباره فعال کنید. در صورت لزوم اشکالات را پرونده کنید.

چک های زمان <uses-library> چک ها در Android 12 اجرا می شود.

شکستگی ها را برطرف کنید

بخش های زیر به شما می گوید چگونه می توانید انواع خاصی از شکستگی را برطرف کنید.

ایجاد خطا: عدم تطابق CLC

سیستم ساخت یک انسجام زمان ساخت و ساز بین اطلاعات موجود در پرونده های 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 را برای verify در DexPreopt ، که باعث می شود AOT کاملاً برای این ماژول غیرفعال شود ، کاهش دهد.
  • برای رفع سریع خط فرمان جهانی ، از متغیر محیط 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 ماژول باشید. اگر آنجا باشد ، سونگ به طور معمول چنین کتابخانه هایی را به طور خودکار اضافه می کند ، به جز در این موارد خاص:

    • این کتابخانه یک کتابخانه SDK نیست (به عنوان java_library به جای java_sdk_library تعریف شده است).
    • این کتابخانه از نام ماژول خود (در سیستم ساخت) نام کتابخانه ای متفاوت (در مانیفست) دارد.

    برای رفع موقتاً ، اضافه provides_uses_lib: "<library-name>" در تعریف کتابخانه Android.bp . برای یک راه حل طولانی مدت ، مسئله اساسی را برطرف کنید: کتابخانه را به یک کتابخانه SDK تبدیل کنید یا ماژول آن را تغییر نام دهید.

  2. اگر مرحله قبلی وضوح ارائه نشده است ، uses_libs: ["<library-module-name>"] برای کتابخانه های مورد نیاز ، یا optional_uses_libs: ["<library-module-name>"] برای کتابخانه های اختیاری به Android.bp تعریف Android.bp از ماژول. این خصوصیات لیستی از نام های ماژول را می پذیرند. ترتیب نسبی کتابخانه ها در لیست باید همان سفارش موجود در مانیفست باشد.

برای ماژول های Android.mk :

  1. بررسی کنید که آیا این کتابخانه از نام ماژول خود (در سیستم ساخت) نام کتابخانه دیگری (در مانیفست) دارد. اگر این کار را انجام دهید ، این کار را به طور موقت با اضافه کردن LOCAL_PROVIDES_USES_LIBRARY := <library-name> در پرونده Android.mk کتابخانه ، یا اضافه کردن provides_uses_lib: "<library-name>" در پرونده Android.bp کتابخانه (هر دو مورد از آنجا که یک ماژول Android.mk ممکن است به یک کتابخانه Android.bp بستگی داشته باشد) امکان پذیر است. برای یک راه حل طولانی مدت ، مسئله اساسی را برطرف کنید: ماژول کتابخانه را تغییر دهید.

  2. اضافه کردن LOCAL_USES_LIBRARIES := <library-module-name> برای کتابخانه های مورد نیاز ؛ اضافه کردن LOCAL_OPTIONAL_USES_LIBRARIES := <library-module-name> برای کتابخانه های اختیاری به تعریف Android.mk از ماژول. این خصوصیات لیستی از نام های ماژول را می پذیرند. ترتیب نسبی کتابخانه ها در لیست باید همانند مانیفست باشد.

ایجاد خطا: مسیر کتابخانه ناشناخته

اگر سیستم ساخت نتواند مسیری را برای یک <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 از مانیفست ماژول y به پرونده ساخت برای y ممکن است به دلیل وابستگی از دست رفته ، خطای ساخت و ساز منجر به ایجاد خطای ساخت شود.

این یک پیام خطای نمونه برای ماژول های 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 A <uses-library> به نام com.android.X را ارائه می دهد.

این نمونه ای برای کتابخانه های Android.bp (خاصیت ماژول) است:

provides_uses_lib: “com.android.X”,

این نمونه ای برای کتابخانه های Android.mk (متغیر ماژول) است:

LOCAL_PROVIDES_USES_LIBRARY := com.android.X

عدم تطابق CLC-Time

در بوت اول ، LogCat را برای پیام های مربوط به عدم تطابق CLC جستجو کنید ، همانطور که در زیر آمده است:

$ adb wait-for-device && adb logcat \
  | grep -E 'ClassLoaderContext [a-z ]+ mismatch' -A1

The output can have messages of the form shown here:

[...] W system_server: ClassLoaderContext shared library size mismatch Expected=..., found=... (PCL[]... | PCL[]...)
[...] I PackageDexOptimizer: Running dexopt (dexoptNeeded=1) on: ...

If you get a CLC mismatch warning, look for a dexopt command for the faulty module. To fix it, ensure that the build-time check for the module passes. اگر این کار نکند ، ممکن است شما یک مورد خاص باشد که توسط سیستم ساخت پشتیبانی نمی شود (مانند برنامه ای که APK دیگری را بار می کند ، نه یک کتابخانه). سیستم ساخت همه موارد را اداره نمی کند ، زیرا در زمان ساخت ، نمی توان دانست که برنامه در زمان اجرا چه چیزی را بارگیری می کند.

زمینه لودر کلاس

CLC یک ساختار شبیه درخت است که سلسله مراتب کلاس بار را توصیف می کند. سیستم ساخت از CLC به معنای باریک استفاده می کند (فقط کتابخانه ها را در بر می گیرد ، نه APK ها یا لودرهای کلاس سفارشی): این یک درخت کتابخانه است که نشان دهنده بسته شدن گذرا از همه وابستگی های <uses-library> یک کتابخانه یا برنامه است. عناصر Toplevel یک CLC وابستگی مستقیم <uses-library> است که در مانیفست (کلاس کلاس) مشخص شده است. هر گره یک درخت CLC یک گره <uses-library> است که ممکن است دارای زیر گره های زیر <uses-library> خود باشد.

از آنجا که وابستگی های <uses-library> یک نمودار حکیمیک هدایت شده است و لزوماً یک درخت نیست ، CLC می تواند حاوی چندین زیر درخت برای همان کتابخانه باشد. به عبارت دیگر ، CLC نمودار وابستگی "آشکار" به یک درخت است. تکثیر فقط در یک سطح منطقی است. لودرهای کلاس اساسی واقعی کپی نشده اند (در زمان اجرا یک نمونه باربری کلاس برای هر کتابخانه وجود دارد).

CLC هنگام حل کلاسهای جاوا که توسط کتابخانه یا برنامه استفاده می شود ، ترتیب جستجوی کتابخانه ها را تعریف می کند. سفارش جستجو بسیار مهم است زیرا کتابخانه ها می توانند شامل کلاس های تکراری باشند و کلاس تا اولین مسابقه حل می شود.

در دستگاه (زمان اجرا) CLC

PackageManager (در frameworks/base ) CLC را برای بارگیری ماژول جاوا در دستگاه ایجاد می کند. این کتابخانه های ذکر شده در برچسب های <uses-library> را در مانیفست ماژول به عنوان عناصر CLC سطح بالا اضافه می کند.

برای هر کتابخانه استفاده شده ، PackageManager تمام وابستگی های <uses-library> خود را دریافت می کند (که به عنوان برچسب در مانیفست آن کتابخانه مشخص شده است) و برای هر وابستگی یک CLC تو در تو را اضافه می کند. این فرآیند به صورت بازگشتی ادامه می یابد تا اینکه تمام گره های برگ درخت CLC ساخته شده ، کتابخانه ها بدون وابستگی <uses-library> باشند.

PackageManager فقط از کتابخانه های مشترک آگاه است. تعریف مشترک در این استفاده با معنای معمول آن متفاوت است (مانند مشترک در مقابل استاتیک). در Android ، کتابخانه های مشترک جاوا آنهایی هستند که در پیکربندی های XML ذکر شده اند که روی آن نصب شده اند ( /system/etc/permissions/platform.xml ). هر ورودی شامل نام یک کتابخانه مشترک ، مسیری برای پرونده Dex JAR و لیستی از وابستگی ها (سایر کتابخانه های مشترک که این یکی از آنها در زمان اجرا استفاده می کند ، و در برچسب های <uses-library> در آشکار خود مشخص می کند).

به عبارت دیگر ، دو منبع اطلاعات وجود دارد که به PackageManager اجازه می دهد تا CLC را در زمان اجرا بسازند: <uses-library> ، برچسب ها در مانیفست ، و وابستگی های کتابخانه ای مشترک در پیکربندی های XML.

CLC در میزبان (زمان ساخت)

CLC فقط هنگام بارگیری کتابخانه یا برنامه مورد نیاز نیست ، بلکه هنگام تهیه یکی از آنها نیز لازم است. Compilation can happen either on-device (dexopt) or during the build (dexpreopt). Since dexopt takes place on-device, it has the same information as PackageManager (manifests and shared library dependencies). Dexpreopt, however, takes place on-host and in a totally different environment, and it has to get the same information from the build system.

Thus, the build-time CLC used by dexpreopt and the run-time CLC used by PackageManager are the same thing, but computed in two different ways.

CLC های ساخت و زمان و زمان اجرا باید همزمان شوند ، در غیر این صورت کد AOT ترکیب شده توسط DexPreopt رد می شود. برای بررسی برابری CLC های ساخت و ساز و زمان اجرا ، کامپایلر Dex2oat CLC را در پرونده های *.odex (در قسمت classpath هدر پرونده OAT) سوابق می دهد. برای یافتن CLC ذخیره شده ، از این دستور استفاده کنید:

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

عدم تطابق CLC در زمان و زمان اجرا در LogCat در هنگام بوت گزارش شده است. آن را با این دستور جستجو کنید:

logcat | grep -E 'ClassLoaderContext [az ]+ mismatch'

عدم تطابق برای عملکرد بد است ، زیرا این کتابخانه یا برنامه را مجبور می کند تا از بین برود ، یا بدون بهینه سازی اجرا شود (برای مثال ، کد برنامه ممکن است نیاز به استخراج در حافظه از APK داشته باشد ، یک عمل بسیار گران قیمت).

یک کتابخانه مشترک می تواند اختیاری باشد یا مورد نیاز باشد. از دیدگاه Dexpreopt ، یک کتابخانه مورد نیاز باید در زمان ساخت وجود داشته باشد (غیبت آن یک خطای ساخت است). یک کتابخانه اختیاری می تواند در زمان ساخت وجود داشته باشد یا غایب باشد: در صورت وجود ، به CLC اضافه می شود ، به Dex2oat منتقل می شود و در پرونده *.odex ضبط می شود. اگر یک کتابخانه اختیاری غایب باشد ، پرش می شود و به CLC اضافه نمی شود. اگر بین وضعیت ساخت و زمان اجرا عدم تطابق وجود داشته باشد (کتابخانه اختیاری در یک مورد وجود دارد ، اما مورد دیگر نیست) ، پس CLC های ساخت و زمان اجرا مطابقت ندارند و کد کامپایل شده رد می شود.

جزئیات سیستم ساخت پیشرفته (مانیفست فیکسور)

گاهی اوقات برچسب ها <uses-library> از مانیفست منبع یک کتابخانه یا برنامه گم نمی شوند. به عنوان مثال ، این اتفاق می افتد ، اگر یکی از وابستگی های گذرا از کتابخانه یا برنامه با استفاده از برچسب دیگر <uses-library> شروع شود ، و مانیفست کتابخانه یا برنامه برای درج آن به روز نمی شود.

Soong می تواند برخی از برچسب های گمشده <uses-library> را برای یک کتابخانه یا برنامه معین به طور خودکار محاسبه کند ، زیرا کتابخانه های SDK در بسته شدن وابستگی گذرا از کتابخانه یا برنامه. بسته شدن مورد نیاز است زیرا کتابخانه (یا برنامه) ممکن است به یک کتابخانه استاتیک بستگی داشته باشد که به یک کتابخانه SDK بستگی دارد ، و احتمالاً ممکن است دوباره از طریق کتابخانه دیگر به صورت روحی بستگی داشته باشد.

همه برچسب ها <uses-library> از این طریق قابل محاسبه نیستند ، اما در صورت امکان ، ترجیح داده می شود که Soong به صورت خودکار ورودی های مانیفست اضافه شود. این کمتر مستعد خطا است و تعمیر و نگهداری را ساده می کند. به عنوان مثال ، هنگامی که بسیاری از برنامه ها از یک کتابخانه استاتیک استفاده می کنند که یک وابستگی جدید <uses-library> را اضافه می کند ، باید تمام برنامه ها به روز شوند که نگهداری آن دشوار است.