В этом документе представлены рекомендации для партнеров по сокращению времени загрузки конкретных устройств Android. Время загрузки является важным компонентом производительности системы, поскольку пользователи должны дождаться завершения загрузки, прежде чем они смогут использовать устройство. Для таких устройств, как автомобили, где холодная загрузка происходит чаще, быстрая загрузка имеет решающее значение (никто не любит ждать десятки секунд, чтобы просто ввести пункт назначения навигации).
Android 8.0 позволяет сократить время загрузки за счет поддержки ряда улучшений в ряде компонентов. В следующей таблице суммированы эти улучшения производительности (по измерениям на устройствах Google Pixel и Pixel XL).
Компонент | Улучшение |
---|---|
загрузчик |
|
Ядро устройства |
|
Настройка ввода/вывода |
|
init.*.rc |
|
Загрузочная анимация |
|
Политика SELinux | Сэкономлено 0,2 секунды благодаря genfscon |
Оптимизировать загрузчик
Чтобы оптимизировать загрузчик для улучшения времени загрузки:
- Для ведения журнала:
- Отключите запись журнала в UART, так как при большом количестве журналов это может занять много времени. (На устройствах Google Pixel мы обнаружили, что загрузчик замедляется на 1,5 секунды).
- Регистрируйте только ситуации ошибок и рассмотрите возможность сохранения остальной информации в памяти с помощью отдельного механизма извлечения.
- Для распаковки ядра рассмотрите возможность использования LZ4 для современного оборудования вместо GZIP (пример патча ). Имейте в виду, что разные параметры сжатия ядра могут иметь разное время загрузки и распаковки, и некоторые параметры могут работать лучше, чем другие, для вашего конкретного оборудования.
- Проверьте ненужное время ожидания для входа в специальный режим или устранение дребезга и минимизируйте его.
- Передавайте время загрузки, проведенное в загрузчике, в ядро в виде командной строки.
- Проверьте тактовую частоту ЦП и рассмотрите возможность распараллеливания (требуется многоядерная поддержка) для загрузки ядра и инициализации ввода-вывода.
Оптимизация эффективности ввода-вывода
Повышение эффективности ввода-вывода имеет решающее значение для ускорения загрузки, а чтение всего ненужного следует отложить до окончания загрузки (в Google Pixel при загрузке считывается около 1,2 ГБ данных).
Настройте файловую систему
Упреждающее чтение ядра Linux срабатывает, когда файл читается с начала или когда блоки читаются последовательно, что приводит к необходимости настройки параметров планировщика ввода-вывода специально для загрузки (которая имеет другую характеристику рабочей нагрузки, чем обычные приложения).
Устройства, поддерживающие плавные (A/B) обновления, значительно выигрывают от настройки файловой системы при первой загрузке (например, 20 секунд на Google Pixel). Например, мы настроили следующие параметры для 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 ...
Разнообразный
- Включите размер предварительной выборки хеша dm-verity, используя конфигурацию ядра DM_VERITY_HASH_PREFETCH_MIN_SIZE (размер по умолчанию — 128).
- Для повышения стабильности файловой системы и отмены принудительной проверки, которая происходит при каждой загрузке, используйте новый инструмент генерации ext4, установив TARGET_USES_MKE2FS в BoardConfig.mk.
Анализ ввода/вывода
Чтобы понять действия ввода-вывода во время загрузки, используйте данные ftrace ядра (также используемые systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Чтобы разбить доступ к файлам для каждого файла, внесите в ядро следующие изменения (только для ядра разработки; не используйте в производственных ядрах):
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);
Используйте следующие сценарии для анализа производительности загрузки.
-
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Измеряет время загрузки с разбивкой важных этапов процесса загрузки. -
system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
Предоставляет информацию о доступе для каждого файла. -
system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Предоставляет разбивку на уровне системы.
Оптимизировать init.*.rc
Init — это мост от ядра до установки платформы, и устройства обычно тратят несколько секунд на разных этапах инициализации.
Запускайте задачи параллельно
Хотя текущая инициализация Android представляет собой более или менее однопоточный процесс, вы все равно можете выполнять некоторые задачи параллельно.
- Выполняйте медленные команды в службе сценариев оболочки и присоединяйтесь к ним позже, ожидая определенного свойства. Android 8.0 поддерживает этот вариант использования с помощью новой команды
wait_for_property
. - Выявление медленных операций в init. Система регистрирует команду init exec/wait_for_prop или любое действие, занимающее много времени (в Android 8.0 любая команда занимает более 50 мс). Например:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
Просмотр этого журнала может указать на возможности для улучшений.
- Запустите службы и включите периферийные устройства на критическом пути заранее. Например, некоторые SOC требуют запуска служб безопасности перед запуском SurfaceFlinger. Просмотрите системный журнал, когда ServiceManager возвращает «ожидание обслуживания» — обычно это признак того, что сначала необходимо запустить зависимую службу.
- Удалите все неиспользуемые службы и команды из init.*.rc. Все, что не используется на ранней стадии инициализации, должно быть отложено до завершения загрузки.
Примечание. Служба свойств является частью процесса инициализации, поэтому вызов setproperty
во время загрузки может привести к длительной задержке, если init занят встроенными командами.
Используйте настройку планировщика
Используйте настройку планировщика для ранней загрузки. Пример из 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
Некоторым службам может потребоваться повышение приоритета во время загрузки. Пример:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
Начните зиготу раньше
Устройства с файловым шифрованием могут запускать зиготу раньше по триггеру zygote-start (по умолчанию зигота запускается в классе main, что намного позже, чем zygote-start). При этом обязательно разрешите запуск zygote на всех процессорах (так как неправильная настройка процессорного набора может привести к запуску zygote на определенных процессорах).
Отключить энергосбережение
Во время загрузки устройства можно отключить настройку энергосбережения для таких компонентов, как UFS и/или регулятор ЦП.
Внимание: для повышения эффективности в режиме зарядного устройства необходимо включить энергосбережение.
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
Отложить некритическую инициализацию
Некритическую инициализацию, такую как ZRAM, можно отложить до boot_complete
.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Оптимизировать анимацию загрузки
Используйте следующие советы для оптимизации анимации загрузки.
Настроить ранний старт
Android 8.0 позволяет запускать загрузочную анимацию заранее, до монтирования раздела пользовательских данных. Однако даже при использовании новой цепочки инструментов ext4 в Android 8.0 fsck по-прежнему периодически запускается из соображений безопасности, что приводит к задержке запуска службы загрузочной анимации.
Чтобы бутанимация начиналась раньше, разделите монтирование fstab на две фазы:
- На раннем этапе смонтируйте только те разделы (такие как
system/
vendor/
), которые не требуют проверки запуска, затем запустите службы загрузочной анимации и их зависимости (например, servicemanager и surflinger). - На втором этапе смонтируйте разделы (например,
data/
), которые требуют проверки запуска.
Загрузочная анимация будет запускаться гораздо быстрее (и за постоянное время) независимо от fsck.
Закончите чистоту
После получения сигнала выхода заключительную часть проигрывает бутанимация, длительность которой может замедлить время загрузки. Система, которая загружается быстро, не нуждается в длительных анимациях, которые могли бы эффективно скрыть любые внесенные улучшения. Мы рекомендуем сделать повторяющийся цикл и финал короткими.
Оптимизировать SELinux
Используйте следующие советы, чтобы оптимизировать SELinux и сократить время загрузки.
- Используйте чистые регулярные выражения (regex) . Плохо сформированное регулярное выражение может привести к большим накладным расходам при сопоставлении политики SELinux для
sys/devices
вfile_contexts
. Например, регулярное выражение/sys/devices/.*abc.*(/.*)?
по ошибке принудительно сканирует все подкаталоги/sys/devices
, содержащие «abc», обеспечивая совпадение как для/sys/devices/abc
, так и/sys/devices/xyz/abc
. Улучшить это регулярное выражение до/sys/devices/[^/]*abc[^/]*(/.*)?
включит совпадение только для/sys/devices/abc
. - Переместите метки в genfscon . Эта существующая функция SELinux передает префиксы сопоставления файлов ядру в двоичном файле SELinux, где ядро применяет их к файловым системам, созданным ядром. Это также помогает исправить неправильно помеченные файлы, созданные ядром, предотвращая состояния гонки, которые могут возникнуть между процессами пользовательского пространства, пытающимися получить доступ к этим файлам, прежде чем произойдет перемаркировка.
Инструменты и методы
Используйте следующие инструменты, которые помогут вам собрать данные для целей оптимизации.
Загрузочная диаграмма
Bootchart обеспечивает разбивку загрузки ЦП и ввода-вывода всех процессов для всей системы. Он не требует перестройки образа системы и может использоваться для быстрой проверки работоспособности перед погружением в systrace.
Чтобы включить загрузочную диаграмму:
adb shell 'touch /data/bootchart/enabled'
adb reboot
После загрузки получите загрузочную диаграмму:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
По завершении удалите /data/bootchart/enabled
чтобы не собирать данные каждый раз.
bootchart.png
не существует, выполните следующие действия:- Выполните следующие команды:
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
- Обновите
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
чтобы он указывал на локальную копиюpybootchartgui
(находится по адресу~/Documents/bootchart/pybootchartgui.py
).
Систраце
Systrace позволяет собирать трассировку ядра и Android во время загрузки. Визуализация systrace может помочь проанализировать конкретную проблему во время загрузки. (Однако, чтобы проверить среднее число или накопленное число за всю загрузку, проще напрямую просмотреть трассировку ядра).
Чтобы включить systrace во время загрузки:
- В
frameworks/native/cmds/atrace/atrace.rc
измените:write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
К:
# write /sys/kernel/debug/tracing/tracing_on 0 # write /sys/kernel/tracing/tracing_on 0
- В файле
device.mk
добавьте следующую строку:PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
- В файл
BoardConfig.mk
устройства добавьте следующее:BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- В файле
init.rc
для конкретного устройства добавьте следующее: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
После загрузки получите трассировку:
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
Это включает трассировку (которая отключена по умолчанию).
Для детального анализа ввода-вывода также добавьте блок, ext4 и f2fs.