Dexpreopt ve <uses-library> kontrolleri

Android 12 sahip Java modülleri için DEX dosyaları (dexpreopt) ait AOT derleme için inşa sistem değişiklikleri var <uses-library> bağımlılıkları. Bazı durumlarda bu yapı sistemi değişiklikleri yapıları bozabilir. Kırılmalara hazırlanmak için bu sayfayı kullanın ve bunları düzeltmek ve azaltmak için bu sayfadaki tarifleri takip edin.

Dexpreopt, Java kitaplıklarının ve uygulamalarının önceden derlenmesi sürecidir. Dexpreopt üzerinde-host (Cihazdaki olduğu gibi dexopt karşı), yapı anda gerçekleşir. Java modülü (kütüphane veya bir uygulama) tarafından kullanılan paylaşılan kütüphane bağımlılıkları yapısı sınıf yükleyicisi içerik (CLC) olarak da bilinir. Açıklamanın doğruluğunu garanti etmek için, derleme zamanı ve çalışma zamanı CLC'leri çakışmalıdır. Derleme zamanı CLC'si, dex2oat derleyicisinin dekspreopt zamanında kullandığı şeydir (ODEX dosyalarına kaydedilir) ve çalışma zamanı CLC, önceden derlenmiş kodun cihaza yüklendiği bağlamdır.

Bu derleme zamanı ve çalışma zamanı CLC'leri, hem doğruluk hem de performans nedenleriyle çakışmalıdır. Doğruluk için, yinelenen sınıfları işlemek gerekir. Çalışma zamanında paylaşılan kitaplık bağımlılıkları derleme için kullanılanlardan farklıysa, bazı sınıflar farklı şekilde çözülebilir ve bu da ince çalışma zamanı hatalarına neden olabilir. Performans, yinelenen sınıflar için çalışma zamanı denetimlerinden de etkilenir.

Etkilenen kullanım durumları

İlk önyükleme, bu değişikliklerden etkilenen ana kullanım durumudur: ART, derleme zamanı ve çalışma zamanı CLC'leri arasında bir uyumsuzluk algılarsa, dexpreopt yapılarını reddeder ve bunun yerine dexopt'u çalıştırır. Sonraki önyüklemeler için bu iyidir, çünkü uygulamalar arka planda dexopte edilebilir ve diskte depolanabilir.

Android'in etkilenen alanları

Bu, diğer Java kitaplıklarında çalışma zamanı bağımlılıkları olan tüm Java uygulamalarını ve kitaplıklarını etkiler. Android'de binlerce uygulama var ve bunlardan yüzlercesi paylaşılan kitaplıkları kullanıyor. Kendi kitaplıkları ve uygulamaları olduğu için iş ortakları da etkilenir.

Son değişiklikler

Yapı sistemi bilmelidir <uses-library> o dexpreopt inşa kurallarını oluşturur bağımlılıkları önce. Ancak, doğrudan tezahür erişebilir ve okuyamaz <uses-library> inşa sistemi (performans nedenleriyle) inşa kurallarını oluşturması durumunda keyfi dosyalarını okumak için izin verilmediği için, içinde etiketleri. Ayrıca, bildirim bir APK içinde veya önceden oluşturulmuş bir paket içinde paketlenebilir. Bu nedenle, <uses-library> bilgi inşa dosyaları (bulunmalıdır Android.bp veya Android.mk ).

Daha önce SANAT (olarak bilinen kütüphane bağımlılıkları paylaşılan ignored bir çözüm kullanılan &-classpath ). Bu güvenli değildi ve ince hatalara neden oldu, bu nedenle geçici çözüm Android 12'de kaldırıldı.

Sonuç olarak, Java modülleri doğru sağlamadığını <uses-library> Açılış anı CLC kaynaklanan (birikimi zaman CLC uyumsuzluğu nedeniyle) inşa kırılmalarına neden olabilir onların inşa dosyalarında bilgi ya da ilk açılış süresi regresyon ( uyumsuzluk ve ardından dexopt).

Taşıma yolu

Bozuk bir yapıyı düzeltmek için şu adımları izleyin:

  1. Belirli bir ürün için derleme zamanı denetimini ayarlayarak küresel olarak devre dışı bırakın

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    ürün makefile içinde. Bu düzeltmeler (listelenen özel durumlar haricinde yapı hatalarını sabitleme kırılmalar bölümünde). Ancak bu geçici bir çözümdür ve önyükleme zamanı CLC uyumsuzluğuna ve ardından dexopt'a neden olabilir.

  2. Eğer global gerekli ekleyerek inşa kez denetleyerek devre dışı önce başarısız olduğunu modülleri Fix <uses-library> (bkz onların inşa dosyalarına bilgi kırılmaları Tespit detaylar için). Çoğu modül için bu birkaç satır ekleyerek gerektirir Android.bp veya içinde Android.mk .

  3. Modül bazında sorunlu durumlar için derleme zamanı denetimini ve açıklamayı kaldırmayı devre dışı bırakın. Önyükleme sırasında reddedilen yapıtlar üzerinde derleme süresini ve depolamayı boşa harcamamak için dekspreopt'u devre dışı bırakın.

  4. Küresel unsetting ile birikimini zaman kontrol yeniden etkinleştirme PRODUCT_BROKEN_VERIFY_USES_LIBRARIES Aşama 1 'de ayarlandı; yapı bu değişiklikten sonra başarısız olmamalıdır (2. ve 3. adımlardan dolayı).

  5. Bir kerede 3. aşamanın tek devre dışı olduğunu modüllerini Fix, daha sonra dexpreopt ve yeniden etkinleştirmek <uses-library> çek. Gerekirse hataları dosyalayın.

Yap-time <uses-library> çekler Android 12'de uygulanır.

Kırılmaları düzeltme

Aşağıdaki bölümlerde, belirli kırılma türlerini nasıl düzelteceğiniz anlatılmaktadır.

Derleme hatası: CLC uyuşmazlığı

Yapı sistemi bilgilere arasındaki bir yapı zamanlı tutarlılık denetimi yapar Android.bp veya Android.mk dosya ve manifest'ten. Yapı sistemi tezahür okuyamaz, ancak apaçık (APK'nın gerekirse onu ayıklanması) okumak için inşa kurallarını oluşturmak ve karşılaştırabilirsiniz <uses-library> karşı apaçık etiketleri <uses-library> bilgileri derleme dosyaları. Kontrol başarısız olursa, hata şöyle görünür:

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

Hata mesajından da anlaşılacağı gibi, aciliyete bağlı olarak birden çok çözüm vardır:

  • Geçici bir ürün çapında düzeltme için set PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true ürün makefile. Derleme zamanı tutarlılık denetimi hala gerçekleştirilir, ancak denetim hatası, yapı hatası anlamına gelmez. Bunun yerine, bir kontrol hatası dex2oat derleyici filtresi sürüm düşürme yapı sistemi kolaylaştırır verify Bu modül için tamamen AOT-derleme devre dışı bırakır dexpreopt, içinde.
  • Hızlı bir küresel komut satırı düzeltme için ortam değişkeni kullanan RELAX_USES_LIBRARY_CHECK=true . It does aynı etkiye sahiptir PRODUCT_BROKEN_VERIFY_USES_LIBRARIES fakat komut satırında kullanılmak üzere tasarlanmıştır. Ortam değişkeni, ürün değişkenini geçersiz kılar.
  • Temel neden düzeltme hatası için bir çözüm için, inşa sistemi haberdar etmek <uses-library> tezahür etiketleri. Soruna neden olan kütüphaneler hata mesajı gösterir bir inceleme (aynı teftiş gelmez AndroidManifest.xml veya `ile kontrol edilebilir APK'nın apaçık içini aapt dump badging $APK | grep uses-library `).

For Android.bp modüllerinin:

  1. Eksik kitaplık için bak libs modülün özelliği. Eğer oradaysa, Soong bu özel durumlar dışında normalde bu tür kitaplıkları otomatik olarak ekler:

    • Kütüphane bir SDK kitaplığı (bu gibi tanımlanmıştır var değildir java_library yerine java_sdk_library ).
    • Kitaplığın, modül adından (derleme sisteminde) farklı bir kitaplık adı (bildirimde) vardır.

    Geçici Bunu düzeltmek eklemek için provides_uses_lib: "<library-name>" içinde Android.bp kütüphane tanımı. Uzun vadeli bir çözüm için temel sorunu düzeltin: kitaplığı bir SDK kitaplığına dönüştürün veya modülünü yeniden adlandırın.

  2. Bir önceki adım bir karar vermediyseniz, eklemek uses_libs: ["<library-module-name>"] gerekli kütüphaneler veya buraya optional_uses_libs: ["<library-module-name>"] isteğe bağlı kütüphaneler için Android.bp modülü tanımı. Bu özellikler, modül adlarının bir listesini kabul eder. Listedeki kitaplıkların göreli sırası, bildirimdeki sıra ile aynı olmalıdır.

For Android.mk modüllerinin:

  1. Kitaplığın, modül adından (derleme sisteminde) farklı bir kitaplık adına (bildirimde) sahip olup olmadığını kontrol edin. Eğer varsa, geçici olarak ekleyerek bu sorunu LOCAL_PROVIDES_USES_LIBRARY := <library-name> içinde Android.mk kütüphanesinin dosyaya veya eklemek provides_uses_lib: "<library-name>" içinde Android.bp kütüphanesinin dosyası (her iki vaka bir yana mümkündür Android.mk modülü bağlı olabilir Android.bp kütüphanesine). Uzun vadeli bir çözüm için temel sorunu düzeltin: kitaplık modülünü yeniden adlandırın.

  2. Ekle LOCAL_USES_LIBRARIES := <library-module-name> gerekli kütüphaneler için; eklemek LOCAL_OPTIONAL_USES_LIBRARIES := <library-module-name> için opsiyonel kütüphaneler için Android.mk modülünün tanımı. Bu özellikler, modül adlarının bir listesini kabul eder. Listedeki kitaplıkların göreli sırası, bildirimdeki ile aynı olmalıdır.

Derleme hatası: bilinmeyen kitaplık yolu

Yapı sistemi için bir yol bulamazsa <uses-library> deksmedetomidin kavanoz (on-host bir yapı zamanlı yolu veya bir yükleme yolu üzerinde aygıtı), genellikle yapı başarısız olur. Yolun bulunamaması, kitaplığın beklenmedik bir şekilde yapılandırıldığını gösterebilir. Sorunlu modül için açıklamayı devre dışı bırakarak yapıyı geçici olarak düzeltin.

Android.bp (modül özellikleri):

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

Android.mk (modül değişkenleri):

LOCAL_ENFORCE_USES_LIBRARIES := false
LOCAL_DEX_PREOPT := false

Desteklenmeyen senaryoları araştırmak için bir hata bildirin.

Derleme hatası: eksik kitaplık bağımlılığı

Bir girişimde eklemek için <uses-library> X yapı hatası neden olabilir Y inşa dosyaya modül Y'nin manifest'ten nedeniyle eksik bağımlılık, X'e

Bu, Android.bp modülleri için örnek bir hata mesajıdır:

"Y" depends on undefined module "X"

Bu, Android.mk modülleri için örnek bir hata mesajıdır:

'.../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

Bu tür hataların yaygın bir kaynağı, bir kitaplığın derleme sisteminde karşılık gelen modülünden farklı olarak adlandırılmasıdır. Örneğin, apaçık eğer <uses-library> giriştir com.android.X ancak kitaplık modülün adı adildir X , bu hataya neden olur. Bu davayı çözmek için, adlandırılmış modül o yapı sistemini anlatmak X bir sağlar <uses-library> adında com.android.X .

Bu örneğidir Android.bp kitaplıkları (modül özelliği):

provides_uses_lib: “com.android.X”,

Bu, Android.mk kitaplıkları için bir örnektir (modül değişkeni):

LOCAL_PROVIDES_USES_LIBRARY := com.android.X

Önyükleme zamanı CLC uyuşmazlığı

İlk açılışta, aşağıda gösterildiği gibi CLC uyuşmazlığıyla ilgili mesajlar için logcat'i arayın:

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

Çıktı, burada gösterilen formun mesajlarına sahip olabilir:

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

Bir CLC uyuşmazlığı uyarısı alırsanız, hatalı modül için bir dexopt komutu arayın. Bunu düzeltmek için, modül için derleme zamanı kontrolünün geçtiğinden emin olun. Bu işe yaramazsa, sizinki derleme sistemi tarafından desteklenmeyen özel bir durum olabilir (bir kitaplık yerine başka bir APK yükleyen bir uygulama gibi). Derleme sistemi tüm durumları ele almaz, çünkü derleme zamanında uygulamanın çalışma zamanında ne yüklediğini kesin olarak bilmek imkansızdır.

Sınıf yükleyici bağlamı

CLC, sınıf yükleyici hiyerarşisini tanımlayan ağaç benzeri bir yapıdır. Yapı sistemi (sadece kütüphaneler değil, APK'ler veya özel sınıf yükleyiciler kapsar) dar anlamda CLC kullanır: hepsinin geçişli kapatılmasını temsil kütüphanelerin bir ağaç <uses-library> bir kütüphane veya uygulamanın bağımlılıkları. Bir CLC toplevel elemanları direkt olan <uses-library> tezahür (sınıf yolunda) belirtilen bağımlılıkları. Bir CLC ağacının her düğüm bir olduğunu <uses-library> kendi sahip olabilir düğüm <uses-library> alt-düğümleri.

Çünkü <uses-library> bağımlılıkları, bir asiklik grafik yönlendirilir ve zorunlu olarak bir ağaç CLC aynı kütüphane için birden çok alt ağaçlar içerebilir. Başka bir deyişle, CLC, bir ağaca "açılmış" bağımlılık grafiğidir. Çoğaltma yalnızca mantıksal bir düzeydedir; gerçek temel sınıf yükleyiciler çoğaltılmaz (çalışma zamanında her kitaplık için tek bir sınıf yükleyici örneği vardır).

CLC, kitaplık veya uygulama tarafından kullanılan Java sınıflarını çözümlerken kitaplıkların arama sırasını tanımlar. Kitaplıklar yinelenen sınıflar içerebileceğinden ve sınıf ilk eşleşmeye göre çözümlendiğinden arama sırası önemlidir.

Cihazda (çalışma zamanı) CLC

PackageManager (de frameworks/base ) cihaz üzerinde bir Java modülü yüklemek için bir CLC oluşturur. Bu listelenen kütüphaneleri ekler <uses-library> modülün apaçık gibi üst düzey CLC elemanları etiketleri.

Her Kullanılmış kütüphanesi için, PackageManager tüm alır <uses-library> (yani kütüphanenin manifest'te etiketleri olarak belirtilir) bağımlılıklar ve her bağımlılık için iç içe geçmiş bir CLC ekler. Bu süreç inşa CLC ağacının tüm yaprak düğümleri olmadan kütüphaneler vardır yinelemeli kadar devam <uses-library> bağımlılıkları.

PackageManager paylaşılan kütüphanelerin sadece farkındadır. Bu kullanımdaki paylaşılan tanımı, olağan anlamından farklıdır (paylaşılana karşı statik olduğu gibi). Android yılında Java kütüphaneleri Cihazdaki (yüklü olduğunu XML yapılandırmasında listelenenler paylaşılmış /system/etc/permissions/platform.xml ). Her giriş paylaşılan kitaplığın adını içerir, onun DEX kavanoz dosya yolu ve bağımlılıkları listesi (diğer paylaşılan kütüphaneler ki bu bir zamanında kullanımları ve belirtir <uses-library> kendi manifest'te etiketleri).

Bir başka deyişle, iki izin bilginin kaynağı vardır PackageManager : zamanında CLC inşa etmek <uses-library> Manifestte etiketleri ve XML yapılandırmasında paylaşılan kütüphane bağımlılıklarını.

Ana bilgisayar üzerinde (derleme zamanı) CLC

CLC'ye yalnızca bir kitaplık veya uygulama yüklenirken değil, aynı zamanda bir kitaplık derlenirken de ihtiyaç duyulur. Derleme, cihazda (dexopt) veya derleme sırasında (dexpreopt) gerçekleşebilir. Dexopt Cihazdaki gerçekleşir yana, aynı bilgi var PackageManager (bildirimler ve paylaşılan kütüphane bağımlılıkları). Ancak Dexpreopt, ana bilgisayar üzerinde ve tamamen farklı bir ortamda gerçekleşir ve yapı sisteminden aynı bilgileri alması gerekir.

Böylece, yapı zamanlı CLC dexpreopt tarafından kullanılan ve CLC tarafından kullanılan çalışma zamanı PackageManager aynı şeydir, ancak iki farklı şekilde hesaplanır.

Yap-zaman ve çalışma zamanı CLCs aksi dexpreopt yarattığı AOT-derlenmiş kod reddedilen, denk olmalıdır. Birikmesi zaman ve çalışma zamanı CLCs eşitliğini kontrol etmek için, içinde dex2oat derleyici kayıtları birikmesi zaman CLC *.odex (dosyalar classpath YULAF dosya başlığında alanında). Depolanan CLC'yi bulmak için şu komutu kullanın:

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

Önyükleme sırasında logcat'te oluşturma zamanı ve çalışma zamanı CLC uyuşmazlığı rapor edilir. Bu komutla arayın:

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

Uyumsuzluk performans açısından kötüdür, çünkü kitaplığı veya uygulamayı dexopted olmaya veya optimizasyonlar olmadan çalışmaya zorlar (örneğin, uygulama kodunun APK'dan bellekte çıkarılması gerekebilir, bu çok pahalı bir işlemdir).

Paylaşılan bir kitaplık isteğe bağlı veya gerekli olabilir. Dexpreopt bakış açısından, derleme zamanında gerekli bir kitaplık bulunmalıdır (yokluğu bir derleme hatasıdır). İsteğe bağlı bir kütüphanesi inşa anda ya mevcut olabilir veya olmayabilir: mevcut ise, bu, CLC de eklenir dex2oat geçirilir ve kaydedilen *.odex dosyası. İsteğe bağlı bir kitaplık yoksa, atlanır ve CLC'ye eklenmez. Derleme zamanı ve çalışma zamanı durumu arasında bir uyumsuzluk varsa (bir durumda isteğe bağlı kitaplık bulunur, diğerinde yoktur), o zaman derleme zamanı ve çalıştırma zamanı CLC'leri eşleşmez ve derlenen kod reddedilir.

Gelişmiş yapı sistemi ayrıntıları (manifest sabitleyici)

Bazen <uses-library> etiketleri bir kütüphane veya uygulamanın kaynak Manifest'ten eksik. Kitaplık veya uygulamanın geçişli bağımlılıklarından biri başka kullanmaya başlar, bu, örneğin, olabilir <uses-library> etiketi ve kütüphane veya uygulama manifest bunu içerecek şekilde güncellenir değildir.

Soong eksik bazı hesaplayabilir <uses-library> kütüphaneden veya uygulamanın geçişli bağımlılık kapatılması SDK kütüphaneler gibi otomatik olarak belirli bir kitaplık veya uygulama için etiketler. Kitaplık (veya uygulama) bir SDK kitaplığına bağlı statik bir kitaplığa bağlı olabileceğinden ve muhtemelen geçişli olarak başka bir kitaplığa bağlı olabileceğinden kapatma gereklidir.

Tüm <uses-library> etiketleri bu şekilde hesaplanabilir ancak mümkün, bu Soong bildirim girişlerini otomatik ekleyelim için prefereable var; daha az hataya açıktır ve bakımı kolaylaştırır. Birçok uygulamalar yeni ekler statik kütüphane kullandığınızda Örneğin, <uses-library> bağımlılık, tüm uygulamalar bakımı zor olan güncellenmelidir.