Dexpreopt ve <uses-library> kontroller

Android 12, <uses-library> bağımlılığı olan Java modülleri için DEX dosyalarının (dexpreopt) AOT derlemesinde sistem değişiklikleri yapar. Bazı durumlarda bu derleme sistemi değişiklikleri, derlemeleri bozabilir. Kesintilere hazırlanmak için bu sayfayı kullanın. Kesintileri düzeltmek ve azaltmak için bu sayfadaki tarifleri uygulayın.

Dexpreopt, Java kitaplıklarının ve uygulamalarının önceden derlenmesiyle ilgilidir. Dexpreopt, derleme sırasında ana makinede gerçekleşir (cihaz üzerinde gerçekleşen dexopt'un aksine). Bir Java modülü (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'in doğruluğunu garanti etmek için derleme zamanı ve çalışma zamanı CLC'leri çakışmalıdır. Derleme zamanı CLC, dex2oat derleyicinin desteği sonlandırıldığında kullandığı ifadedir (ODEX dosyalarına kaydedilir) ve çalışma zamanı CLC, önceden derlenen kodun cihaza yüklendiği bağlamdır.

Bu derleme zamanı ve çalışma zamanı CLC'leri, hem doğruluk hem de performans açısından birbiriyle eşleşmelidir. Doğruluk açısından yinelenen sınıfların ele alınması gerekir. Çalışma zamanında paylaşılan kitaplık bağımlılıkları derleme için kullanılanlardan farklıysa sınıflardan bazıları farklı şekilde çözümlenebilir ve bu da çalışma zamanındaki küçük hatalara neden olabilir. Performans, yinelenen sınıflar için çalışma zamanında yapılan kontrollerden de etkilenir.

Etkilenen kullanım alanları

İlk başlatma, bu değişikliklerden etkilenen ana kullanım alanıdır: ART, derleme zamanı ile çalışma zamanı CLC'leri arasında bir uyumsuzluk tespit ederse dexpreopt yapısını reddeder ve bunun yerine dexopt'yi çalıştırır. Uygulamalar arka planda kaldırılabildiği ve diskte depolanabildiği için sonraki başlatmalarda bu bir sorun teşkil etmez.

Android'in etkilenen alanları

Bu durum, diğer Java kitaplıklarına çalışma zamanında bağımlı olan tüm Java uygulamalarını ve kitaplıklarını etkiler. Android'de binlerce uygulama vardır ve bu uygulamaların yüzlercesi paylaşılan kitaplıklar kullanır. Kendi kitaplıkları ve uygulamaları olan iş ortakları da bu durumdan etkilenir.

Sayfa sonu değişiklikleri

Derleme sisteminin, dexpreopt derleme kurallarını oluşturmadan önce <uses-library> bağımlılıkları bilmesi gerekir. Ancak derleme sisteminin derleme kuralları oluştururken rastgele dosyaları okumasına izin verilmediği için (performans nedeniyle) manifeste doğrudan erişemez ve içindeki <uses-library> etiketlerini okuyamaz. Ayrıca manifest, bir APK veya önceden derlenmiş bir paketin içine yerleştirilmiş olabilir. Bu nedenle, derleme dosyalarında (Android.bp veya Android.mk) <uses-library> bilgileri bulunmalıdır.

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, güvenli olmadığı ve küçük hatalara neden olduğu için bu geçici çözüm Android 12'de kaldırıldı.

Bunun sonucunda, derleme dosyalarında doğru <uses-library> bilgilerini sağlamayan Java modülleri, derleme kesintilerine (derleme zamanı CLC uyuşmazlığından kaynaklanır) veya ilk başlatma zamanı regresyonlarına (başlatma zamanı CLC uyuşmazlığından sonra dexopt'den kaynaklanan) yol açabilir.

Taşıma yolu

Bozuk bir derlemeyi düzeltmek için şu adımları uygulayın:

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

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    işlem dosyası oluşturun. Bu, yapı hatalarını düzeltir (Kesmeleri düzeltme bölümünde listelenen özel durumlar hariç). Ancak bu geçici bir çözümdür ve dexopt'un ardından önyükleme sırasında CLC uyuşmazlığına neden olabilir.

  2. Derleme zamanı kontrolünü genel olarak devre dışı bırakmadan önce, gerekli <uses-library> bilgilerini derleme dosyalarına ekleyerek başarısız olan modülleri düzeltin (ayrıntılar için Kırılmaları düzeltme bölümüne bakın). Çoğu modül için Android.bp veya Android.mk sürümüne birkaç satır eklenmesi gerekir.

  3. Sorunlu durumlar için modül bazında derleme zamanı denetimini devre dışı bırakın ve desteği sonlandırın. Açılışta reddedilen yapıların derleme süresini ve depolama alanını boşa harcamamak için dexpreopt'u devre dışı bırakın.

  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ımlar nedeniyle).

  5. 3. adımda devre dışı bıraktığınız modülleri tek tek düzeltin, ardından dexpreopt ve <uses-library> kontrolünü yeniden etkinleştirin. Gerekirse hataları bildirin.

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

Kesintileri düzeltme

Aşağıdaki bölümlerde, belirli kesinti türlerinin nasıl düzeltileceği açıklanmaktadır.

Derleme hatası: CLC uyuşmazlığı

Derleme sistemi, Android.bp veya Android.mk dosyalarındaki bilgiler ile manifest arasında derleme zamanında tutarlılık kontrolü yapar. Derleme sistemi manifest dosyasını okuyamaz ancak manifest dosyasını okumak (gerekirse APK'dan ayıklayarak) ve manifest dosyasında bulunan <uses-library> etiketlerini derleme dosyalarındaki <uses-library> bilgileriyle karşılaştırmak için derleme kuralları oluşturabilir. Kontrol 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ında belirtildiği gibi, aciliyete bağlı olarak birden fazla çözüm vardır:

  • Ürün genelinde geçici bir düzeltme için ürün oluşturma dosyasında PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true değerini ayarlayın. Derleme zamanı tutarlılık kontrolü yine de gerçekleştirilir ancak kontrol hatası, derleme hatası anlamına gelmez. Bunun yerine, kontrol hatası, derleme sisteminin dexpreopt'ta dex2oat derleyici filtresini verify olarak düşürmesine neden olur. Bu da AOT derlemeyi bu modül için tamamen devre dışı bırakır.
  • Hızlı ve genel bir komut satırı çözümü 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ılmak üzere tasarlanmıştır. Ortam değişkeni, ürün değişkenini geçersiz kılar.
  • Hatayı temel nedenden kaynaklanan bir düzeltmeyle çözmek için derleme sisteminin manifest'teki <uses-library> etiketlerinden haberdar olmasını sağlayın. Hata mesajının incelenmesi, hangi kitaplıkların soruna neden olduğunu gösterir (ör. AndroidManifest.xml veya "aapt dump badging $APK | grep uses-library" ile kontrol edilebilen APK'nın içindeki manifestin denetlenmesi).

Android.bp modül için:

  1. Modülün libs özelliğinde eksik kitaplığı arayın. Bu dosya varsa Soong, aşağıdaki özel durumlar hariç olmak üzere bu tür kitaplıkları genellikle otomatik olarak ekler:

    • Kitaplık bir SDK kitaplığı değil (java_sdk_library yerine java_library olarak tanımlanır).
    • Kitaplığın kitaplık adı (manifest'te), modül adından (derleme sisteminde) farklı.

    Bu sorunu geçici olarak düzeltmek için Android.bp kitaplığı 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 gerekli kitaplıklar için uses_libs: ["<library-module-name>"] veya modülün Android.bp tanımına isteğe bağlı kitaplıklar için optional_uses_libs: ["<library-module-name>"] ekleyin. Bu mülklerde modül adlarının bir listesini kabul eder. Listede kitaplıkların göreli sırası, manifest'teki sırayla aynı olmalıdır.

Android.mk modül için:

  1. Kitaplığın modül adından (derleme sisteminde) farklı bir kitaplık adı (manifest dosyasında) olup olmadığını kontrol edin. Bu durumda, kitaplığın Android.mk dosyasına LOCAL_PROVIDES_USES_LIBRARY := <library-name> ekleyerek veya kitaplığın Android.bp dosyasına provides_uses_lib: "<library-name>" ekleyerek bu sorunu geçici olarak düzeltin (Android.mk modülü bir Android.bp kitaplığına bağlı olabileceğinden her iki durum da 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 kitaplıklar 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 mülklerde modül adlarının bir listesi kabul edilir. Listedeki kitaplıkların göreli sırası, manifest dosyasındakiyle aynı olmalıdır.

Derleme hatası: Bilinmeyen kitaplık yolu

Derleme sistemi bir <uses-library> DEX jar'ının yolunu (ana makinede derleme zamanı yolu veya cihazda yükleme yolu) bulamıyorsa genellikle derleme başarısız olur. Bir yol bulunamaması, kitaplığın beklenmedik bir şekilde yapılandırıldığını gösterebilir. Sorunlu modül için dexpreopt'i devre dışı bırakarak derlemeyi 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ı incelemek için hata kaydı oluşturun.

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

Y modülünün manifest dosyasından Y derleme dosyasına <uses-library> X ekleme girişimi, X bağımlılığının eksik olması nedeniyle derleme hatasına neden olabilir.

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

"Y" depends on undefined module "X"

Aşağıda, Android.mk modülleri için örnek bir hata mesajı verilmiştir:

'.../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ğı, kitaplığın derleme sisteminde karşılık gelen modülünden farklı bir şekilde adlandırılmasıdır. Örneğin, manifest <uses-library> girişi com.android.X ise ancak kitaplık modülünün adı yalnızca X ise hata oluşur. Bu durumu çözmek için derleme sistemine X adlı modülün com.android.X adlı bir <uses-library> sağladığını bildirin.

Aşağıda, Android.bp kitaplıkları (modül özelliği) için bir örnek verilmiştir:

provides_uses_lib: “com.android.X”,

Aşağıda, Android.mk kitaplıkları (modül değişkeni) için bir örnek verilmiştir:

LOCAL_PROVIDES_USES_LIBRARY := com.android.X

Açılış zamanı CLC uyuşmazlığı

İlk açılışta, aşağıdaki gibi CLC uyuşmazlığıyla ilgili mesajlar için logcat'te arama yapın:

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

Çıkış, burada gösterilen biçimde mesajlar içerebilir:

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

CLC uyuşmazlığı uyarısı alırsanız hatalı modül için dexopt komutu arayın. Bu sorunu düzeltmek için modülün derleme zamanı kontrolünün geçtiğinden emin olun. Bu işe yaramazsa sizin uygulamanız, derleme sistemi tarafından desteklenmeyen özel bir durum olabilir (örneğin, kitaplık değil, başka bir APK yükleyen bir uygulama). Derleme sırasında uygulamanın çalışma zamanında neleri yükleyeceğini kesin olarak bilmek mümkün olmadığından derleme sistemi tüm durumları ele almaz.

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

CLC, sınıf-yükleyici hiyerarşisini açıklayan ağaç benzeri bir yapıdır. Derleme sistemi, CLC'yi dar anlamda kullanır (APK'ları 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 kapatılmasını temsil eden bir kitaplık ağacıdır. CLC'nin üst düzey öğeleri, manifest'te belirtilen doğrudan <uses-library> bağımlılıklardır (sınıf yolu). CLC ağacının her düğümü, kendi <uses-library> alt düğümlerine sahip olabilecek bir <uses-library> düğümüdür.

<uses-library> bağımlılıkları, zorunlu olarak bir ağaç değil, yönlendirilmiş döngüsel olmayan bir grafik olduğundan CLC, aynı kitaplık için birden fazla alt ağaç içerebilir. Diğer bir deyişle, CLC, bir ağaca "açılmış" bağımlılık grafiğidir. Kopyalama yalnızca mantıksal düzeydedir; gerçek temel sınıf yükleyiciler yinelenmez (çalışma zamanında her kitaplık için tek bir sınıf yükleyici örneği olur).

CLC, kitaplık veya uygulama tarafından kullanılan Java sınıflarını çözerken 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üldüğünden arama sırası önemlidir.

Cihaz üzerinde (çalışma zamanı) CLC

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

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

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

Diğer bir deyişle, PackageManager'nin çalışma zamanında CLC oluşturmasına olanak tanıyan iki bilgi kaynağı vardır: manifest'teki <uses-library> etiketleri ve XML yapılandırmalarındaki paylaşılan kitaplık bağımlılıkları.

Ana makine üzerinde (derleme zamanı) CLC

CLC yalnızca bir kitaplık veya uygulama yüklerken değil, derlerken de gereklidir. Derleme, cihaz üzerinde (dexopt) veya derleme sırasında (dexpreopt) yapılabilir. Dexopt cihaz üzerinde gerçekleştiğinden PackageManager ile aynı bilgilere (manifestler ve paylaşılan kitaplık bağımlılıkları) sahiptir. Ancak Dexpreopt, ana makinede ve tamamen farklı bir ortamda gerçekleşir. Ayrıca, derleme sisteminden de aynı bilgileri alması gerekir.

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

Derleme zamanı ile çalışma zamanı CLC'leri birbiriyle örtüşmelidir. Aksi takdirde, dexpreopt tarafından oluşturulan AOT tarafından derlenmiş kod reddedilir. dex2oat derleyicisi, derleme zamanı ve çalışma zamanı CLC'lerinin eşitliğini kontrol etmek için derleme zamanı CLC'sini *.odex dosyalarına (OAT dosyası başlığının classpath alanına) kaydeder. Depolanan CLC'yi bulmak için şu komutu kullanın:

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

Başlatma sırasında logcat'te derleme zamanı ve çalışma zamanı CLC uyuşmazlığı bildirilir. Aracı bulmak için şu komutu kullanın:

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

Eşleşmeme, kitaplığı veya uygulamayı dexopt&#39;a zorladığı ya da optimizasyon olmadan çalıştırmaya zorladığı için performans açısından kötüdür (örneğin, uygulamanın kodunun APK&#39;dan belleğe çıkarılması gerekebilir. Bu işlem çok pahalıdır).

Paylaşılan kitaplık, isteğe bağlı veya zorunlu olabilir. dexpreopt açısından, gerekli bir kitaplık derleme zamanında mevcut olmalıdır (yokluğu derleme hatası olur). İsteğe bağlı bir kitaplık, derleme zamanında mevcut veya eksik olabilir: Mevcut olduğunda CLC'ye eklenir, dex2oat'a geçirilir ve *.odex dosyasına kaydedilir. İsteğe bağlı bir kitaplık yoksa bu kitaplık atlanır ve CLC'ye eklenmez. Derleme zamanı ve çalışma zamanı durumu arasında uyuşmazlık varsa (isteğe bağlı kitaplık bir durumda mevcutsa ancak diğerinde mevcut değilse) derleme zamanı ve çalışma zamanı CLC&#39;leri eşleşmez ve derlenmiş kod reddedilir.

Gelişmiş derleme sistemi ayrıntıları (manifest düzeltme aracı)

Bazen bir kitaplığın veya uygulamanın kaynak manifest'inde <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 ya da uygulamanın manifesti bunu içerecek şekilde güncellenmezse bu durum görülebilir.

Yakındag, belirli bir kitaplık veya uygulama için eksik <uses-library> etiketlerinden bazılarını otomatik olarak hesaplayabilir. Bunun nedeni, kitaplığın veya uygulamanın geçişli bağımlılığının kapatılmasında SDK kitaplıklarıdır. Kitaplık (veya uygulama) bir SDK kitaplığına bağlı olan statik bir kitaplığa bağlı olabileceği ve yine başka bir kitaplık üzerinden geçişli olarak bağımlı olabileceği için kapatma işlemi gereklidir.

Tüm <uses-library> etiketlerinin bu şekilde hesaplanması mümkün değildir. Ancak mümkün olduğunda, sFTP'nin manifest girişlerini otomatik olarak eklemesine izin vermek tercih edilebilir. Bu yöntem, hataya daha az açıktır ve bakımı basitleştirir. Ö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. Bu da sürdürülmesi zor bir durumdur.