Итак, на руках у меня довольно свежий продукт от компании Xiaomi - Smart Band 10 Pro.
В отличие от Band 9 Pro - апгрейд в основном затронул систему, но и как же без ложки дегтя:
глобальная версия опять со сломанными JerryScript приложениями - зачем делать приложения - а чтобы юзеры не стонали - просто вырежем движок - лол, молодцы, что уж..

Что же мы имеем, практически тот же BEST1503 - это внутренний идентификатор SoC, внешне это BES2700iMP, какая то его ревизия - не вскрывал еще данную модель,
только внутренний flash 16Mb, против 8 у 9Pro, и порядка 16Mb PSRAM, внешний SPI флеш на 512Mb (256Mb для обычной глобалки)
Устройство системы
В качестве операционной системы, тут опять используется RTOS NuttX OS, очень приятная embedded операционка, здесь неплохой shell, поддержка встроенных и загружаемых приложений.
Ну и классически Xiaomi встраивает 2 движка JerryScript для приложений и LUA для циферблатов, с практически полным сток API Lua 5.4
Именно в этой модели - здесь довольно продвинутый shell, например, позволяет читать в переменную вывод работы команды, что мне не хватало в Redmi Watch 5 с которыми я работал до этого.

внешний SPI Nand flash разбит на следующие сектора, resource - romfs образ системного раздела, nand_data - yaffs RW данные, циферблаты, приложения, данные фитнеса и т.п.

структура внутреннего флеш выглядит вот так, bl2 - secondary bootloader, ap - непосредственно главное приложение, mode/nv - настройки устройства, ну и в данном случае, это данные драйвера ap - не хватает раздела bl - primary bootloader, но он и не нужен.
Запускается устройство в таком порядке:
1. bl - primary bootloader - делает базовую инициализацию, смотрит на флаги загрузки - прописывает ключи setprop параметры загрузки, передает управление bl2
2. bl2 - secondary bootloader - смотрит причину сброса, выбирает режим загрузки - передает управление в app/recovery/factory
3. в обычном режиме запускает app - основное приложение, либо recovery приложение, либо factory mode.
каждый сегмент прошивки - это отдельная NuttX сборка, в каждой сборке в приложение зашит etc romfs, содержащий скрипты инициализации /etc/init.d/rcS и /etc/init.d/rc.sysinit,
первым выполняется rc.sysinit, затем rcS.
Проблема recovery
Как работает сток механизм рекавери:
любой сбой в приложении перезагружает устройство, которое попадает в bl2 загрузчик, посмотрим как работает его скрипт rcS - именно он отвечает за логику загрузки устройства.
set +e set -x echo "you are running bl2" set resetcause `resetcause` echo $resetcause if [ "$resetcause" == "cpu_soft_reset(restore)" -o "$resetcause" == "cpu_soft_reset(factory)" ] then echo "recovery reset system" # обработка reboot с флагом restore/factory sh /etc/recovery_reset.sh # запуск очистки раздела /data fi if [ "$resetcause" == "cpu_soft_reset(bootloader)" ] then rb -f /dev --skip_prefix vela_ --skip_suffix .bin reboot fi if [ -e /data/ota.zip ] # если нашли /data/ota.zip - запускаем установку OTA then echo "mount ota.zip to /ota" mount -t zipfs -o /data/ota.zip /ota set errcode $? if [ $errcode -ne 0 ] then echo "mount ota.zip failed!!!" setprop persist.ota_fail 1 else set ota_in_progress `getprop persist.ota.inprocess` echo $ota_in_progress if [ "$ota_in_progress" == "0" ] then setprop persist.bl2.ota.trytimes 0 else # механизм защиты от сбоев при установке OTA обновления set trytimes `getprop persist.bl2.ota.trytimes` set trytimes `expr $trytimes + 1` echo $trytimes if [ $trytimes -gt 5 ] then setprop persist.bl2.ota.trytimes 0 setprop persist.ota.precheck.finished 0 setprop persist.ota.inprocess 0 echo "Tried many times" rm -r /data/ota_tmp rm /data/ota.zip reboot else setprop persist.bl2.ota.trytimes $trytimes fi fi if [ "$resetcause" == "cpu_soft_reset(recovery)" -o "$ota_in_progress" == "1" ] then avb_verify /ota/vela_ota.bin /etc/key.avb # проверка цифровой подписи установщика if [ $? -eq 0 ] then echo "Recovery Mode (OTA).." cp -f /ota/vela_ota.bin /data/vela_ota.bin boot /data/vela_ota.bin echo "Boot ota failed!" else echo "Verify ota failed!" setprop persist.ota.precheck.finished 0 setprop persist.ota_fail 1 rm /data/ota.zip reboot fi fi fi fi miwear_recovery_boot set boot_reset `getprop boot_reset_flag` echo $boot_reset if [ "$boot_reset" == "1" ] then echo "jump boot reset mode" mount -t romfs /dev/resource /resource boot /resource/prebuild/vela_recovery.bin # загрузка recovery ELF приложения echo "Boot recovery failed!" fi set factory_finished `getprop ro.factory.finished` echo $factory_finished if [ "$factory_finished" != "1" ] then echo "Boot factory" mount -t romfs /dev/resource /resource boot /resource/prebuild/vela_factory.bin # загрузка factory ELF приложения echo "Boot factory failed!" fi echo "save checkpt" umount -f /data echo "System Mode (AP).." boot echo "Boot ap failed!"
у режима загрузки - resetcause - как видите есть несколько состояний:
normal
bootloader
restore
factory
Это все параметры команды reboot <param>.
Режимы restore/factory запускают скрипт /etc/recovery_reset.sh, который просто форматирует раздел c данными - пользовательские кривые циферблаты или приложения.
set +e echo "umount /data" umount -f /data echo "force format /data" mount -t yaffs -o forceformat /dev/nand_data /data
Это все хорошо, только это нисколько не спасает от сбойного приложения.
В случае когда падает основное приложение - ap, rcS скрипт попадает в строки 68-75 и запускает в RAM ELF приложение boot /resource/prebuild/vela_recovery.bin
задача этого приложения вывести ошибку на экран и дать пользователю одну единственную кнопку - сбросить данные - выполнить команду - reboot restore
В результате этого действия, скрипт rcS попадает в строки 6-9 и происходит очистка внешней флешки, раздела nand_data - идет очистка данных, дальше идет загрузка сбойного ap - и все повторяется по кругу - получаем циклический ребут.
Улучшаем механизм recovery
Самое интересное, что данный механизм реализован не только во флагманских Watch S3/S4/S5 но и в Xiaomi Smart Band 10, ну и в Mi Band 11 (там прошивка 1в1 как у нашего пациента)
Как же он работает?
А очень просто - системный раздел содержит backup OTA пакет, который не содержит ресурсов, а содержит лишь необходимый минимум для функционирования часов. Слава богу, китайцы научились делать независимые от ресурсов сборки и корректно обрабатывают, как отсутствие текстовых ресурсов i18n, так и графических.

благодаря выстроенной системе код рекавери очень простой и краткий.

вот полный OTA пакет, vela_resource.bin это системый romfs, который монтируется в /resource при старте системы, в случае bl2 он не нужен и не монтируется.

fac_to_user.zip - это recovery OTA пакет с минимальным содержимым для обновления.
Нам остается только упаковать fac_to_user.zip в romfs - vela_resource.bin
и переписать скрипт загрузчика vela_bl2.bin.
Итоговый код загрузчика
set +e set -x echo "you are running bl2" set resetcause `resetcause` echo $resetcause if [ "$resetcause" == "cpu_soft_reset(restore)" ] # здесь идет копирование recovery then # OTA в стандартный путь обновления echo "recovery restore system" # система дальше автоматом mount -t romfs /dev/resource /resource # начинает установку cp /resource/prebuild/fac_to_user.zip /data/ota.zip sh /etc/recovery_reset.sh fi if [ "$resetcause" == "cpu_soft_reset(factory)" ] then echo "recovery reset system" sh /etc/recovery_reset.sh fi if [ "$resetcause" == "cpu_soft_reset(bootloader)" ] then rb -f /dev --skip_prefix vela_ --skip_suffix .bin reboot fi if [ -e /data/ota.zip ] then echo "mount ota.zip to /ota" mount -t zipfs -o /data/ota.zip /ota set errcode $? ...
Самое интересное код Secondary bootloader разработчики включили в пакет OTA, т.е. даже стараться не нужно его достать, вот вам пример как не нужно делать прошивки господа.
Обход цифровой подписи и запись OTA настолько банальны, что даже не буду рассказывать, чтобы не поломать чуткое китайское самолюбие.
Всем добра и интересных гаджетов.