این سند راهنمای شریک را برای بهبود زمان راهاندازی دستگاههای اندرویدی خاص ارائه میکند. زمان بوت یکی از اجزای مهم عملکرد سیستم است زیرا کاربران باید قبل از استفاده از دستگاه منتظر بمانند تا بوت کامل شود. برای دستگاههایی مانند اتومبیلهایی که بوتآپ سرد بیشتر اتفاق میافتد، داشتن زمان راهاندازی سریع بسیار مهم است (هیچکس دوست ندارد دهها ثانیه فقط برای وارد کردن مقصد ناوبری منتظر بماند).
Android 8.0 با پشتیبانی از چندین پیشرفت در طیف وسیعی از مؤلفه ها، زمان بوت شدن را کاهش می دهد. جدول زیر این بهبودهای عملکرد را خلاصه میکند (همانطور که در دستگاههای Google Pixel و Pixel XL اندازهگیری شده است).
جزء | بهبود |
---|---|
بوت لودر |
|
هسته دستگاه |
|
تنظیم I/O |
|
init.*.rc |
|
پویانمایی بوت |
|
خط مشی SELinux | 0.2 ثانیه توسط genfscon ذخیره شد |
بهینه سازی بوت لودر
برای بهینه سازی بوت لودر برای بهبود زمان بوت:
- برای ورود به سیستم:
- نوشتن گزارش در UART را غیرفعال کنید زیرا ممکن است با ورود زیاد زمان زیادی طول بکشد. (در دستگاههای Google Pixel، متوجه شدیم که بوت لودر 1.5s را کند میکند).
- فقط موقعیت های خطا را ثبت کنید و اطلاعات دیگر را با مکانیزم جداگانه برای بازیابی در حافظه ذخیره کنید.
- برای رفع فشرده سازی هسته، استفاده از LZ4 برای سخت افزارهای معاصر به جای GZIP (نمونه پچ ) در نظر گرفته شود. به خاطر داشته باشید که گزینههای مختلف فشردهسازی هسته میتوانند زمانهای بارگیری و رفع فشردهسازی متفاوتی داشته باشند و برخی از گزینهها ممکن است بهتر از سایر گزینهها برای سختافزار خاص شما کار کنند.
- زمانهای انتظار غیرضروری را برای ورود به حالت انحرافی/ویژه بررسی کنید و آنها را به حداقل برسانید.
- زمان بوت صرف شده در بوت لودر را به عنوان cmdline به هسته منتقل کنید.
- ساعت CPU را بررسی کنید و موازی سازی (نیاز به پشتیبانی چند هسته ای) را برای بارگذاری هسته و مقداردهی اولیه I/O در نظر بگیرید.
بازده ورودی/خروجی را بهینه کنید
بهبود کارایی ورودی/خروجی برای سریعتر کردن زمان راهاندازی بسیار مهم است و خواندن هر چیزی که لازم نیست باید به بعد از راهاندازی موکول شود (در Google Pixel، حدود 1.2 گیگابایت داده هنگام بوت خوانده میشود).
فایل سیستم را تنظیم کنید
خواندن پیشخوان هسته لینوکس زمانی آغاز میشود که یک فایل از ابتدا خوانده میشود یا زمانی که بلوکها به صورت متوالی خوانده میشوند، تنظیم پارامترهای زمانبندی ورودی/خروجی را بهطور خاص برای بوت کردن ضروری میسازد (که ویژگیهای بار کاری متفاوتی نسبت به برنامههای معمولی دارد).
دستگاههایی که از بهروزرسانیهای یکپارچه (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 روشن کنید (اندازه پیش فرض 128 است).
- برای پایداری بهتر سیستم فایل و بررسی اجباری حذف شده در هر بوت، از ابزار جدید تولید 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, 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 پل بین هسته تا ایجاد فریمورک است و دستگاه ها معمولاً چند ثانیه را در مراحل مختلف شروع می گذرانند.
وظایف را به صورت موازی اجرا کنید
در حالی که init فعلی اندروید کم و بیش یک فرآیند رشته ای است، هنوز هم می توانید برخی از کارها را به صورت موازی انجام دهید.
- دستورات آهسته را در یک سرویس اسکریپت پوسته اجرا کنید و بعداً با انتظار برای ویژگی خاص به آن بپیوندید. اندروید 8.0 از این مورد استفاده با دستور
wait_for_property
جدید پشتیبانی می کند. - عملیات کند را در init شناسایی کنید. سیستم دستور init exec/wait_for_prop یا هر اقدامی را که زمان زیادی می برد (در اندروید 8.0، هر فرمانی بیش از 50 میلی ثانیه طول می کشد) ثبت می کند. به عنوان مثال:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
مرور این گزارش ممکن است فرصتهایی را برای بهبود نشان دهد.
- خدمات را شروع کنید و دستگاه های جانبی را در مسیر بحرانی زودتر فعال کنید. به عنوان مثال، برخی از SOC ها قبل از راه اندازی SurfaceFlinger نیاز به راه اندازی سرویس های مرتبط با امنیت دارند. زمانی که ServiceManager «انتظار برای سرویس» را برمیگرداند، گزارش سیستم را مرور کنید - این معمولاً نشانهای است که ابتدا باید یک سرویس وابسته راهاندازی شود.
- هر گونه سرویس و دستور استفاده نشده را در init.*.rc حذف کنید. هر چیزی که در مرحله اولیه استفاده نشده باشد باید به اتمام بوت موکول شود.
توجه: سرویس Property بخشی از فرآیند init است، بنابراین اگر init در دستورات داخلی مشغول باشد، فراخوانی setproperty
در هنگام بوت میتواند منجر به تأخیر طولانی شود.
از تنظیم زمانبندی استفاده کنید
از تنظیم زمانبندی برای راه اندازی اولیه استفاده کنید. مثالی از گوگل پیکسل:
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-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 در اندروید 8.0، fsck همچنان به دلایل ایمنی به طور دورهای فعال میشود و باعث تاخیر در شروع سرویس بوتانیمیشن میشود.
برای اینکه بوتانیمیشن زودتر شروع شود، mount fstab را به دو مرحله تقسیم کنید:
- در مرحله اولیه، فقط پارتیشنهایی (مانند
system/
وvendor/
) را که نیازی به بررسی اجرا ندارند، نصب کنید، سپس سرویسهای پویانمایی بوت و وابستگیهای آن (مانند servicemanager و surfaceflinger) را شروع کنید. - در مرحله دوم، پارتیشنهایی (مانند
data/
) را که نیاز به بررسی اجرا دارند، سوار کنید.
انیمیشن بوت بدون در نظر گرفتن fsck بسیار سریعتر (و در زمان ثابت) شروع می شود.
تمیز را تمام کنید
پس از دریافت سیگنال خروج، بوتانیمیشن آخرین قسمت را اجرا می کند که طول آن می تواند زمان بوت را کاهش دهد. سیستمی که به سرعت بوت میشود، نیازی به انیمیشنهای طولانی ندارد که میتواند بهطور موثری هر گونه پیشرفت انجام شده را پنهان کند. ما توصیه می کنیم که هم حلقه تکرار و هم آخر را کوتاه کنید.
SELinux را بهینه کنید
از نکات زیر برای بهینه سازی SELinux برای بهبود زمان بوت استفاده کنید.
- از عبارات منظم تمیز (regex) استفاده کنید . Regex با شکلدهی ضعیف میتواند هنگام تطبیق خطمشی SELinux برای
sys/devices
درfile_contexts
منجر به سربار زیادی شود. به عنوان مثال، regex/sys/devices/.*abc.*(/.*)?
به اشتباه همه زیرشاخههای/sys/devices
که حاوی "abc" هستند، اسکن میکند و مطابقت را برای/sys/devices/abc
و/sys/devices/xyz/abc
فعال میکند. آیا این regex به/sys/devices/[^/]*abc[^/]*(/.*)?
تطابق را فقط برای/sys/devices/abc
فعال می کند. - برچسب ها را به genfscon منتقل کنید. این ویژگی SELinux موجود، پیشوندهای تطبیق فایل را به هسته در باینری SELinux منتقل می کند، جایی که هسته آنها را برای فایل سیستم های تولید شده توسط هسته اعمال می کند. این همچنین کمک میکند تا فایلهای دارای برچسب اشتباه ایجاد شده توسط هسته را برطرف کرده و از شرایط مسابقهای که میتواند بین فرآیندهای فضای کاربر که تلاش میکنند به این فایلها دسترسی دارند قبل از برچسبگذاری مجدد رخ دهد، جلوگیری کند.
ابزار و روش ها
از ابزارهای زیر برای کمک به جمع آوری داده ها برای اهداف بهینه سازی استفاده کنید.
بوتچارت
Bootchart تفکیک بار CPU و I/O همه فرآیندها را برای کل سیستم فراهم می کند. این نیازی به بازسازی تصویر سیستم ندارد و می تواند به عنوان یک بررسی سریع سلامت عقل قبل از فرو رفتن در 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 امکان جمعآوری ردپای هسته و اندروید را در هنگام بالا آمدن میدهد. تجسم 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 را نیز اضافه کنید.