Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Deexpreopt dan pemeriksaan <uses-library>

Android 12 memiliki sistem perubahan membangun untuk AOT kompilasi DEX file (dexpreopt) untuk modul Jawa yang memiliki <uses-library> dependensi. Dalam beberapa kasus, perubahan sistem build ini dapat merusak build. Gunakan halaman ini untuk mempersiapkan kerusakan, dan ikuti resep di halaman ini untuk memperbaiki dan menguranginya.

Dexpreopt adalah proses kompilasi perpustakaan dan aplikasi Java sebelumnya. Dexpreopt terjadi pada host pada waktu pembangunan (sebagai lawan dexopt, yang terjadi pada perangkat). Struktur dependensi shared library yang digunakan oleh modul Java (perpustakaan atau aplikasi) dikenal sebagai konteks kelas loader nya (CLC). Untuk menjamin kebenaran dexpreopt, CLC build-time dan run-time harus bertepatan. Build-time CLC adalah apa yang digunakan kompiler dex2oat pada waktu dexpreopt (tercatat dalam file ODEX), dan CLC run-time adalah konteks di mana kode yang telah dikompilasi dimuat pada perangkat.

CLC build-time dan run-time ini harus bertepatan untuk alasan kebenaran dan kinerja. Untuk kebenaran, perlu untuk menangani kelas duplikat. Jika dependensi pustaka bersama saat runtime berbeda dari yang digunakan untuk kompilasi, beberapa kelas mungkin diselesaikan secara berbeda, menyebabkan bug runtime yang tidak kentara. Kinerja juga dipengaruhi oleh pemeriksaan runtime untuk kelas duplikat.

Kasus penggunaan yang terpengaruh

Boot pertama adalah kasus penggunaan utama yang terpengaruh oleh perubahan ini: jika ART mendeteksi ketidakcocokan antara CLC waktu pembuatan dan waktu proses, ART akan menolak artefak dexpreopt dan menjalankan dexopt sebagai gantinya. Untuk boot berikutnya ini baik-baik saja karena aplikasi dapat di-dexopted di latar belakang dan disimpan di disk.

Area Android yang terpengaruh

Ini memengaruhi semua aplikasi dan pustaka Java yang memiliki dependensi waktu proses pada pustaka Java lainnya. Android memiliki ribuan aplikasi, dan ratusan di antaranya menggunakan pustaka bersama. Mitra juga terpengaruh, karena mereka memiliki perpustakaan dan aplikasi mereka sendiri.

Melanggar perubahan

Membangun sistem perlu tahu <uses-library> dependensi sebelum menghasilkan dexpreopt aturan membangun. Namun, tidak dapat mengakses manifest langsung dan membaca <uses-library> tag di dalamnya, karena sistem build tidak diperbolehkan untuk membaca file sewenang-wenang ketika menghasilkan aturan membangun (untuk alasan kinerja). Selain itu, manifes mungkin dikemas dalam APK atau bawaan. Oleh karena itu, <uses-library> informasi harus hadir dalam membangun file ( Android.bp atau Android.mk ).

Sebelumnya ART digunakan solusi yang mengabaikan bersama dependensi library (dikenal sebagai &-classpath ). Ini tidak aman dan menyebabkan bug halus, jadi solusinya telah dihapus di Android 12.

Akibatnya, Jawa modul yang tidak memberikan benar <uses-library> informasi dalam file membangun mereka dapat menyebabkan membangun pecah (disebabkan oleh membangun-waktu CLC mismatch) atau pertama-boot regresi (disebabkan oleh boot-time CLC ketidakcocokan diikuti oleh dexopt).

Jalur migrasi

Ikuti langkah-langkah ini untuk memperbaiki build yang rusak:

  1. Nonaktifkan pemeriksaan waktu pembuatan secara global untuk produk tertentu dengan menyetel

    PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true

    dalam file make produk. Perbaikan ini membangun kesalahan (kecuali untuk kasus khusus, yang terdaftar di breakages Fixing bagian). Namun, ini adalah solusi sementara, dan dapat menyebabkan ketidakcocokan CLC waktu boot diikuti oleh dexopt.

  2. Memperbaiki modul yang gagal sebelum Anda secara global dinonaktifkan cek build-time dengan menambahkan diperlukan <uses-library> informasi untuk membangun file (lihat Memperbaiki pecah untuk rincian). Bagi kebanyakan modul ini memerlukan menambahkan beberapa baris di Android.bp , atau di Android.mk .

  3. Nonaktifkan pemeriksaan waktu pembuatan dan dexpreopt untuk kasus yang bermasalah, berdasarkan per-modul. Nonaktifkan dexpreopt sehingga Anda tidak membuang waktu pembuatan dan penyimpanan pada artefak yang ditolak saat boot.

  4. Secara global mengaktifkan kembali membangun-waktu check oleh unsetting PRODUCT_BROKEN_VERIFY_USES_LIBRARIES yang didirikan pada Langkah 1; build tidak boleh gagal setelah perubahan ini (karena langkah 2 dan 3).

  5. Memperbaiki modul yang Anda dinonaktifkan pada Langkah 3, satu per satu, kemudian mengaktifkan kembali dexpreopt dan <uses-library> cek. File bug jika perlu.

Build-time <uses-library> cek ditegakkan di Android 12.

Memperbaiki kerusakan

Bagian berikut memberi tahu Anda cara memperbaiki jenis kerusakan tertentu.

Kesalahan pembuatan: ketidakcocokan CLC

Membangun sistem melakukan build-waktu koherensi cek antara informasi di Android.bp atau Android.mk file dan memanifestasikan. Membangun sistem tidak dapat membaca nyata, tetapi dapat menghasilkan aturan membangun untuk membaca manifest (penggalian itu dari APK jika perlu), dan membandingkan <uses-library> tag di manifest terhadap <uses-library> informasi di membangun file. Jika pemeriksaan gagal, kesalahannya terlihat seperti ini:

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

Seperti yang disarankan oleh pesan kesalahan, ada beberapa solusi, tergantung pada urgensinya:

  • Untuk memperbaiki produk-lebar sementara, set PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true dalam makefile produk. Pemeriksaan koherensi waktu build masih dilakukan, tetapi kegagalan pemeriksaan tidak berarti kegagalan build. Sebaliknya, kegagalan cek membuat sistem build downgrade filter dex2oat compiler untuk verify di dexpreopt, yang menonaktifkan AOT-kompilasi sepenuhnya untuk modul ini.
  • Untuk cepat, global yang fix baris perintah, menggunakan variabel lingkungan RELAX_USES_LIBRARY_CHECK=true . Ini memiliki efek yang sama seperti halnya PRODUCT_BROKEN_VERIFY_USES_LIBRARIES , tetapi dimaksudkan untuk digunakan pada baris perintah. Variabel lingkungan menimpa variabel produk.
  • Untuk solusi untuk akar-penyebab memperbaiki kesalahan, membuat sistem build menyadari <uses-library> tag dalam manifes. Inspeksi menunjukkan pesan kesalahan yang perpustakaan penyebab masalah (seperti halnya memeriksa AndroidManifest.xml atau bagian dalam manifest dari APK yang dapat diperiksa dengan ` aapt dump badging $APK | grep uses-library `).

Untuk Android.bp modul:

  1. Carilah perpustakaan yang hilang di libs milik modul. Jika ada, Soong biasanya menambahkan perpustakaan tersebut secara otomatis, kecuali dalam kasus khusus ini:

    • Perpustakaan tidak perpustakaan SDK (itu didefinisikan sebagai java_library daripada java_sdk_library ).
    • Pustaka memiliki nama pustaka yang berbeda (dalam manifes) dari nama modulnya (dalam sistem pembangunan).

    Untuk mengatasinya sementara, tambahkan provides_uses_lib: "<library-name>" di Android.bp definisi perpustakaan. Untuk solusi jangka panjang, perbaiki masalah mendasar: konversi pustaka menjadi pustaka SDK, atau ganti nama modulnya.

  2. Jika langkah sebelumnya tidak memberikan resolusi, tambahkan uses_libs: ["<library-module-name>"] untuk diperlukan perpustakaan, atau optional_uses_libs: ["<library-module-name>"] untuk perpustakaan opsional untuk Android.bp definisi modul. Properti ini menerima daftar nama modul. Urutan relatif pustaka pada daftar harus sama dengan urutan dalam manifes.

Untuk Android.mk modul:

  1. Periksa apakah perpustakaan memiliki nama perpustakaan yang berbeda (dalam manifes) dari nama modulnya (dalam sistem pembangunan). Jika tidak, memperbaikinya sementara dengan menambahkan LOCAL_PROVIDES_USES_LIBRARY := <library-name> di Android.mk file perpustakaan, atau menambahkan provides_uses_lib: "<library-name>" di Android.bp file perpustakaan (kedua kasus yang mungkin sejak Android.mk modul mungkin bergantung pada Android.bp perpustakaan). Untuk solusi jangka panjang, perbaiki masalah mendasar: ganti nama modul perpustakaan.

  2. Menambahkan LOCAL_USES_LIBRARIES := <library-module-name> untuk diperlukan perpustakaan; menambahkan LOCAL_OPTIONAL_USES_LIBRARIES := <library-module-name> untuk perpustakaan opsional ke Android.mk definisi modul. Properti ini menerima daftar nama modul. Urutan relatif pustaka pada daftar harus sama seperti di manifes.

Kesalahan pembuatan: jalur perpustakaan tidak dikenal

Jika sistem build tidak dapat menemukan jalan ke <uses-library> DEX jar (baik membangun-waktu jalur on-host atau menginstal jalur on-device), biasanya gagal membangun. Kegagalan untuk menemukan jalur dapat menunjukkan bahwa perpustakaan dikonfigurasi dalam beberapa cara yang tidak terduga. Perbaiki sementara build dengan menonaktifkan dexpreopt untuk modul yang bermasalah.

Android.bp (properti modul):

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

Android.mk (variabel modul):

LOCAL_ENFORCE_USES_LIBRARIES := false
LOCAL_DEX_PREOPT := false

Ajukan bug untuk menyelidiki skenario yang tidak didukung.

Kesalahan pembuatan: ketergantungan perpustakaan hilang

Sebuah usaha untuk menambahkan <uses-library> X dari manifes modul Y untuk membangun file untuk Y mungkin mengakibatkan kesalahan membangun karena hilang ketergantungan, X.

Ini adalah contoh pesan kesalahan untuk modul Android.bp:

"Y" depends on undefined module "X"

Ini adalah contoh pesan kesalahan untuk modul 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

Sumber umum kesalahan tersebut adalah ketika pustaka diberi nama yang berbeda dari modul terkait yang dinamai dalam sistem pembangunan. Sebagai contoh, jika manifes <uses-library> masuk adalah com.android.X , tapi nama modul perpustakaan hanya X , hal itu menyebabkan kesalahan. Untuk mengatasi hal ini, mengatakan sistem build bahwa modul bernama X menyediakan <uses-library> bernama com.android.X .

Ini adalah contoh untuk Android.bp perpustakaan (properti modul):

provides_uses_lib: “com.android.X”,

Ini adalah contoh untuk perpustakaan Android.mk (variabel modul):

LOCAL_PROVIDES_USES_LIBRARY := com.android.X

Ketidakcocokan CLC waktu boot

Saat boot pertama, cari logcat untuk pesan yang terkait dengan ketidakcocokan CLC, seperti yang ditunjukkan di bawah ini:

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

Outputnya dapat memiliki pesan dari formulir yang ditunjukkan di sini:

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

Jika Anda mendapatkan peringatan ketidakcocokan CLC, cari perintah dexopt untuk modul yang salah. Untuk memperbaikinya, pastikan pemeriksaan waktu build untuk modul berlalu. Jika itu tidak berhasil, kasus Anda mungkin merupakan kasus khusus yang tidak didukung oleh sistem pembangunan (seperti aplikasi yang memuat APK lain, bukan pustaka). Sistem build tidak menangani semua kasus, karena pada waktu build tidak mungkin untuk mengetahui dengan pasti apa yang dimuat aplikasi saat runtime.

Konteks pemuat kelas

CLC adalah struktur seperti pohon yang menggambarkan hierarki class-loader. Sistem membangun menggunakan CLC dalam arti sempit (hanya mencakup perpustakaan, tidak APK atau loader custom-kelas): itu adalah pohon perpustakaan yang mewakili penutupan transitif dari semua <uses-library> dependensi dari perpustakaan atau aplikasi. Elemen-elemen level atas dari CLC adalah langsung <uses-library> dependensi ditentukan dalam manifes (classpath). Setiap node dari pohon CLC adalah <uses-library> simpul yang mungkin memiliki sendiri <uses-library> sub-node.

Karena <uses-library> dependensi yang diarahkan grafik asiklik, dan belum tentu pohon, CLC dapat berisi beberapa sub pohon untuk perpustakaan yang sama. Dengan kata lain, CLC adalah grafik ketergantungan yang "terbuka" ke pohon. Duplikasi hanya pada tingkat logis; pemuat kelas yang mendasari sebenarnya tidak diduplikasi (saat runtime ada satu contoh pemuat kelas untuk setiap perpustakaan).

CLC mendefinisikan urutan pencarian pustaka saat menyelesaikan kelas Java yang digunakan oleh pustaka atau aplikasi. Urutan pencarian penting karena perpustakaan dapat berisi kelas duplikat, dan kelas diselesaikan ke kecocokan pertama.

Pada perangkat (run-time) CLC

PackageManager (di frameworks/base ) menciptakan CLC untuk memuat modul Java pada perangkat. Ia menambahkan perpustakaan tercantum dalam <uses-library> tag di bermanifestasi sebagai elemen CLC tingkat atas modul.

Untuk setiap perpustakaan digunakan, PackageManager mendapat semua nya <uses-library> dependensi (ditetapkan sebagai tag dalam manifest perpustakaan itu) dan menambahkan CLC bersarang untuk setiap ketergantungan. Proses ini berlanjut secara rekursif sampai semua node daun pohon CLC yang dibangun perpustakaan tanpa <uses-library> dependensi.

PackageManager hanya menyadari shared library. Definisi shared dalam penggunaan ini berbeda dari arti biasanya (seperti dalam shared vs. static). Di Android, Java bersama perpustakaan yang terdaftar dalam konfigurasi XML yang diinstal pada perangkat ( /system/etc/permissions/platform.xml ). Setiap entri berisi nama shared library, jalan ke file DEX jar nya, dan daftar dependensi (shared library lain yang satu ini menggunakan pada saat runtime, dan menspesifikasikan di <uses-library> tag di manifest nya).

Dengan kata lain, ada dua sumber informasi yang memungkinkan PackageManager untuk membangun CLC saat runtime: <uses-library> tag di manifest, dan berbagi dependensi perpustakaan di konfigurasi XML.

CLC di-host (waktu pembuatan)

CLC tidak hanya diperlukan saat memuat pustaka atau aplikasi, tetapi juga diperlukan saat mengompilasinya. Kompilasi dapat terjadi baik di perangkat (dexopt) atau selama build (dexpreopt). Sejak dexopt berlangsung pada perangkat, ia memiliki informasi yang sama seperti PackageManager (memanifestasikan dan berbagi dependensi library). Namun, Dexpreopt berlangsung di host dan di lingkungan yang sama sekali berbeda, dan harus mendapatkan informasi yang sama dari sistem pembangunan.

Dengan demikian, membangun-waktu CLC digunakan oleh dexpreopt dan run-time CLC digunakan oleh PackageManager adalah hal yang sama, tetapi dihitung dalam dua cara yang berbeda.

Build-waktu dan run-time CLC harus bertepatan, jika kode AOT-disusun diciptakan oleh dexpreopt akan ditolak. Untuk memeriksa kesetaraan membangun-waktu dan run-time CLC, catatan dex2oat compiler build-waktu CLC di *.odex file (dalam classpath bidang file header OAT). Untuk menemukan CLC yang disimpan, gunakan perintah ini:

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

Ketidakcocokan CLC waktu build dan run-time dilaporkan di logcat selama boot. Cari dengan perintah ini:

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

Ketidakcocokan buruk untuk kinerja, karena memaksa pustaka atau aplikasi untuk di-dexopt, atau berjalan tanpa pengoptimalan (misalnya, kode aplikasi mungkin perlu diekstraksi dalam memori dari APK, operasi yang sangat mahal).

Pustaka bersama dapat bersifat opsional atau wajib. Dari sudut pandang dexpreopt, pustaka yang diperlukan harus ada pada waktu pembuatan (ketidakhadirannya adalah kesalahan pembuatan). Sebuah perpustakaan opsional dapat berupa hadir atau tidak hadir pada waktu membangun: jika ada, itu ditambahkan ke CLC, diteruskan ke dex2oat, dan dicatat dalam *.odex berkas. Jika pustaka opsional tidak ada, pustaka tersebut akan dilewati dan tidak ditambahkan ke CLC. Jika ada ketidakcocokan antara status build-time dan run-time (library opsional hadir dalam satu kasus, tetapi tidak pada kasus lainnya), maka CLC build-time dan run-time tidak cocok dan kode yang dikompilasi akan ditolak.

Detail sistem build lanjutan (pemecah masalah manifes)

Kadang-kadang <uses-library> tag yang hilang dari manifes sumber perpustakaan atau aplikasi. Hal ini dapat terjadi, misalnya, jika salah satu dari dependensi transitif perpustakaan atau aplikasi mulai menggunakan lain <uses-library> tag, dan perpustakaan atau aplikasi manifes tidak diperbarui untuk memasukkannya.

Soong dapat menghitung beberapa hilang <uses-library> tag untuk perpustakaan atau aplikasi diberikan secara otomatis, sebagai perpustakaan SDK di ketergantungan penutupan transitif perpustakaan atau aplikasi. Penutupan diperlukan karena pustaka (atau aplikasi) mungkin bergantung pada pustaka statis yang bergantung pada pustaka SDK, dan mungkin lagi bergantung secara transitif melalui pustaka lain.

Tidak semua <uses-library> tag dapat dihitung dengan cara ini, tetapi bila mungkin, lebih disarankan untuk membiarkan Soong menambahkan entri manifest secara otomatis; itu kurang rawan kesalahan dan menyederhanakan perawatan. Sebagai contoh, ketika banyak aplikasi menggunakan perpustakaan statis yang menambahkan baru <uses-library> ketergantungan, semua aplikasi harus diperbarui, yang sulit untuk mempertahankan.