این سند راهنمایی برای شریک ارائه میدهد تا زمان راهاندازی را برای دستگاههای Android خاصی بهبود بخشد. زمان راهاندازی جزء مهمی از عملکرد سیستم است زیرا کاربران باید منتظر بمانند تا راهاندازی کامل شود و سپس بتوانند از دستگاه استفاده کنند. برای دستگاههایی مثل خودرو که راهاندازی مجدد در آنها بیشتر اتفاق میافتد، داشتن زمان راهاندازی سریع بسیار مهم است (هیچکس دوست ندارد دهها ثانیه منتظر بماند تا بتواند مقصد ناوبری را وارد کند).
Android 8.0 با پشتیبانی از چندین بهبود در طیف وسیعی از عناصر، امکان کاهش زمان راهاندازی را فراهم میکند. جدول زیر این بهبودهای عملکرد را خلاصه میکند (همانگونه که در دستگاههای Google Pixel و Pixel XL اندازهگیری شده است).
| مؤلفه | بهبود |
|---|---|
| راهانداز سیستم |
|
| هسته دستگاه |
|
| تنظیم ورودی/خروجی |
|
| init.*.rc |
|
| پویانمایی راهاندازی |
|
| خطمشی SELinux | ۰٫۲ ثانیه در genfscon ذخیره شد |
بهینهسازی راهانداز سیستم
برای بهینهسازی راهانداز سیستم برای بهبود زمانهای راهاندازی:
- برای ورود به سیستم:
- نوشتن گزارش در UART غیرفعال شود زیرا با گزارشگیری زیاد ممکن است زمان زیادی طول بکشد. (در دستگاههای Google Pixel، متوجه شدیم که این کار سرعت بارکننده را ۱٫۵ ثانیه کاهش میدهد).
- فقط وضعیتهای خطا را ثبت کنید و اطلاعات دیگر را با سازوکار جداگانهای برای بازیابی در حافظه ذخیره کنید.
- برای فشردهسازی هسته، برای سختافزار معاصر بهجای GZIP از LZ4 استفاده کنید (مثال وصله). بهخاطر داشته باشید که گزینههای مختلف فشردهسازی هسته میتوانند زمانهای بارگیری و باز کردن فشردهسازی متفاوتی داشته باشند، و برخیاز گزینهها ممکن است برای سختافزار خاص شما بهتر از بقیه عمل کنند.
- زمانهای انتظار غیرضروری برای ورود به حالت ویژه/لرزشگیری را بررسی کنید و آنها را به حداقل برسانید.
- زمان بوت صرفشده در bootloader را بهعنوان cmdline به هسته منتقل کنید.
- ساعت CPU را بررسی کنید و موازیسازی (نیازمند پشتیبانی چندهستهای) را برای بار کردن هسته و مقداردهی اولیه I/O درنظر بگیرید.
بهینهسازی کارایی ورودی/خروجی
بهبود کارایی ورودی/خروجی برای سریعتر کردن زمان راهاندازی بسیار مهم است، و خواندن هر چیزی که ضروری نیست باید تا بعداز راهاندازی بهتعویق بیفتد (در Google Pixel، حدود ۱٫۲ گیگابایت داده در زمان راهاندازی خوانده میشود).
تنظیم کردن سیستم فایل
وقتی فایلی از ابتدا خوانده میشود یا وقتی بلوکها بهترتیب خوانده میشوند، پیشخوان هسته Linux فعال میشود، که باعث میشود لازم شود پارامترهای زمانبندی ورودی/خروجی بهطور خاص برای راهاندازی تنظیم شود (که مشخصههای بار کاری متفاوتی نسبتبه برنامههای عادی دارد).
دستگاههایی که از بهروزرسانیهای یکپارچه (A/B) پشتیبانی میکنند، از تنظیم سیستم فایل در اولین راهاندازی (مثلاً ۲۰ ثانیه در 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 (اندازه پیشفرض ۱۲۸ است).
- برای پایداری بهتر سیستم فایل و بررسی اجباری حذفشدهای که در هر راهاندازی رخ میدهد، از ابزار نسل جدید ext4 با تنظیم TARGET_USES_MKE2FS در BoardConfig.mk استفاده کنید.
تجزیهوتحلیل I/O
برای درک فعالیتهای ورودی/خروجی درطول راهاندازی، از دادههای 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, const struct open_how *how, 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, how->flags, how->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 پل ارتباطی بین هسته تا زمان ایجاد چارچوب است و دستگاهها معمولاً چند ثانیه را در مراحل مختلف init سپری میکنند.
اجرای همزمان تکالیف
اگرچه مقدار اولیه Android فعلی کموبیش یک فرایند تکرشتهای است، اما همچنان میتوانید برخیاز وظایف را بهصورت موازی انجام دهید.
- فرمانهای کند را در سرویس دستورگان پوستهای اجرا کنید و بعداً با
انتظار برای دارایی خاص به آن بپیوندید. Android 8.0 از این مورد استفاده با فرمان جدید
wait_for_propertyپشتیبانی میکند. - شناسایی عملیاتهای کند در init. سیستم فرمان init
exec/wait_for_prop یا هر اقدامی را که زمان زیادی طول میکشد (در Android 8.0، هر فرمانی که
بیشتر از ۵۰ میلیثانیه طول میکشد) ثبت میکند. برای مثال:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
مرور این گزارش میتواند فرصتهایی برای بهبود را نشان دهد.
- سرویسها را شروع کنید و دستگاههای جانبی را در مسیر بحرانی زودتر فعال کنید. برای مثال، برخیاز SOCها نیاز دارند که سرویسهای مرتبط با امنیت قبلاز شروع SurfaceFlinger شروع شوند. وقتی ServiceManager پیام «انتظار برای سرویس» برمیگرداند، گزارش سیستم را مرور کنید — این معمولاً نشانهای است که سرویس وابسته باید ابتدا شروع شود.
- هرگونه سرویس و فرمان استفادهنشده را در init.*.rc بردارید. هر چیزی که در راهاندازی اولیه مرحله اولیه استفاده نمیشود باید به تکمیل بوت موکول شود.
توجه: سرویس دارایی بخشی از فرایند init است، بنابراین اگر init در
فرمانهای داخلی مشغول باشد، فراخوانی
setproperty درطول راهاندازی میتواند منجر به تأخیر طولانی شود.
استفاده از تنظیم زمانبندی
از تنظیم زمانبند برای راهاندازی اولیه استفاده کنید. مثال از 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
دستگاههای دارای رمزگذاری مبتنی بر فایل میتوانند zygote را زودتر در محرک zygote-start شروع کنند (بهطور پیشفرض، zygote در کلاس اصلی راهاندازی میشود که بسیار دیرتر از zygote-start است). هنگام انجام این کار، مطمئن شوید که به zygote اجازه میدهید در همه CPUها اجرا شود (زیرا تنظیم cpuset اشتباه ممکن است zygote را مجبور کند در CPUهای خاصی اجرا شود).
غیرفعال کردن صرفهجویی در مصرف برق
درطول راهاندازی دستگاه، تنظیمات صرفهجویی در مصرف باتری برای مؤلفههایی مانند UFS و/یا CPU میتواند غیرفعال شود.
احتیاط: برای بهرهوری، «ذخیره انرژی» باید در حالت شارژر فعال باشد.
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 همچنان بهدلیل مسائل ایمنی بهصورت دورهای راهاندازی میشود و باعث تأخیر در شروع سرویس bootanimation میشود.
برای اینکه پویانمایی راهاندازی زودتر شروع شود، نصب fstab را به دو مرحله تقسیم کنید:
- در مرحله اولیه، فقط پارتیشنهایی (مثل
system/وvendor/) را که به بررسیهای زمان اجرا نیاز ندارند نصب کنید، سپس سرویسهای پویانمایی راهاندازی و وابستگیهای آن (مثل servicemanager و surfaceflinger) را شروع کنید. - در فاز دوم، پارتیشنهایی (مانند
data/) را که نیاز به بررسی اجرا دارند، سوار کنید.
پویانمایی راهاندازی مجدد بدون درنظر گرفتن fsck خیلی سریعتر (و در زمان ثابت) شروع خواهد شد.
پایان پاکسازی
پساز دریافت سیگنال خروج، bootanimation بخش آخر را پخش میکند که طول آن میتواند زمان راهاندازی را کند کند. سیستمی که سریع راهاندازی میشود نیازی به پویانماییهای طولانی ندارد که بتواند هرگونه بهبود ایجادشده را بهطور مؤثر پنهان کند. توصیه میکنیم هم حلقه تکرارشونده و هم بخش پایانی را کوتاه بسازید.
بهینهسازی 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
Bootchart تفکیک بار CPU و I/O همه فرایندها را برای کل سیستم ارائه میدهد. این کار نیازی به بازسازی تصویر سیستم ندارد و میتوان از آن بهعنوان یک بررسی سریع قبلاز پرداختن به systrace استفاده کرد.
برای فعال کردن bootchart:
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-python3cd ~/Documentsgit clone https://github.com/xrmx/bootchart.gitcd bootchart/pybootchartguimv main.py.in main.py -
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.shرا بهروز کنید تا به نسخه محلیpybootchartgui(واقع در~/Documents/bootchart/pybootchartgui.py) اشاره کند
Systrace
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_traceadb pull /data/local/tmp/boot_trace$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=boot_trace
این کار ردیابی را فعال میکند (که بهطور پیشفرض غیرفعال است).
برای تجزیهوتحلیل دقیق ورودی/خروجی، block و ext4 و f2fs را نیز اضافه کنید.