Dokumen ini memberikan panduan kepada partner guna meningkatkan waktu booting untuk Perangkat Android. Waktu {i>booting<i} adalah komponen penting dari kinerja sistem karena pengguna harus menunggu hingga selesai {i>booting<i} sebelum dapat menggunakan perangkat. Untuk perangkat seperti mobil yang lebih sering melakukan {i> cold boot-up<i}, memiliki {i>quick boot<i} waktu sangat penting (tidak ada yang suka menunggu lusinan detik hanya untuk memasukkan tujuan navigasi).
Android 8.0 memungkinkan waktu booting yang lebih singkat dengan mendukung beberapa peningkatan pada berbagai komponen. Tabel berikut merangkum performa ini (seperti yang diukur di perangkat Google Pixel dan Pixel XL).
Komponen | Peningkatan |
---|---|
{i>Bootloader<i} |
|
Kernel perangkat |
|
penyesuaian I/O |
|
init.*.rc |
|
Animasi boot |
|
Kebijakan SELinux | Dihemat 0,2 dtk pada oleh genfscon |
Optimalkan bootloader
Untuk mengoptimalkan bootloader demi waktu booting yang lebih baik:
- Untuk logging:
- Nonaktifkan penulisan log ke UART karena bisa memakan waktu lama dengan banyak pembuatan log. (Di perangkat Google Pixel, kami menemukannya memperlambat bootloader 1.5).
- Hanya catat situasi kesalahan dan pertimbangkan untuk menyimpan informasi lainnya ke memori dengan mekanisme terpisah untuk diambil.
- Untuk dekompresi kernel, pertimbangkan penggunaan LZ4 untuk hardware kontemporer bukan GZIP (contoh patch). Perlu diingat bahwa opsi kompresi {i>kernel<i} yang berbeda bisa memiliki fungsi pemuatan yang berbeda dan waktu dekompresi, dan beberapa opsi mungkin bekerja lebih baik daripada yang lain untuk perangkat keras tertentu.
- Periksa waktu tunggu yang tidak perlu untuk entri mode debounan/khusus dan mereka.
- Teruskan waktu booting di bootloader ke kernel sebagai cmdline.
- Memeriksa clock CPU dan mempertimbangkan paralelisasi (memerlukan dukungan multi-core) untuk pemuatan {i>kernel<i} dan menginisialisasi I/O.
Mengoptimalkan efisiensi I/O
Meningkatkan efisiensi I/O sangat penting untuk mempercepat waktu booting, dan hal apa pun yang tidak diperlukan harus ditunda hingga setelah {i>booting<i} (di Google Pixel, sekitar 1,2 GB data yang dibaca saat {i>booting<i}).
Menyesuaikan sistem file
Kernel Linux {i>read forward<i} dimulai ketika file dibaca dari awal atau ketika blok dibaca secara berurutan, sehingga perlu untuk menyesuaikan penjadwal I/O parameter khusus untuk booting (yang memiliki beban kerja berbeda karakterisasi daripada aplikasi normal).
Perangkat yang mendukung update tanpa hambatan (A/B) sangat diuntungkan dengan adanya sistem file tuning pada booting pertama kali (misalnya 20 dtk di Google Pixel). Sebagai contoh, kita 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
- Mengaktifkan ukuran pengambilan data hash dm-verity menggunakan konfigurasi kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (ukuran default adalah 128).
- Untuk stabilitas sistem file yang lebih baik dan penurunan pemeriksaan paksa yang terjadi di setiap booting, gunakan alat pembuatan ext4 baru dengan menetapkan TARGET_USES_MKE2FS di {i>BoardConfig.mk.<i}
Analisis 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 memerinci akses file 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 setiap 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 {i>kernel<i} sampai kerangka kerja dibuat, dan perangkat biasanya menghabiskan beberapa detik pada berbagai tahap init.
Menjalankan 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 gabungkan nanti dengan
menunggu properti tertentu. Android 8.0 mendukung kasus penggunaan ini dengan
Perintah
wait_for_property
. - Mengidentifikasi operasi lambat dalam init. Sistem mencatat perintah init ke dalam log
{i>exec/wait_for_prop<i} atau tindakan apa pun yang memakan waktu lama (di Android 8.0, perintah apa pun
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.
- Memulai layanan dan mengaktifkan perangkat periferal di jalur kritis lebih awal. Sebagai misalnya, beberapa SOC mengharuskan memulai layanan terkait keamanan sebelum memulai SurfaceFlinger. Tinjau log sistem saat ServiceManager menampilkan "wait for 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 di init tahap awal harus ditunda hingga proses {i>booting<i} 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 scheduler
Menggunakan penyesuaian scheduler 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 ...
Mulai zygote lebih awal
Perangkat dengan enkripsi berbasis file dapat memulai zygote lebih awal pada zygote-start (secara default, zygote diluncurkan di class main, yang berlangsung lebih lama dari zygote-start). Ketika melakukannya, pastikan untuk mengizinkan zygote berjalan di semua CPU (seperti pengaturan cpuset yang salah dapat memaksa zygote untuk berjalan di CPU tertentu).
Nonaktifkan mode hemat daya
Selama booting perangkat, setelan hemat daya untuk komponen seperti UFS dan/atau CPU gubernur dapat dinonaktifkan.
Perhatian: Mode hemat daya akan diaktifkan di 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 yang tidak penting
Inisialisasi tidak penting seperti ZRAM dapat dialihkan ke boot_complete
.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Mengoptimalkan animasi boot
Gunakan tips berikut untuk mengoptimalkan animasi booting.
Konfigurasi mulai awal
Android 8.0 memungkinkan animasi booting lebih awal, sebelum memasang data pengguna partisi. Namun, bahkan saat menggunakan rantai alat ext4 baru di Android 8.0, {i>fsck<i} masih dipicu secara berkala karena alasan keamanan, menyebabkan keterlambatan dalam memulai layanan {i>boot<i}.
Agar bootanimasi dimulai lebih awal, bagi pemasangan fstab menjadi dua fase:
- Pada fase awal, pasang partisi saja (seperti
system/
danvendor/
) yang tidak memerlukan run pemeriksaan, lalu memulai layanan animasi booting dan dependensinya (seperti servicemanager dan surfaceflinger). - Pada fase kedua, pasang partisi (seperti
data/
) yang memerlukan pemeriksaan yang berjalan.
Animasi {i>booting<i} akan dimulai jauh lebih cepat (dan dalam waktu yang konstan) terlepas dari {i>fsck<i}.
Finishing bersih
Setelah menerima sinyal keluar, bootanimasi memainkan bagian terakhir, panjang yang dapat memperlambat waktu booting. Sistem yang melakukan {i>booting<i} dengan cepat tidak perlu waktu yang lama animasi yang secara efektif dapat menyembunyikan setiap peningkatan yang dilakukan. Saran dari kami membuat pengulangan dan pengulangan menjadi pendek.
Mengoptimalkan SELinux
Gunakan tips berikut untuk mengoptimalkan SELinux agar waktu booting menjadi lebih baik.
- Gunakan ekspresi reguler yang bersih (regex). Format ekspresi reguler tidak tepat
dapat menyebabkan banyak {i>overhead<i}
saat mencocokkan kebijakan SELinux untuk
sys/devices
dalamfile_contexts
. Misalnya, ekspresi reguler/sys/devices/.*abc.*(/.*)?
keliru memaksa pemindaian semua/sys/devices
subdirektori yang berisi "abc", mengaktifkan kecocokan untuk/sys/devices/abc
dan/sys/devices/xyz/abc
. Meningkatkan ekspresi reguler 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 di biner SELinux, di mana {i>kernel<i} menerapkannya ke file yang dihasilkan {i>kernel<i} sistem file. Hal ini juga membantu memperbaiki file yang dibuat {i>kernel<i} yang salah label, kondisi perlombaan yang dapat terjadi di antara proses ruang pengguna yang mencoba mengakses file ini sebelum dilakukan pelabelan ulang.
Alat dan metode
Gunakan alat berikut untuk membantu Anda mengumpulkan data untuk target pengoptimalan.
Diagram Booting
Bootchart menyediakan perincian beban CPU dan I/O dari semua proses untuk keseluruhan sistem file. Tidak memerlukan pembangunan ulang image sistem dan dapat digunakan sebagai pemeriksaan kesehatan sebelum mendalami 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
untuk 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 komputer {i>booting<i}. (Namun, untuk memeriksa jumlah rata-rata atau jumlah akumulasi selama sehingga 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
- Dalam 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 hal berikut:BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- Di file
init.rc
khusus perangkat, tambahkan hal 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 trace:
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 terperinci, tambahkan juga blok, ext4 dan f2fs.