Android 12, <uses-library>
bağımlılıkları olan Java modülleri için DEX dosyalarının AOT derlemesinde (dexpreopt) yapı sistemi değişiklikleri içerir. Bazı durumlarda bu derleme sistemi değişiklikleri derlemeleri bozabilir. Kesintilere hazırlanmak için bu sayfayı kullanın ve bu sayfadaki tarifleri uygulayarak kesintileri düzeltin ve azaltın.
Dexpreopt, Java kitaplıklarının ve uygulamalarının önceden derlenmesi işlemidir. 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'un doğruluğunu garanti etmek için derleme zamanı ve çalışma zamanı CLC'leri çakışmalıdır. Derleme zamanı CLC, dex2oat derleyicisinin dexpreopt zamanında kullandığı şeydir (ODEX dosyalarına kaydedilir) ve çalışma zamanı CLC, önceden derlenmiş kodun cihaza yüklendiği bağlamdır.
Hem doğruluk hem de performans açısından bu derleme ve çalışma zamanındaki CLC'ler çakışmalıdır. Doğruluk için yinelenen sınıfların ele alınması gerekir. Çalışma zamanındaki ortak kitaplık bağımlılıkları derleme için kullanılanlardan farklıysa sınıfların bazıları farklı şekilde çözülerek çalışma zamanında küçük hatalar oluşabilir. Performans, yinelenen sınıflar için çalışma zamanında yapılan kontrollerden de etkilenir.
Etkilenen kullanım alanları
İlk önyükleme, bu değişikliklerden etkilenen ana kullanım alanıdır: ART, derleme zamanı ve çalışma zamanı CLC'leri arasında uyuşmazlık tespit ederse dexpreopt yapılarını reddeder ve bunun yerine dexopt'u çalıştırır. Uygulamalar arka planda dexopt edilebilir ve diskte depolanabileceğinden sonraki önyüklemeler için bu sorun oluşturmaz.
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 bunların yüzlercesinde paylaşılan kitaplıklar kullanılır. Kendi kitaplıkları ve uygulamaları olan iş ortakları da bu durumdan etkilenir.
Zarar veren değişiklikler
Derleme sisteminin, dexpreopt derleme kurallarını oluşturmadan önce <uses-library>
bağımlılıkları bilmesi gerekir. Ancak derleme sistemi, derleme kuralları oluştururken (performans nedeniyle) rastgele dosyaları okumasına izin verilmediğinden doğrudan manifest dosyasına 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, <uses-library>
bilgileri derleme dosyalarında (Android.bp
veya Android.mk
) 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 çözüm güvenli değildi ve gözden kaçan hatalara neden olduğu için Android 12'de kaldırıldı.
Sonuç olarak, derleme dosyalarında doğru <uses-library>
bilgileri sağlamayan Java modülleri derleme hatalarına (derleme zamanındaki CLC uyuşmazlığından kaynaklanır) veya ilk açılış zamanındaki gerilemelere (boot zamanındaki CLC uyuşmazlığından ve ardından dexopt'tan kaynaklanır) neden olabilir.
Taşıma yolu
Bozuk bir derlemeyi düzeltmek için aşağıdaki adımları uygulayın:
Aşağıdaki ayarı yaparak belirli bir ürün için derleme zamanı kontrolünü küresel olarak devre dışı bırakma
PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true
dosyasında bulunabilir. Bu işlem, derleme hatalarını düzeltir (Kırılmaları 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.
Derleme zamanı kontrolünü genel olarak devre dışı bırakmadan önce, derleme dosyalarına gerekli
<uses-library>
bilgilerini 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 bu işlem,Android.bp
veyaAndroid.mk
dosyasına birkaç satır eklemeyi gerektirir.Derleme zamanı kontrolünü ve dexpreopt'i sorunlu durumlar için modül bazında devre dışı bırakı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.
1. adımda ayarlanan
PRODUCT_BROKEN_VERIFY_USES_LIBRARIES
değerini kaldırarak derleme zamanı kontrolünü global olarak yeniden etkinleştirin. Bu değişiklikten sonra derleme işlemi başarısız olmaz (2. ve 3. adımlar nedeniyle).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 hata kaydı oluşturun.
Derleme zamanı <uses-library>
kontrolleri Android 12'de zorunlu kılınmıştı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 bilgilerle 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ındaki <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 da belirtildiği gibi, aciliyet durumuna bağlı olarak birden fazla çözüm vardır:
- Ürün genelinde geçici bir düzeltme için ürün makefile'inde
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 filtresiniverify
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. Çevre değişkeni, ürün değişkenini geçersiz kılar. - Hatayı temel nedenden düzeltme çözümü için derleme sisteminin manifest'teki
<uses-library>
etiketlerinden haberdar olmasını sağlayın. Hata mesajı incelendiğinde soruna hangi kitaplıkların neden olduğu gösterilir (AndroidManifest.xml
veya APK içindeki manifest incelendiğinde de "aapt dump badging $APK | grep uses-library
" ile kontrol edilebilir).
Android.bp
modülleri için:
Eksik kitaplığı, modülün
libs
mülkünde bulun. 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ğildir (
java_sdk_library
yerinejava_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ınaprovides_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.- Kitaplık bir SDK kitaplığı değildir (
Önceki adım bir çözüm sağlamadıysa modülün
Android.bp
tanımına zorunlu kitaplıklar içinuses_libs: ["<library-module-name>"]
veya isteğe bağlı kitaplıklar içinoptional_uses_libs: ["<library-module-name>"]
ekleyin. Bu mülkler, bir modül adı listesi kabul eder. Listede kitaplıkların göreli sırası, manifest'teki sırayla aynı olmalıdır.
Android.mk
modülleri için:
Kitaplığın, kitaplık adının (manifest dosyasında) modül adından (derleme sisteminde) farklı olup olmadığını kontrol edin. Bu durumda, kitaplığın
Android.mk
dosyasınaLOCAL_PROVIDES_USES_LIBRARY := <library-name>
ekleyerek veya kitaplığınAndroid.bp
dosyasınaprovides_uses_lib: "<library-name>"
ekleyerek bu sorunu geçici olarak düzeltin (Android.mk
modülü birAndroid.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.Gerekli kitaplıklar için
LOCAL_USES_LIBRARIES := <library-module-name>
, isteğe bağlı kitaplıklar içinLOCAL_OPTIONAL_USES_LIBRARIES := <library-module-name>
ekleyin.Android.mk
Bu mülkler, modül adlarının listesini kabul eder. Listede kitaplıkların göreceli sırası, manifest'teki sırayla 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. Yol bulunamazsa kitaplığın beklenmedik bir şekilde yapılandırılmış olabileceği anlaşılır. Sorunlu modül için dexpreopt'u 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ıyla sonuçlanabilir.
Aşağıda Android.bp modülleri için örnek bir hata mesajı verilmiştir:
"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 nedeni, bir kitaplığın derleme sisteminde ilgili modülün adından 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
Çıktı, 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 yöntem işe yaramazsa derleme sistemi tarafından desteklenmeyen özel bir durumla (ör. kitaplık yerine başka bir APK yükleyen bir uygulama) karşı karşıya olabilirsiniz. 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; temeldeki gerçek sınıf yükleyiciler 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ı çö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ında) CLC
PackageManager
(frameworks/base
içinde), 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.
Kullanılan her kitaplık için PackageManager
, tüm <uses-library>
bağımlılıklarını (bu kitaplığın manifest dosyasında etiket olarak belirtilir) alır ve her bağımlılık için iç içe yerleştirilmiş bir CLC ekler. Bu işlem, oluşturulan CLC ağacının tüm yaprak düğümleri <uses-library>
bağımlılık içermeyen kitaplıklar olana kadar yinelemeli olarak devam eder.
PackageManager
yalnızca paylaşılan kitaplıkları bilir. Bu kullanımda paylaşılanın tanımı, genel anlamından (ör. paylaşılan ve statik) farklıdır. 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 listesini (bu kitaplığın çalışma zamanında kullandığı ve manifest dosyasında <uses-library>
etiketlerinde belirttiği 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 makinede (derleme zamanında) CLC
CLC yalnızca bir kitaplığı veya uygulamayı yüklerken değil, derlemede de gereklidir. Derleme, cihaz üzerinde (dexopt) veya derleme sırasında (dexpreopt) yapılabilir. Dexopt cihaz üzerinde gerçekleştiği için 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 ve derleme sisteminden aynı bilgileri alması gerekir.
Bu nedenle, dexpreopt tarafından kullanılan derleme zamanı CLC'si ile 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 eşleşmelidir. Aksi takdirde dexpreopt tarafından oluşturulan AOT 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 = '
Derleme zamanı ve çalışma zamanı CLC uyuşmazlığı, önyükleme sırasında logcat'te bildirilir. Aşağıdaki komutu kullanarak arayın:
logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch'
Eşleşmeme, kitaplığı veya uygulamayı dexopt'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'dan belleğe çıkarılması gerekebilir. Bu işlem çok pahalıdır).
Paylaşılan kitaplıklar isteğe bağlı veya zorunlu olabilir. dexpreopt açısından, gerekli bir kitaplık derleme sırasında mevcut olmalıdır (yokluğu derleme hatası olur). İsteğe bağlı bir kitaplık, derleme sırasında mevcut veya mevcut olmayabilir: Mevcutsa CLC'ye eklenir, dex2oat'a iletilir ve *.odex
dosyasına kaydedilir. İsteğe bağlı bir kitaplık yoksa 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'leri eşleşmez ve derlenmiş kod reddedilir.
Gelişmiş derleme sistemi ayrıntıları (manifest düzeltici)
Bazen bir kitaplığın veya uygulamanın kaynak manifest dosyasında <uses-library>
etiketleri eksiktir. Bu durum, örneğin, kitaplığın veya uygulamanın geçişli bağımlılıklarından biri başka bir <uses-library>
etiketi kullanmaya başlarsa ve kitaplığın veya uygulamanın manifest dosyası bu etiketi içerecek şekilde güncellenmezse ortaya çıkabilir.
Soong, kitaplığın veya uygulamanın geçişli bağımlılık kapanışındaki SDK kitaplıkları olarak belirli bir kitaplık ya da uygulama için eksik <uses-library>
etiketlerinin bir kısmını otomatik olarak hesaplayabilir. Kitaplık (veya uygulama), bir SDK kitaplığına bağlı olan statik bir kitaplığa bağlı olabileceği ve muhtemelen başka bir kitaplık aracılığıyla yine geçişli olarak bağlı olabileceği için kapanış gereklidir.
Tüm <uses-library>
etiketleri bu şekilde hesaplanamaz ancak mümkün olduğunda Soong'un manifest girişlerini otomatik olarak eklemesine izin vermek tercih edilir. Bu yöntem, hata olasılığını azaltır ve bakım işlemlerini 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.