Dokumen ini memberikan panduan partner untuk meningkatkan waktu booting untuk perangkat Android tertentu. Waktu booting adalah komponen penting dari performa sistem karena pengguna harus menunggu booting selesai sebelum dapat menggunakan perangkat. Untuk perangkat seperti mobil yang sering melakukan cold boot, memiliki waktu booting yang cepat sangatlah penting (tidak ada 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 meringkas peningkatan performa ini (seperti yang diukur pada perangkat Google Pixel dan Pixel XL).
Komponen | Peningkatan |
---|---|
Bootloader |
|
Kernel perangkat |
|
Penyesuaian I/O |
|
init.*.rc |
|
Animasi booting |
|
Kebijakan SELinux | Menyimpan 0,2 detik dengan genfscon |
Mengoptimalkan bootloader
Untuk mengoptimalkan bootloader agar waktu booting lebih baik:
- Untuk logging:
- Nonaktifkan penulisan log ke UART karena dapat memerlukan waktu lama dengan banyak logging. (Di perangkat Google Pixel, kami mendapati bahwa hal ini memperlambat bootloader 1,5 detik).
- Catat hanya situasi error dan pertimbangkan untuk menyimpan informasi lain ke memori dengan mekanisme terpisah untuk diambil.
- Untuk dekompresi kernel, pertimbangkan untuk menggunakan LZ4 untuk hardware kontemporer, bukan GZIP (contoh patch). Perlu diingat bahwa opsi kompresi kernel yang berbeda dapat memiliki waktu pemuatan dan dekompresi yang berbeda, dan beberapa opsi mungkin berfungsi lebih baik daripada yang lain untuk hardware tertentu.
- Periksa waktu tunggu yang tidak perlu untuk debouncing/entri mode khusus dan minimalkan waktu tunggu tersebut.
- Teruskan waktu booting yang dihabiskan di bootloader ke kernel sebagai cmdline.
- Periksa clock CPU dan pertimbangkan paralelisasi (memerlukan dukungan multi-core) untuk pemuatan kernel dan inisialisasi I/O.
Mengoptimalkan efisiensi I/O
Meningkatkan efisiensi I/O sangat penting untuk mempercepat waktu booting, dan membaca apa pun yang tidak diperlukan harus ditangguhkan hingga setelah booting (di Google Pixel, sekitar 1,2 GB data dibaca saat booting).
Menyesuaikan sistem file
Pembacaan di depan kernel Linux dimulai saat file dibaca dari awal atau saat blok dibaca secara berurutan, sehingga perlu menyesuaikan parameter penjadwal I/O secara khusus untuk booting (yang memiliki karakterisasi beban kerja yang berbeda dari aplikasi normal).
Perangkat yang mendukung update lancar (A/B) sangat diuntungkan dari penyesuaian sistem file saat pertama kali melakukan booting (misalnya, 20 detik di Google Pixel). Sebagai contoh, kami menyesuaikan 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 ...
Lain-lain
- 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 dihapus yang terjadi pada setiap booting, gunakan alat pembuatan ext4 baru dengan menetapkan TARGET_USES_MKE2FS di BoardConfig.mk.
Menganalisis I/O
Untuk memahami aktivitas I/O selama booting, gunakan data ftrace kernel (juga digunakan oleh systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Untuk menguraikan akses file untuk setiap file, buat perubahan berikut pada kernel (khusus kernel pengembangan; jangan gunakan dalam 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 performa booting.
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 per file.system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Memberikan perincian tingkat sistem.
Mengoptimalkan init.*.rc
Init adalah jembatan dari kernel hingga framework dibuat, dan perangkat biasanya menghabiskan beberapa detik dalam berbagai tahap init.
Menjalankan tugas secara paralel
Meskipun init Android saat ini kurang lebih merupakan proses dengan satu thread, Anda masih dapat melakukan beberapa tugas secara paralel.
- Jalankan perintah lambat di layanan skrip shell dan gabungkan nanti dengan
menunggu properti tertentu. Android 8.0 mendukung kasus penggunaan ini dengan perintah
wait_for_property
baru. - Identifikasi operasi yang lambat di init. Sistem mencatat log perintah init
exec/wait_for_prop atau tindakan apa pun yang memerlukan waktu lama (di Android 8.0, perintah apa pun
yang memerlukan waktu lebih dari 50 md). Contoh:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
Meninjau log ini dapat menunjukkan peluang untuk peningkatan.
- Mulai layanan dan aktifkan perangkat periferal di jalur kritis lebih awal. Misalnya, beberapa SOC memerlukan layanan terkait keamanan yang dimulai sebelum memulai SurfaceFlinger. Tinjau log sistem saat ServiceManager menampilkan "tunggu layanan" — ini biasanya merupakan tanda bahwa layanan dependen harus dimulai terlebih dahulu.
- Hapus layanan dan perintah yang tidak digunakan di init.*.rc. Apa pun yang tidak digunakan dalam inisialisasi tahap awal harus ditangguhkan hingga booting selesai.
Catatan: Layanan properti adalah bagian dari proses init, sehingga memanggil
setproperty
selama booting dapat menyebabkan penundaan yang lama jika init sibuk dalam
perintah bawaan.
Menggunakan penyesuaian penjadwal
Gunakan penyesuaian penjadwal untuk booting 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 selama booting. Contoh:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
Memulai zygote lebih awal
Perangkat dengan enkripsi berbasis file dapat memulai zygote lebih awal pada pemicu zygote-start (secara default, zygote diluncurkan di class utama, yang jauh lebih lambat daripada zygote-start). Saat melakukannya, pastikan untuk mengizinkan zygote berjalan di semua CPU (karena setelan cpuset yang salah dapat memaksa zygote berjalan di CPU tertentu).
Menonaktifkan mode hemat daya
Selama booting perangkat, setelan hemat daya untuk komponen seperti UFS dan/atau pengontrol CPU dapat dinonaktifkan.
Perhatian: Hemat 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
Menunda inisialisasi non-penting
Inisialisasi non-penting seperti ZRAM dapat ditangguhkan ke boot_complete
.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Mengoptimalkan animasi booting
Gunakan tips berikut untuk mengoptimalkan animasi booting.
Mengonfigurasi awal mulai
Android 8.0 memungkinkan animasi booting dimulai lebih awal, sebelum memasang partisi userdata. Namun, meskipun menggunakan rantai alat ext4 baru di Android 8.0, fsck masih dipicu secara berkala karena alasan keamanan, sehingga menyebabkan penundaan dalam memulai layanan bootanimation.
Agar animasi booting dimulai lebih awal, bagi pemasangan fstab menjadi dua fase:
- Pada fase awal, hanya pasang partisi (seperti
system/
danvendor/
) yang tidak memerlukan pemeriksaan operasi, lalu mulai layanan animasi booting dan dependensinya (seperti servicemanager dan surfaceflinger). - Pada fase kedua, pasang partisi (seperti
data/
) yang memerlukan pemeriksaan run.
Animasi booting akan dimulai jauh lebih cepat (dan dalam waktu konstan) terlepas dari fsck.
Selesaikan pembersihan
Setelah menerima sinyal keluar, bootanimation akan memutar bagian terakhir, yang durasinya dapat memperlambat waktu booting. Sistem yang melakukan booting dengan cepat tidak memerlukan animasi yang panjang yang dapat secara efektif menyembunyikan peningkatan apa pun yang dilakukan. Sebaiknya buat loop berulang dan akhiran singkat.
Mengoptimalkan SELinux
Gunakan tips berikut untuk mengoptimalkan SELinux agar waktu booting lebih baik.
- Gunakan ekspresi reguler (regex) yang bersih. Regex yang dibentuk dengan buruk
dapat menyebabkan banyak overhead saat mencocokkan kebijakan SELinux untuk
sys/devices
difile_contexts
. Misalnya, ekspresi reguler/sys/devices/.*abc.*(/.*)?
secara keliru memaksa pemindaian semua subdirektori/sys/devices
yang berisi "abc", sehingga memungkinkan pencocokan untuk/sys/devices/abc
dan/sys/devices/xyz/abc
. Meningkatkan ekspresi reguler ini ke/sys/devices/[^/]*abc[^/]*(/.*)?
akan memungkinkan kecocokan hanya untuk/sys/devices/abc
. - Pindahkan label ke genfscon. Fitur SELinux yang ada ini meneruskan awalan pencocokan file ke kernel dalam biner SELinux, tempat kernel menerapkannya ke sistem file yang dibuat kernel. Hal ini juga membantu memperbaiki file yang dibuat kernel yang salah diberi label, sehingga mencegah kondisi perlombaan yang dapat terjadi antara proses ruang pengguna yang mencoba mengakses file ini sebelum pemberian label ulang terjadi.
Alat dan metode
Gunakan alat berikut untuk membantu Anda mengumpulkan data untuk target pengoptimalan.
Bootchart
Bootchart memberikan perincian beban CPU dan I/O dari semua proses untuk seluruh sistem. Tindakan ini tidak memerlukan pembuatan ulang image sistem dan dapat digunakan sebagai pemeriksaan kewarasan cepat sebelum mempelajari systrace.
Untuk mengaktifkan bootchart:
adb shell 'touch /data/bootchart/enabled'
adb reboot
Setelah booting, ambil diagram booting:
$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 mengarah ke salinan lokalpybootchartgui
(terletak di~/Documents/bootchart/pybootchartgui.py
)
Systrace
Systrace memungkinkan pengumpulan rekaman aktivitas kernel dan Android selama booting. Visualisasi systrace dapat membantu menganalisis masalah tertentu selama proses booting. (Namun, untuk memeriksa jumlah rata-rata atau jumlah akumulasi selama seluruh booting, akan lebih mudah untuk melihat pelacakan kernel secara langsung).
Untuk mengaktifkan systrace selama booting:
- Di
frameworks/native/cmds/atrace/atrace.rc
, ubah:write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
Untuk:
# 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 kode 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 kode 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 booting, ambil rekaman aktivitas:
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
Tindakan ini akan mengaktifkan pelacakan (yang dinonaktifkan secara default).
Untuk analisis I/O mendetail, tambahkan juga blok dan ext4 serta f2fs.