Dexpreopt ve <kütüphaneyi kullanır> çekler

Android 12, <uses-library> bağımlılıklarına sahip Java modülleri için DEX dosyalarının (dexpreopt) AOT derlemesinde sistem değişiklikleri oluşturdu. Bazı durumlarda bu yapı sistemi değişiklikleri yapıların bozulmasına neden olabilir. Kırılmalara hazırlanmak için bu sayfayı kullanın ve bunları düzeltmek ve azaltmak için bu sayfadaki tarifleri izleyin.

Dexpreopt, Java kitaplıklarının ve uygulamalarının önceden derlenmesi işlemidir. Dexpreopt, derleme sırasında ana bilgisayarda gerçekleşir (cihazda gerçekleşen dexopt'un aksine). Bir Java modülü (bir kitaplık veya uygulama) tarafından kullanılan paylaşılan kitaplık bağımlılıklarının yapısı, sınıf yükleyici bağlamı (CLC) olarak bilinir. Dexpreopt'un doğruluğunu garanti etmek için derleme zamanı ve çalışma zamanı CLC'lerinin çakışması gerekir. Derleme zamanı CLC, dex2oat derleyicisinin dexpreopt zamanında kullandığı şeydir (ODEX dosyalarına kaydedilir) ve çalışma zamanı CLC, önceden derlenmiş kodun aygıta yüklendiği bağlamdır.

Bu derleme zamanı ve çalışma zamanı CLC'leri hem doğruluk hem de performans açısından çakışmalıdır. Doğruluk için yinelenen sınıfları ele almak gerekir. Çalışma zamanındaki 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 aynı zamanda yinelenen sınıflara yönelik çalışma zamanı denetimlerinden de etkilenir.

Etkilenen kullanım örnekleri

İ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 tespit ederse, dexpreopt yapıtlarını reddeder ve bunun yerine dexopt'u çalıştırır. Sonraki önyüklemeler için bu sorun değildir çünkü uygulamalar arka planda çıkarılabilir ve diskte saklanabilir.

Android'in etkilenen alanları

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

Değişiklikleri sonlandır

Derleme sisteminin dexpreopt derleme kuralları oluşturmadan önce <uses-library> bağımlılıklarını bilmesi gerekir. Ancak, manifest dosyasına doğrudan erişemez ve içindeki <uses-library> etiketlerini okuyamaz, çünkü derleme sisteminin derleme kuralları oluştururken rastgele dosyaları okumasına izin verilmez (performans nedenleriyle). Ayrıca manifest, bir APK'nin veya önceden oluşturulmuş bir uygulamanın içinde paketlenmiş olabilir. Bu nedenle, derleme dosyalarında ( Android.bp veya Android.mk ) <uses-library> bilgisinin bulunması gerekir.

Daha önce ART, paylaşılan kitaplık bağımlılıklarını ( &-classpath olarak bilinir) yok sayan bir geçici çözüm kullanıyordu. Bu durum güvensizdi ve hafif hatalara neden olduğundan geçici çözüm Android 12'de kaldırıldı.

Sonuç olarak, derleme dosyalarında doğru <uses-library> bilgilerini sağlamayan Java modülleri, derleme bozulmalarına (derleme zamanı CLC uyumsuzluğundan kaynaklanır) veya ilk önyükleme zamanı gerilemelerine (önyükleme zamanı CLC'sinden kaynaklanır) neden olabilir. uyumsuzluk ve ardından dexopt).

Geçiş yolu

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

  1. Ayarlayarak belirli bir ürün için yapım zamanı denetimini genel olarak devre dışı bırakın

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    ürün makefile'ında. Bu, derleme hatalarını düzeltir ( Kusurların düzeltilmesi bölümünde listelenen özel durumlar hariç). Ancak bu geçici bir çözümdür ve önyükleme zamanı CLC uyumsuzluğuna ve ardından dexopt'a neden olabilir.

  2. Derleme dosyalarına gerekli <uses-library> bilgilerini ekleyerek derleme zamanı denetimini genel olarak devre dışı bırakmadan önce başarısız olan modülleri düzeltin (ayrıntılar için bkz . Arızaların onarılması ). Çoğu modül için bu, Android.bp veya Android.mk dosyasına birkaç satır eklenmesini gerektirir.

  3. Sorunlu durumlar için modül bazında derleme zamanı kontrolünü ve dexpreopt'u devre dışı bırakın. Dexpreopt'u devre dışı bırakın, böylece derleme süresini ve depolama alanını önyükleme sırasında reddedilen yapılar üzerinde boşa harcamazsınız.

  4. 1. Adımda ayarlanan PRODUCT_BROKEN_VERIFY_USES_LIBRARIES ayarını kaldırarak derleme zamanı denetimini genel olarak yeniden etkinleştirin; derleme bu değişiklikten sonra başarısız olmamalıdır (2. ve 3. adımlardan dolayı).

  5. Adım 3'te devre dışı bıraktığınız modülleri teker teker düzeltin, ardından dexpreopt'u ve <uses-library> denetimini yeniden etkinleştirin. Gerekirse hataları dosyalayın.

Derleme zamanı <uses-library> kontrolleri Android 12'de uygulanır.

Kırılmaları düzeltin

Aşağıdaki bölümlerde belirli kırılma türlerinin nasıl düzeltileceği anlatılmaktadır.

Derleme hatası: CLC uyuşmazlığı

Derleme sistemi, Android.bp veya Android.mk dosyalarındaki bilgiler ile bildirim arasında derleme zamanı tutarlılık kontrolü yapar. Derleme sistemi bildirimi okuyamaz, ancak bildirimi okumak için derleme kuralları oluşturabilir (gerekirse APK'dan çıkartarak) ve bildirimdeki <uses-library> etiketlerini içindeki <uses-library> bilgileriyle karşılaştırabilir. yapı dosyaları. Denetim başarısız olursa hata şu şekilde 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 fazla çözüm vardır:

  • Ürün çapında geçici bir düzeltme için ürün makefile'ında PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true ayarlayın. Derleme zamanı tutarlılık denetimi hâlâ gerçekleştirilir, ancak denetimin başarısız olması, derlemenin başarısız olduğu anlamına gelmez. Bunun yerine, bir kontrol hatası, derleme sisteminin dex2oat derleyici filtresini dexpreopt'ta verify için düşürmesine neden olur, bu da bu modül için AOT derlemesini tamamen devre dışı bırakır.
  • Hızlı, genel bir komut satırı düzeltmesi için RELAX_USES_LIBRARY_CHECK=true ortam değişkenini kullanın. PRODUCT_BROKEN_VERIFY_USES_LIBRARIES ile aynı etkiye sahiptir ancak komut satırında kullanılması amaçlanmıştır. Ortam değişkeni ürün değişkenini geçersiz kılar.
  • Hatanın kök nedenini düzeltmeye yönelik bir çözüm için derleme sisteminin manifestteki <uses-library> etiketlerinden haberdar olmasını sağlayın. Hata mesajının incelenmesi, soruna hangi kitaplıkların neden olduğunu gösterir ( AndroidManifest.xml veya ' aapt dump badging $APK | grep uses-library ' ile kontrol edilebilen bir APK'nın içindeki bildirimin incelenmesinde olduğu gibi).

Android.bp modülleri için:

  1. Modülün libs özelliğinde eksik kitaplığı arayın. Eğer oradaysa, Soong normalde bu tür kütüphaneleri şu özel durumlar dışında otomatik olarak ekler:

    • Kitaplık bir SDK kitaplığı değildir ( java_sdk_library yerine java_library olarak tanımlanır).
    • Kitaplığın, modül adından (derleme sistemindeki) farklı bir kitaplık adı (bildirimde) vardır.

    Bunu geçici olarak düzeltmek için Android.bp kitaplık tanımına provides_uses_lib: "<library-name>" ekleyin. 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. Önceki adım bir çözüm sağlamadıysa, Android'e gerekli kitaplıklar için uses_libs: ["<library-module-name>"] veya isteğe bağlı kitaplıklar için optional_uses_libs: ["<library-module-name>"] ekleyin Android.bp modülün Android.bp tanımı. Bu özellikler, modül adlarının bir listesini kabul eder. Listedeki kitaplıkların göreli sırası manifestteki sıra ile aynı olmalıdır.

Android.mk modülleri için:

  1. Kitaplığın, modül adından (derleme sistemindeki) farklı bir kitaplık adına (bildirimde) sahip olup olmadığını kontrol edin. Eğer öyleyse, kütüphanenin Android.mk dosyasına LOCAL_PROVIDES_USES_LIBRARY := <library-name> ekleyerek veya kütüphanenin Android.bp dosyasına provides_uses_lib: "<library-name>" ekleyerek bu sorunu geçici olarak düzeltin (her iki durumda da) Bir Android.mk modülü bir Android.bp kitaplığına bağlı olabileceğinden mümkündür). Uzun vadeli bir çözüm için temel sorunu düzeltin: kitaplık modülünü yeniden adlandırın.

  2. Gerekli kütüphaneler için LOCAL_USES_LIBRARIES := <library-module-name> ekleyin; modülün Android.mk tanımına isteğe bağlı kitaplıklar için LOCAL_OPTIONAL_USES_LIBRARIES := <library-module-name> ekleyin. Bu özellikler, modül adlarının bir listesini kabul eder. Listedeki kitaplıkların göreli sırası manifesttekiyle aynı olmalıdır.

Derleme hatası: bilinmeyen kitaplık yolu

Derleme sistemi <uses-library> DEX jar'ına (ana makinedeki derleme zamanı yolu veya cihazdaki yükleme yolu) giden yolu bulamazsa genellikle derlemede başarısız olur. Yolun bulunamaması, kitaplığın beklenmedik bir şekilde yapılandırıldığını gösterebilir. Sorunlu modül için dexpreopt'u 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ı: kitaplık bağımlılığı eksik

Y modülünün bildiriminden <uses-library> X'i Y'nin derleme dosyasına ekleme girişimi, X bağımlılığının eksik olması nedeniyle bir derleme hatasıyla sonuçlanabilir.

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, yapı sisteminde karşılık gelen modülün adından farklı şekilde adlandırılmasıdır. Örneğin, manifest <uses-library> girişi com.android.X ise ancak kütüphane modülünün adı yalnızca X ise, bu bir hataya neden olur. Bu durumu çözmek için yapı sistemine X adlı modülün com.android.X adında bir <uses-library> sağladığını söyleyin.

Bu, Android.bp kitaplıklarına (modül özelliği) bir örnektir:

provides_uses_lib: “com.android.X”,

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

LOCAL_PROVIDES_USES_LIBRARY := com.android.X

Önyükleme zamanı CLC uyumsuzluğu

İlk açılışta, aşağıda gösterildiği gibi CLC uyumsuzluğuyla ilgili mesajları logcat'te arayın:

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

Çıktı burada gösterilen biçimdeki mesajlara sahip olabilir:

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

CLC uyumsuzluğu uyarısı alırsanız arızalı modül için dexopt komutunu arayın. Bunu düzeltmek için modülün derleme zamanı kontrolünün geçtiğinden emin olun. Bu işe yaramazsa sizinki, derleme sistemi tarafından desteklenmeyen özel bir durum olabilir (örneğin, kitaplık değil, başka bir APK yükleyen bir uygulama). 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. Derleme sistemi CLC'yi dar anlamda kullanır (APK'leri veya özel sınıf yükleyicileri değil, yalnızca kitaplıkları kapsar): bir kitaplığın veya uygulamanın tüm <uses-library> bağımlılıklarının geçişli olarak kapatılmasını temsil eden bir kitaplıklar ağacıdır. Bir CLC'nin üst düzey öğeleri, bildirimde (sınıf yolu) belirtilen doğrudan <uses-library> bağımlılıklarıdır. Bir CLC ağacının her düğümü, kendi <uses-library> alt düğümlerine sahip olabilen bir <kullanımlar- <uses-library> düğümüdür.

<uses-library> bağımlılıkları yönlendirilmiş döngüsel olmayan bir grafik olduğundan ve bir ağaç olması gerekmediğinden, CLC aynı kitaplık için birden fazla alt ağaç 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 düzeydedir; asıl temel sınıf yükleyicileri kopyalanmaz (ç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 çözümlendiğinden arama sırası önemlidir.

Cihazda (çalışma zamanı) CLC

PackageManager ( frameworks/base içinde), cihaza bir Java modülü yüklemek için bir CLC oluşturur. Modülün bildirimindeki <uses-library> etiketlerinde listelenen kitaplıkları üst düzey CLC öğeleri olarak ekler.

Kullanılan her kitaplık için, PackageManager tüm <uses-library> bağımlılıklarını alır (bu kitaplığın bildiriminde etiketler olarak belirtilir) ve her bağımlılık için iç içe geçmiş bir CLC ekler. Bu süreç, oluşturulan CLC ağacının tüm yaprak düğümleri <uses-library> bağımlılıkları olmayan kütüphaneler olana kadar yinelemeli olarak devam eder.

PackageManager yalnızca paylaşılan kitaplıkların farkındadır. Bu kullanımdaki paylaşılan tanımı, olağan anlamından farklıdır (paylaşılan ve statik gibi). Android'de, Java paylaşılan kitaplıkları, cihaza yüklenen XML yapılandırmalarında listelenen kitaplıklardır ( /system/etc/permissions/platform.xml ). Her giriş, paylaşılan bir kitaplığın adını, DEX jar dosyasının yolunu ve bağımlılıkların bir listesini (bunun çalışma zamanında kullandığı diğer paylaşılan kitaplıklar ve manifest dosyasındaki <uses-library> etiketlerinde belirtir) içerir.

Başka bir deyişle, PackageManager çalışma zamanında CLC oluşturmasına izin veren iki bilgi kaynağı vardır: bildirimdeki <uses-library> etiketleri ve XML yapılandırmalarındaki paylaşılan kitaplık bağımlılıkları.

Ana makinede (derleme zamanı) CLC

CLC yalnızca bir kitaplığı veya uygulamayı yüklerken gerekli değildir, aynı zamanda bir uygulamayı derlerken de gereklidir. Derleme cihaz üzerinde (dexopt) veya derleme sırasında (dexpreopt) gerçekleşebilir. Dexopt cihaz üzerinde gerçekleştiğinden, PackageManager ile aynı bilgilere sahiptir (bildirimler ve paylaşılan kitaplık bağımlılıkları). Ancak Dexpreopt, ana bilgisayarda ve tamamen farklı bir ortamda gerçekleşir ve aynı bilgiyi yapı sisteminden alması gerekir.

Dolayısıyla dexpreopt tarafından kullanılan derleme zamanı CLC'si ve PackageManager tarafından kullanılan çalışma zamanı CLC'si aynı şeydir ancak iki farklı şekilde hesaplanır.

Derleme zamanı ve çalışma zamanı CLC'leri çakışmalıdır , aksi takdirde dexpreopt tarafından oluşturulan AOT ile derlenmiş kod reddedilir. Derleme zamanı ve çalışma zamanı CLC'lerinin eşitliğini kontrol etmek için dex2oat derleyicisi, derleme zamanı CLC'sini *.odex dosyalarına (OAT dosya başlığının classpath alanına) kaydeder. Saklanan CLC'yi bulmak için şu komutu kullanın:

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

Önyükleme sırasında logcat'te derleme zamanı ve çalışma zamanı CLC uyumsuzluğu rapor ediliyor. Bu komutla arayın:

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

Uyumsuzluk, kitaplığı veya uygulamayı ya devre dışı kalmaya ya da optimizasyonlar olmadan çalışmaya zorladığından performans açısından kötüdür (örneğin, uygulama kodunun, çok pahalı bir işlem olan APK'dan belleğe çıkarılması gerekebilir).

Paylaşılan bir kitaplık isteğe bağlı veya gerekli olabilir. Dexpreopt açısından bakıldığında, gerekli bir kütüphanenin derleme sırasında mevcut olması gerekir (yokluğu bir derleme hatasıdır). İsteğe bağlı bir kitaplık derleme sırasında mevcut olabilir veya olmayabilir: Varsa CLC'ye eklenir, dex2oat'a aktarılır ve *.odex dosyasına kaydedilir. İsteğe bağlı bir kitaplık yoksa atlanır ve CLC'ye eklenmez. Derleme zamanı ile çalışma zamanı durumu arasında bir uyumsuzluk varsa (isteğe bağlı kitaplık bir durumda mevcut, diğerinde mevcut değil), bu durumda derleme zamanı ve çalışma zamanı CLC'leri eşleşmez ve derlenen kod reddedilir.

Gelişmiş yapı sistemi ayrıntıları (bildirim düzeltici)

Bazen bir kitaplığın veya uygulamanın kaynak bildiriminde <uses-library> etiketleri eksik olur. Örneğin, kitaplığın veya uygulamanın geçişli bağımlılıklarından biri başka bir <uses-library> etiketini kullanmaya başlarsa ve kitaplığın veya uygulamanın bildirimi onu içerecek şekilde güncellenmezse bu durum meydana gelebilir.

Soong, belirli bir kitaplık veya uygulama için eksik <uses-library> etiketlerinden bazılarını, kitaplığın veya uygulamanın geçişli bağımlılığının kapatılmasındaki SDK kitaplıkları olarak otomatik olarak hesaplayabilir. Kitaplığın (veya uygulamanın) bir SDK kitaplığına bağlı olan statik bir kitaplığa bağlı olabileceği ve muhtemelen yine başka bir kitaplığa geçişli olarak bağlı olabileceği için kapatma gereklidir.

<uses-library> etiketlerinin tümü bu şekilde hesaplanamaz, ancak mümkün olduğunda Soong'un bildirim girişlerini otomatik olarak eklemesine izin verilmesi tercih edilir; hataya daha az eğilimlidir ve bakımı kolaylaştırır. Örneğin, birçok uygulama yeni bir <uses-library> bağımlılığı ekleyen statik bir kitaplık kullandığında, tüm uygulamaların güncellenmesi gerekir ve bunun bakımı zordur.