Dokumen ini memberikan panduan mitra untuk meningkatkan waktu booting untuk perangkat Android tertentu. Waktu booting merupakan komponen penting kinerja sistem karena pengguna harus menunggu booting selesai sebelum dapat menggunakan perangkat. Untuk perangkat seperti mobil dimana cold boot-up lebih sering terjadi, memiliki waktu boot yang cepat sangatlah penting (tidak ada orang yang suka menunggu puluhan detik hanya untuk memasukkan tujuan navigasi).
Android 8.0 memungkinkan pengurangan waktu booting dengan mendukung beberapa peningkatan di berbagai komponen. Tabel berikut merangkum peningkatan kinerja ini (yang diukur pada perangkat Google Pixel dan Pixel XL).
Komponen | Peningkatan |
---|---|
Pemuat boot |
|
Kernel perangkat |
|
penyetelan I/O |
|
init.*.rc |
|
Animasi boot |
|
kebijakan SELinux | Disimpan 0,2 detik oleh genfscon |
Optimalkan bootloader
Untuk mengoptimalkan bootloader agar waktu booting lebih baik:
- Untuk pencatatan:
- Nonaktifkan penulisan log ke UART karena dapat memakan waktu lama dengan banyak logging. (Pada perangkat Google Pixel, kami menemukannya memperlambat bootloader 1,5 detik).
- Catat hanya situasi kesalahan dan pertimbangkan untuk menyimpan informasi lain ke memori dengan mekanisme terpisah untuk mengambilnya.
- Untuk dekompresi kernel, pertimbangkan untuk menggunakan LZ4 untuk perangkat keras kontemporer daripada GZIP (contoh patch ). Ingatlah bahwa opsi kompresi kernel yang berbeda dapat memiliki waktu pemuatan dan dekompresi yang berbeda, dan beberapa opsi mungkin bekerja lebih baik daripada opsi lainnya untuk perangkat keras spesifik Anda.
- Periksa waktu tunggu yang tidak perlu untuk debounce/entri mode khusus dan minimalkan.
- Lewati waktu boot yang dihabiskan di bootloader ke kernel sebagai cmdline.
- Periksa jam CPU dan pertimbangkan paralelisasi (memerlukan dukungan multi-core) untuk memuat kernel dan menginisialisasi I/O.
Mengoptimalkan efisiensi I/O
Meningkatkan efisiensi I/O sangat penting untuk mempercepat waktu booting, dan pembacaan apa pun yang tidak diperlukan sebaiknya ditunda hingga booting selesai (di Google Pixel, sekitar 1,2 GB data dibaca saat booting).
Sesuaikan sistem file
Pembacaan awal kernel Linux dimulai ketika file dibaca dari awal atau ketika blok dibaca secara berurutan, sehingga perlu menyetel parameter penjadwal I/O secara khusus untuk booting (yang memiliki karakterisasi beban kerja berbeda dari aplikasi normal).
Perangkat yang mendukung pembaruan tanpa batas (A/B) mendapat manfaat besar dari penyetelan sistem file saat boot pertama kali (misalnya 20 detik di Google Pixel). Sebagai contoh, kami menyetel parameter berikut untuk Google Pixel:
on late-fs # boot time fs tune # boot time fs tune write /sys/block/sda/queue/iostats 0 write /sys/block/sda/queue/scheduler cfq write /sys/block/sda/queue/iosched/slice_idle 0 write /sys/block/sda/queue/read_ahead_kb 2048 write /sys/block/sda/queue/nr_requests 256 write /sys/block/dm-0/queue/read_ahead_kb 2048 write /sys/block/dm-1/queue/read_ahead_kb 2048 on property:sys.boot_completed=1 # end boot time fs tune write /sys/block/sda/queue/read_ahead_kb 512 ...
Aneka ragam
- Aktifkan ukuran prefetch hash dm-verity menggunakan konfigurasi kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (ukuran default adalah 128).
- Untuk stabilitas sistem file yang lebih baik dan pemeriksaan paksa yang hilang yang terjadi pada setiap boot, gunakan alat generasi ext4 baru dengan mengatur TARGET_USES_MKE2FS di BoardConfig.mk.
Analisis I/O
Untuk memahami aktivitas I/O saat boot, gunakan data kernel ftrace (juga digunakan oleh systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Untuk memecah akses file untuk setiap file, lakukan perubahan berikut pada kernel (hanya kernel pengembangan; jangan gunakan di kernel produksi):
diff --git a/fs/open.c b/fs/open.c index 1651f35..a808093 100644 --- a/fs/open.c +++ b/fs/open.c @@ -981,6 +981,25 @@ } EXPORT_SYMBOL(file_open_root); +static void _trace_do_sys_open(struct file *filp, int flags, int mode, long fd) +{ + char *buf; + char *fname; + + buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return; + fname = d_path(&filp-<f_path, buf, PAGE_SIZE); + + if (IS_ERR(fname)) + goto out; + + trace_printk("%s: open(\"%s\", %d, %d) fd = %ld, inode = %ld\n", + current-<comm, fname, flags, mode, fd, filp-<f_inode-<i_ino); +out: + kfree(buf); +} + long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { struct open_flags op; @@ -1003,6 +1022,7 @@ } else { fsnotify_open(f); fd_install(fd, f); + _trace_do_sys_open(f, flags, mode, fd);
Gunakan skrip berikut untuk membantu menganalisis kinerja boot.
-
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Mengukur waktu booting dengan perincian langkah-langkah penting dalam proses booting. -
system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
Memberikan informasi akses untuk setiap file. -
system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Memberikan perincian tingkat sistem.
Optimalkan init.*.rc
Init adalah jembatan dari kernel hingga kerangka kerja dibuat, dan perangkat biasanya menghabiskan beberapa detik dalam tahapan init yang berbeda.
Jalankan tugas secara paralel
Meskipun init Android saat ini kurang lebih merupakan proses thread tunggal, Anda masih dapat melakukan beberapa tugas secara paralel.
- Jalankan perintah lambat di layanan skrip shell dan gabung nanti dengan menunggu properti tertentu. Android 8.0 mendukung kasus penggunaan ini dengan perintah
wait_for_property
baru. - Identifikasi operasi lambat di init. Sistem mencatat perintah init exec/wait_for_prop atau tindakan apa pun yang memerlukan waktu lama (di Android 8.0, perintah apa pun memerlukan waktu lebih dari 50 ms). Misalnya:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
Meninjau log ini mungkin menunjukkan peluang untuk perbaikan.
- Mulai layanan dan aktifkan perangkat periferal di jalur kritis sejak dini. Misalnya, beberapa SOC memerlukan memulai layanan terkait keamanan sebelum memulai SurfaceFlinger. Tinjau log sistem ketika ServiceManager mengembalikan "tunggu layanan" — ini biasanya merupakan tanda bahwa layanan dependen harus dimulai terlebih dahulu.
- Hapus semua layanan dan perintah yang tidak digunakan di init.*.rc. Apa pun yang tidak digunakan pada tahap awal init harus ditunda hingga booting selesai.
Catatan: Layanan properti adalah bagian dari proses init, jadi memanggil setproperty
saat boot dapat menyebabkan penundaan yang lama jika init sibuk dengan perintah bawaan.
Gunakan penyetelan penjadwal
Gunakan penyetelan penjadwal untuk boot awal. Contoh dari Google Pixel:
on init # boottime stune write /dev/stune/schedtune.prefer_idle 1 write /dev/stune/schedtune.boost 100 on property:sys.boot_completed=1 # reset stune write /dev/stune/schedtune.prefer_idle 0 write /dev/stune/schedtune.boost 0 # or just disable EAS during boot on init write /sys/kernel/debug/sched_features NO_ENERGY_AWARE on property:sys.boot_completed=1 write /sys/kernel/debug/sched_features ENERGY_AWARE
Beberapa layanan mungkin memerlukan peningkatan prioritas saat boot. Contoh:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
Mulai zigot lebih awal
Perangkat dengan enkripsi berbasis file dapat memulai zygote lebih awal di pemicu zygote-start (secara default, zygote diluncurkan di kelas main, yang lebih lambat dari zygote-start). Saat melakukan ini, pastikan untuk mengizinkan zigot berjalan di semua CPU (karena pengaturan cpuset yang salah dapat memaksa zigot berjalan di CPU tertentu).
Nonaktifkan penghematan daya
Selama booting perangkat, pengaturan hemat daya untuk komponen seperti UFS dan/atau pengatur CPU dapat dinonaktifkan.
Perhatian: Penghematan daya harus diaktifkan dalam mode pengisi daya untuk efisiensi.
on init # Disable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 0 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 0 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0 write /sys/module/lpm_levels/parameters/sleep_disabled Y on property:sys.boot_completed=1 # Enable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1 write /sys/module/lpm_levels/parameters/sleep_disabled N on charger # Enable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1 write /sys/class/typec/port0/port_type sink write /sys/module/lpm_levels/parameters/sleep_disabled N
Tunda inisialisasi nonkritis
Inisialisasi nonkritis seperti ZRAM dapat ditunda ke boot_complete
.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Optimalkan animasi boot
Gunakan tip berikut untuk mengoptimalkan animasi boot.
Konfigurasikan permulaan awal
Android 8.0 memungkinkan memulai animasi booting lebih awal, sebelum memasang partisi data pengguna. Namun, bahkan saat menggunakan rantai alat ext4 baru di Android 8.0, fsck masih terpicu secara berkala karena alasan keamanan, sehingga menyebabkan penundaan dalam memulai layanan bootanimasi.
Untuk memulai bootanimasi lebih awal, bagi pemasangan fstab menjadi dua fase:
- Pada tahap awal, pasang hanya partisi (seperti
system/
danvendor/
) yang tidak memerlukan pemeriksaan proses, lalu mulai layanan animasi booting dan dependensinya (seperti servicemanager dan Surfaceflinger). - Pada fase kedua, pasang partisi (seperti
data/
) yang memerlukan pemeriksaan jalankan.
Animasi boot akan dimulai lebih cepat (dan dalam waktu yang konstan) terlepas dari fsck.
Selesai bersih
Setelah menerima sinyal keluar, bootanimation memainkan bagian terakhir, yang durasinya dapat memperlambat waktu booting. Sistem yang melakukan booting dengan cepat tidak memerlukan animasi panjang yang dapat secara efektif menyembunyikan perbaikan apa pun yang dilakukan. Kami merekomendasikan agar perulangan berulang dan akhir menjadi pendek.
Optimalkan SELinux
Gunakan tip berikut untuk mengoptimalkan SELinux untuk meningkatkan waktu boot.
- Gunakan ekspresi reguler yang bersih (regex) . Regex yang bentuknya buruk dapat menyebabkan banyak overhead saat mencocokkan kebijakan SELinux untuk
sys/devices
difile_contexts
. Misalnya, regex/sys/devices/.*abc.*(/.*)?
secara keliru memaksa pemindaian semua subdirektori/sys/devices
yang berisi "abc", mengaktifkan kecocokan untuk/sys/devices/abc
dan/sys/devices/xyz/abc
. Meningkatkan regex ini ke/sys/devices/[^/]*abc[^/]*(/.*)?
akan mengaktifkan kecocokan hanya untuk/sys/devices/abc
. - Pindahkan label ke genfscon . Fitur SELinux yang ada ini meneruskan awalan pencocokan file ke dalam kernel dalam biner SELinux, di mana kernel menerapkannya ke sistem file yang dihasilkan kernel. Hal ini juga membantu memperbaiki file yang dibuat oleh kernel dengan label yang salah, mencegah kondisi balapan yang dapat terjadi antara proses ruang pengguna yang mencoba mengakses file ini sebelum pelabelan ulang terjadi.
Alat dan metode
Gunakan alat berikut untuk membantu Anda mengumpulkan data untuk target pengoptimalan.
Bagan boot
Bootchart menyediakan perincian beban CPU dan I/O dari semua proses untuk keseluruhan sistem. Itu tidak memerlukan pembangunan kembali citra sistem dan dapat digunakan sebagai pemeriksaan kewarasan cepat sebelum masuk ke systrace.
Untuk mengaktifkan bootchart:
adb shell 'touch /data/bootchart/enabled'
adb reboot
Setelah boot, ambil bagan boot:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
Setelah selesai, hapus /data/bootchart/enabled
untuk mencegah pengumpulan data setiap saat.
bootchart.png
tidak ada, lakukan hal berikut:- Jalankan perintah berikut:
sudo apt install python-is-python3
cd ~/Documents
git clone https://github.com/xrmx/bootchart.git
cd bootchart/pybootchartgui
mv main.py.in main.py
- Perbarui
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
agar menunjuk ke salinan lokalpybootchartgui
(terletak di~/Documents/bootchart/pybootchartgui.py
)
Systrace
Systrace memungkinkan pengumpulan jejak kernel dan Android saat boot. Visualisasi systrace dapat membantu dalam menganalisis masalah tertentu selama boot-up. (Namun, untuk memeriksa jumlah rata-rata atau jumlah akumulasi selama keseluruhan boot, lebih mudah untuk melihat jejak kernel secara langsung).
Untuk mengaktifkan systrace saat boot-up:
- Dalam
frameworks/native/cmds/atrace/atrace.rc
, ubah:write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
Ke:
# write /sys/kernel/debug/tracing/tracing_on 0 # write /sys/kernel/tracing/tracing_on 0
- Di file
device.mk
, tambahkan baris berikut:PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
- Di file
BoardConfig.mk
perangkat, tambahkan yang berikut:BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- Dalam file
init.rc
khusus perangkat, tambahkan yang berikut:on property:sys.boot_completed=1 // This stops tracing on boot complete write /d/tracing/tracing_on 0 write /d/tracing/events/ext4/enable 0 write /d/tracing/events/f2fs/enable 0 write /d/tracing/events/block/enable 0
Setelah boot, ambil jejak:
adb root && adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace
adb pull /data/local/tmp/boot_trace
$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=boot_trace
Ini mengaktifkan pelacakan (yang dinonaktifkan secara default).
Untuk analisis I/O terperinci, tambahkan juga blok dan ext4 dan f2fs.