Po co smartfonom Xiaomi ROM'y fastboot i jak z nich korzystać

Spis treści

Przeglądając jakiś czas temu oficjalną stronę Xiaomi w poszukiwaniu nowszych wersji oficjalnego ROM'u na mój smartfon Redmi 9, zauważyłem, że są tam dostępne instrukcje na temat wgrania takiego oprogramowania za pomocą trybu fastboot. Trochę się zdziwiłem, bo przecie ROM'y dostarczane są w paczkach .zip , przez co nie są one przeznaczone do wgrywania w tym trybie. Tak czy inaczej, zgodnie z informacją, która widnieje na tamtej stronie, te linki do obrazów fastboot jeszcze nie zostały wypuszczone, przynajmniej oficjalnie. Nieoficjalnie zaś można je pobrać ze strony xiaomifirmwareupdater.com. To, co się rzuca od razu w oczy, to rozmiar takiego pliku, bo standardowo pliki z ROM'em MIUI ważą około 2,2 GiB. ROM'y fastboot mają rozmiar około 4,5 GiB. Kolejna sprawa, to rozszerzenie samego pliku. W przypadku standardowego ROM'u mamy .zip , a ROM'y fastboot mają już rozszerzenie .tar.gz lub .tgz . Nie mogłem przejść obojętnie obok tej zagadki i postanowiłem sprawdzić, co taka paczka w sobie zawiera i do czego ewentualnie ona może nam się przydać w kontekście alternatywnego oprogramowania wrzucanego na telefon.

Zawartość ROM'u fastboot

Wszystkie alternatywne ROM'y na bazie AOSP/LineageOS zalecają, czy też wręcz wymagają, od nas by przed instalacją takiego oprogramowania, w telefonie znajdował się stock'owy ROM w określonej wersji, zwykle MIUI v12.0.1.0. Biorąc pod uwagę taki stan rzeczy, postanowiłem zaciągnąć na swój komputer właśnie ten najbardziej pożądany ROM, tj. plik lancelot_eea_global_images_V12.0.1.0.QJCEUXM_20210119.0000.00_10.0_eea_a197df7d17.tgz. Po wypakowaniu tej paczki, jej zawartość prezentuje następująco:

$ tree -pugsh lancelot_eea_global_images_V12.0.1.0.QJCEUXM_20210119.0000.00_10.0_eea
lancelot_eea_global_images_V12.0.1.0.QJCEUXM_20210119.0000.00_10.0_eea
├── [drwxr-xr-x morfik   morfik   4.0K]  AP
│   ├── [-rw-r--r-- morfik   morfik   191K]  APDB_MT6768_S01__W2006
│   └── [-rw-r--r-- morfik   morfik    20K]  APDB_MT6768_S01__W2006_ENUM
├── [drwxr-xr-x morfik   morfik   4.0K]  BP
│   ├── [-rw-r--r-- morfik   morfik   3.5M]  DbgInfo_LR12A.R3.MP_HUAQIN_Q0MP1_MT6769_SP_MOLY_LR12A_R3_MP_V98_P75_2020_12_18_14_28_1_ulwctg_n
│   ├── [-rw-r--r-- morfik   morfik   211K]  MDDB.META.ODB_MT6768_S00_MOLY_LR12A_R3_MP_V98_P75_1_ulwctg_n.XML.GZ
│   ├── [-rw-r--r-- morfik   morfik   310K]  MDDB.META_MT6768_S00_MOLY_LR12A_R3_MP_V98_P75_1_ulwctg_n.EDB
│   └── [-rw-r--r-- morfik   morfik    16M]  MDDB_InfoCustomAppSrcP_MT6768_S00_MOLY_LR12A_R3_MP_V98_P75_1_ulwctg_n.EDB
├── [drwxr-xr-x morfik   morfik   4.0K]  BP_IN
├── [-rwxr-xr-x morfik   morfik    40K]  CheckSum_Gen
├── [drwxr-xr-x morfik   morfik   4.0K]  Log
│   └── [-rw-r--r-- morfik   morfik    204]  ADPT_20210119-212711_0.log
├── [-rwxr-xr-x morfik   morfik     99]  check_sum.sh
├── [-rwxr-xr-x morfik   morfik   2.7K]  flash_all.bat
├── [-rwxr-xr-x morfik   morfik   3.3K]  flash_all.sh
├── [-rwxr-xr-x morfik   morfik   2.6K]  flash_all_except_data_storage.bat
├── [-rwxr-xr-x morfik   morfik   3.2K]  flash_all_except_data_storage.sh
├── [-rwxr-xr-x morfik   morfik   3.1K]  flash_all_lock.bat
├── [-rwxr-xr-x morfik   morfik   3.6K]  flash_all_lock.sh
├── [-rwxr-xr-x morfik   morfik   5.3K]  flash_gen_crc_list.py
├── [-rwxr-xr-x morfik   morfik   1.3K]  flash_gen_md5_list.py
├── [-rwxr-xr-x morfik   morfik   842K]  flash_gen_resparsecount
├── [-rwxr-xr-x morfik   morfik    989]  hat_extract.py
├── [-rwxr-xr-x morfik   morfik    591]  hat_flash.sh
├── [drwxr-xr-x morfik   morfik   4.0K]  images
│   ├── [-rw-r--r-- morfik   morfik    422]  Checksum.ini
│   ├── [-rw-r--r-- morfik   morfik    20K]  MT6768_Android_scatter.txt
│   ├── [-rw-r--r-- morfik   morfik    64M]  boot.img
│   ├── [-rw-r--r-- morfik   morfik   176K]  cache.img
│   ├── [-rw-r--r-- morfik   morfik    245]  crclist.txt
│   ├── [-rw-r--r-- morfik   morfik   652M]  cust.img
│   ├── [-rw-r--r-- morfik   morfik    16M]  dtbo.img
│   ├── [-rw-r--r-- morfik   morfik    512]  efuse.img
│   ├── [-rw-r--r-- morfik   morfik   200M]  exaid.img
│   ├── [-rw-r--r-- morfik   morfik    16K]  gsort.img
│   ├── [-rw-r--r-- morfik   morfik   1.6M]  lk.img
│   ├── [-rw-r--r-- morfik   morfik   1.5M]  logo.bin
│   ├── [-rw-r--r-- morfik   morfik    56M]  md1img.img
│   ├── [-rw-r--r-- morfik   morfik    16K]  oem_misc1.img
│   ├── [-rw-r--r-- morfik   morfik   270K]  preloader_lancelot.bin
│   ├── [-rw-r--r-- morfik   morfik    64M]  recovery.img
│   ├── [-rw-r--r-- morfik   morfik   344K]  scp.img
│   ├── [-rw-r--r-- morfik   morfik     56]  sparsecrclist.txt
│   ├── [-rw-r--r-- morfik   morfik    37K]  spmfw.img
│   ├── [-rw-r--r-- morfik   morfik   493K]  sspm.img
│   ├── [-rw-r--r-- morfik   morfik   4.1G]  super.img
│   ├── [-rw-r--r-- morfik   morfik   2.3M]  tee.img
│   ├── [-rw-r--r-- morfik   morfik   1.2G]  userdata.img
│   ├── [-rw-r--r-- morfik   morfik   4.0K]  vbmeta.img
│   ├── [-rw-r--r-- morfik   morfik   4.0K]  vbmeta_system.img
│   └── [-rw-r--r-- morfik   morfik   4.0K]  vbmeta_vendor.img
├── [-rw-r--r-- morfik   morfik   1.6M]  libflashtool.so
├── [-rw-r--r-- morfik   morfik   7.0M]  libflashtool.v1.so
├── [-rw-r--r-- morfik   morfik   6.6M]  libflashtoolEx.so
├── [-rw-r--r-- morfik   morfik   2.2K]  md5sum.xml
└── [-rw-r--r-- morfik   morfik     81]  misc.txt

Zatem mamy tutaj parę skryptów, no i też jest szereg obrazów .img , a konkretnie jest ich aż 22, jeśli dobrze policzyłem. Jest tam też plik o bardzo dźwięcznej nazwie, tj. flash_all.sh . Jako, że jest to skrypt shell'owy, to podejrzałem go sobie, by zobaczyć co takiego on skrywa, choć po jego nazwie nietrudno zgadnąć. Sam skrypt nie jest jako rozbudowany, więc cała jego treść jest poniżej:

fastboot $* getvar product 2>&1 | grep -E "^product: *lancelot$"
if [ $? -ne 0 ] ; then echo "error : Missmatching image and device"; exit 1; fi

CURRENT_ANTI_VER=2
version=`fastboot getvar rollback_ver 2>&1 | grep "rollback_ver:" | awk -F ": " '{print $2}'`
if [  "${version}"x == ""x ] ; then version=0 ; fi
if [ ${version} -gt ${CURRENT_ANTI_VER} ] ; then  echo "error : current device antirollback #version is greater than this package" ; exit 1 ; fi

#fastboot $* erase boot
#if [ $? -ne 0 ] ; then echo "Erase boot error"; exit 1; fi
fastboot $* flash preloader `dirname $0`/images/preloader_lancelot.bin
if [ $? -ne 0 ] ; then echo "Flash preloader error"; exit 1; fi
#fastboot $* flash efuse `dirname $0`/images/efuse.img
#if [ $? -ne 0 ] ; then echo "Flash efuse error"; exit 1; fi
fastboot $* flash logo `dirname $0`/images/logo.bin
if [ $? -ne 0 ] ; then echo "Flash logo error"; exit 1; fi
fastboot $* flash tee1 `dirname $0`/images/tee.img
if [ $? -ne 0 ] ; then echo "Flash tee1 error"; exit 1; fi
fastboot $* flash tee2 `dirname $0`/images/tee.img
if [ $? -ne 0 ] ; then echo "Flash tee2 error"; exit 1; fi
fastboot $* flash scp1 `dirname $0`/images/scp.img
if [ $? -ne 0 ] ; then echo "Flash scp1 error"; exit 1; fi
fastboot $* flash scp2 `dirname $0`/images/scp.img
if [ $? -ne 0 ] ; then echo "Flash scp2 error"; exit 1; fi
fastboot $* flash sspm_1 `dirname $0`/images/sspm.img
if [ $? -ne 0 ] ; then echo "Flash sspm_1 error"; exit 1; fi
fastboot $* flash sspm_2 `dirname $0`/images/sspm.img
if [ $? -ne 0 ] ; then echo "Flash sspm_2 error"; exit 1; fi
fastboot $* flash lk `dirname $0`/images/lk.img
if [ $? -ne 0 ] ; then echo "Flash lk error"; exit 1; fi
fastboot $* flash lk2 `dirname $0`/images/lk.img
if [ $? -ne 0 ] ; then echo "Flash lk2 error"; exit 1; fi
fastboot $* flash super `dirname $0`/images/super.img
if [ $? -ne 0 ] ; then echo "Flash super error"; exit 1; fi
fastboot $* flash cache `dirname $0`/images/cache.img
if [ $? -ne 0 ] ; then echo "Flash cache error"; exit 1; fi
fastboot $* flash recovery `dirname $0`/images/recovery.img
if [ $? -ne 0 ] ; then echo "Flash recovery error"; exit 1; fi
fastboot $* flash boot `dirname $0`/images/boot.img
if [ $? -ne 0 ] ; then echo "Flash boot error"; exit 1; fi
fastboot $* flash dtbo `dirname $0`/images/dtbo.img
if [ $? -ne 0 ] ; then echo "Flash dtbo error"; exit 1; fi
fastboot $* flash vbmeta `dirname $0`/images/vbmeta.img
if [ $? -ne 0 ] ; then echo "Flash vbmeta error"; exit 1; fi
fastboot $* flash spmfw `dirname $0`/images/spmfw.img
if [ $? -ne 0 ] ; then echo "Flash spmfw error"; exit 1; fi
fastboot $* flash md1img `dirname $0`/images/md1img.img
if [ $? -ne 0 ] ; then echo "Flash md1img error"; exit 1; fi
fastboot $* flash vbmeta_system `dirname $0`/images/vbmeta_system.img
if [ $? -ne 0 ] ; then echo "Flash vbmeta_system error"; exit 1; fi
fastboot $* flash vbmeta_vendor `dirname $0`/images/vbmeta_vendor.img
if [ $? -ne 0 ] ; then echo "Flash vbmeta_vendor error"; exit 1; fi
fastboot $* flash cust `dirname $0`/images/cust.img
if [ $? -ne 0 ] ; then echo "Flash cust error"; exit 1; fi
fastboot $* flash exaid `dirname $0`/images/exaid.img
if [ $? -ne 0 ] ; then echo "Flash exaid error"; exit 1; fi
fastboot $* flash userdata `dirname $0`/images/userdata.img
if [ $? -ne 0 ] ; then echo "Flash userdata error"; exit 1; fi
fastboot $* reboot
if [ $? -ne 0 ] ; then echo "Reboot error"; exit 1; fi

Jak możemy zauważyć, mamy tutaj szereg wywołań narzędzia fastboot , które wrzuca stosowne obrazy zawarte w pobranej przez nas paczce na odpowiadające im partycje w telefonie. Zatem już wiemy skąd w tym ROM'ie wzięła się nazwa fastboot.

Do czego może nam się przydać ROM fastboot

Po zawartości paczki możemy stwierdzić, że są tam w zasadzie gołe obrazy, które wgrywane są na smartfon przy pomocy narzędzia fastboot . By móc jednak skorzystać z ROM'u fastboot, potrzebny nam będzie odblokowany bootloader (tutaj artykuł na przykładzie Redmi 9). Zakładając, że blokada z bootloader'a została już zdjęta, to nasuwa się jedno pytanie. Co przy pomocy takiego ROM'u fastboot jesteśmy w stanie zrobić z naszym telefon od Xiaomi?

Zmiana regionu z EEA na Global

Przy pomocy ROM'u fastboot jesteśmy w stanie wgrać oficjalny ROM Xiaomi, który nie jest przeznaczony na nasze urządzenie, tj. chodzi o region, w którym taki telefon został dopuszczony do użytku. Na terenie Europy smartfony mają wgrany ROM z regionem EEA, który z racji pewnych europejskich standardów w kwestii prywatności, jest pozbawiony części funkcjonalności. Jeśli prywatność dla nas nie ma znaczenia lub też bardziej cenimy sobie funkcjonalność urządzenia, to moglibyśmy wgrać sobie ROM z regionem Global .

Downgrade ROM'u

Zakładając, że Xiaomi wypuścił nowszą wersję ROM'u na nasz smartfon, oraz że ta aktualizacja zawiera nowszego Androida, który nie działa za dobrze na tym urządzeniu, np. z powodu zbyt słabej wydajności, to przy pomocy ROM'u fastboot będziemy w stanie zrobić downgrade do starszej wersji, tj. tej, która u nas zdawała się działać lepiej.

Możliwość odtworzenia stanu fabrycznego ROM'u

ROM fastboot powstał w zasadzie, by dać nam możliwość przywrócenia fabrycznego oprogramowania w naszym smartfonach Xiaomi, w sytuacji gdy coś pochrzanimy, np. bawiąc się alternatywnym softem. Być może są również i inne zastosowania dla tego ROM'u ale nas, tj. osoby korzystające z custom ROM'ów, bardziej interesuje aspekt popsucia urządzenia wskutek wgrania trefnych obrazów, czy też poczynienia zbyt śmiałych zmian w konfiguracji samego telefonu.

Odtworzenie partycji /boot/ i /recovery/

W pobranej przez nas paczce .tgz znajdują się obrazy partycji /boot/ oraz /recovery/ . Jeśli korzystamy z TWRP albo SHRP, to one przepisują zawartość partycji /recovery/ . System telefonu zwykle jest w stanie tę partycję odtworzyć sobie sam jeśli wykryje w niej zmiany ale tylko, gdy partycja /boot/ pozostaje nietknięta. Zwykle jednak po wgraniu TWRP/SHRP, wrzucany jest na telefon także Magisk (w celu uzyskania praw root), który modyfikuje partycję /boot/ na swoje potrzeby. Może się zatem zdarzyć tak, że któraś z tych partycji nam się uszkodzi i jeśli nie mamy zrobionego backup'u flash'a telefonu, to przy pomocy ROM'u fastboot będziemy w stanie te dwie partycje przywrócić do stanu fabrycznego i potencjalnie przywrócić nasz smartfon do życia.

Odtworzenie ustawień mechanizmu AVB

Następna rzecz to mechanizm AVB (Android Verified Boot), przy którym zwykle coś majstrujemy, by móc wgrać na smartfon TWRP/SHRP recovery lub też alternatywne ROM'y. Chodzi generalnie o zmiany dokonywane w obrazach vbmeta , vbmeta_system oraz vbmeta_vendor . Może się zatem zdarzyć tak, że nie będziemy w stanie tego mechanizmu włączyć ponownie, np. gdyby nam się już znudziło bawienie otwartym oprogramowaniem, lub też gdy zwyczajnie chcielibyśmy to urządzenie komuś odsprzedać.

Przywrócenie oryginalnego oprogramowania

Tej paczce z ROM'em fastboot mamy też naturalnie obraz całej partycji /super/ , w której skład wchodzi partycja /system/ , /product/ oraz /vendor/ . Mamy zatem tutaj stock'owe oprogramowanie, na wypadek, gdybyśmy chcieli w późniejszym czasie do niego powrócić. Naturalnie nie tylko partycja /super/ jest potrzebna do odtworzenia fabrycznego oprogramowania ale to tutaj znajduje się Android, z którego tak energicznie korzystamy na co dzień.

Naprawa partycji /data/ oraz /cache/

W paczce z ROM'em fastboot mogliśmy też ujrzeć obrazy partycji /data/ oraz /cache/ . Nie do końca wiem po co one zostały tam umieszczone. Intuicja mi jednak podpowiada, że może chodzić o sytuacje, w których użytkownik coś namiesza podczas zabawy z alternatywnym ROM'em, przez co system może mieć jakieś problemy z umieszczeniem danych na tych dwóch partycjach. Być może te obrazy są przeznaczone do fabrycznego odtworzenia ich zawartości (systemu plików, szyfrowania, etc.) i tym samym usunięcia wszelkich zaistniałych problemów powstałych z winy użytkownika.

Raz zdarzyło mi się tak namieszać w partycji /data/ , że by znów telefon zaczął działać poprawnie, to trzeba było skorzystać właśnie z tego ROM'u fastboot. Pewnie szło wszystkie zmiany cofnąć ręcznie, choć czasami jest to trudne, zwłaszcza w przypadku, gdy do końca się nie wie co się popsuło i w jaki sposób.

Aktualizacja/downgrade firmware

Po rzuceniu okiem na partycje, które są przepisywane podczas flash'owania telefonu tym ROM'em fastboot, widać, że aktualizacji podlega między innymi cały firmware urządzenia, tj. pozycje /spmfw/ , /scp1/ , /scp2/ , /sspm_1/ , /sspm_2/ , /tee1/ , /tee2/ , /lk/ , /lk2/ oraz /md1img/ . Zatem już mamy kolejny sposób zastosowania tego ROM'u, tj. jeśli z jakiegoś powodu potrzebujemy powrócić do określonej wersji firmware, to jak najbardziej wgranie tej paczki na smartfon nam to umożliwi. Podobnie też i w drugą stronę, tj. gdy firmware chcielibyśmy zaktualizować.

Naturalnie, gdy chodzi o proces wgrywania firmware, to można go przeprowadzić niezależnie od wgrywania reszty ROM'u (szczegóły w podlinkowanym wyżej artykule). Niemniej jednak, warto wiedzieć, że po wgraniu ROM'u fastboot, firmware również zostanie zmieniony.

Aktualizacja/downgrade preloader'a

Podobnie jak w przypadku firmware, preloader również może zostać zaktualizowany i podobnie możemy przy pomocy ROM'u fastboot zmienić jego wersję na tę, która była obecna we wcześniejszych oficjalnych ROM'ach od Xiaomi.

Gdzie ROM fastboot nie znajdzie zastosowania

Praktycznie każda z tych 22 partycji może zostać odtworzona do stanu fabrycznego po skorzystaniu z tego ROM'u fastboot. Trzeba jednak pamiętać, że Android na swoim flash'u ma tych partycji koło 50, zatem ta paczka nie będzie nam w stanie zawsze pomóc ale w sporej większości przypadków na pewno znajdzie zastosowanie.

Utrata IMEI, MAC WiFi i Bluetooth

Jednym z takich kluczowych problemów, na które użytkownik smartfona może trafić podczas zabawy z alternatywnymi ROM'ami, to uszkodzenie krytycznych z punktu widzenia funkcjonalności numerów urządzenia, takich jak np. IMEI, adresy MAC kart WiFi/Bluetooth czy też dane kalibracyjne do modemu GSM. Te dane są specyficzne dla danego urządzenia i z reguły przechowywane na poniższych partycjach:

  • /nvcfg/ -- przechowuje zmienną konfigurację dla /nvdata/ i /nvram/
  • /nvdata/ -- przechowuje zmienne informacje identyfikacyjne danego urządzenia, m.in. IMEI, WiFi MAC, Bluetooth MAC, dane kalibracyjne.
  • /nvram/ -- przechowuje niezmienne informacje identyfikacyjne danego urządzenia, m.in. IMEI, WiFi MAC, Bluetooth MAC, dane kalibracyjne.
  • /persist/ -- przechowuje niezmienne dane użyteczne dla mechanizmu FRP (Factory Reset Protection), takie jak dane do konta Google czy MIaccount/MIcloud.
  • /protect_f/ -- przechowuje zmienne dane od ustawień SIM/RADIO/MODEM/BASEBAND.
  • /protect_s/ -- przechowuje zmienne dane od ustawień SIM/RADIO/MODEM/BASEBAND.

Jako, że żadna z tych partycji nie znajduje się w ROM'ie fastboot, to ich uszkodzenie, wyzerowanie czy nadpisanie w inny sposób może uczynić nasz telefon złomem elektronicznym, przynajmniej jeśli chodzi o dzwonienie i korzystanie z internetu. Dlatego też ROM fastboot nie będzie nam w stanie pomóc w przypadku utraty IMEI czy adresów MAC. Zawsze możemy zrobić sobie backup IMEI czy adresów MAC WiFi i Bluetooth we własnym zakresie, tak by w razie czego być w stanie przywrócić te numerki.

Telefon się nie uruchamia

ROM fastboot, jak nazwa sugeruje, wymaga, by w naszym telefonie działał tryb fastboot. Jeśli nasz smartfon się nie uruchamia, to siłą rzeczy nie zostanie w nim odpalona stosowna usługa, która byłaby w stanie zaakceptować i wgrać na partycje odpowiednie obrazy. Dlatego też w tym przypadku z tego ROM'u nie będzie za wiele pożytku.

Jak wgrać ROM fastboot na smartfon Xiaomi

ROM fastboot na smartfony Xiaomi możemy wgrać zarówno z poziomu windows'a, jak i linux'a. Trzeba tylko posiadać odpowiednią paczkę z ROM'em oraz naturalnie stosowne oprogramowanie zainstalowane w systemie operacyjnym, z którego korzystamy na co dzień.

Linux i XiaoMiTool

Technicznie rzecz biorąc, to można bez większego problemu taki ROM fastboot wgrać na smartfon z poziomu dowolnej dystrybucji linux'a przy pomocy narzędzia XiaoMiTool. Wystarczy odpalić XiaoMiTool i wybrać opcję po prawej stronie na poniższej fotce:

xiaomitool-fastboot-rom-xiaomi-redmi-9-flash-linux

Podczas uruchamiania się urządzenia przełączamy nasz smartfon w tryb fastboot przy pomocy przycisków Power + VolumeDown. Po podłączeniu telefonu do portu USB komputera, XiaoMiTool powinien wykryć nasz sprzęt:

xiaomitool-fastboot-rom-xiaomi-redmi-9-flash-linux

Wskazujemy XiaoMiTool jakie to jest dokładnie urządzenie, w tym przypadku jest to Redmi 9 (lancelot/galahad):

xiaomitool-fastboot-rom-xiaomi-redmi-9-flash-linux

Po chwili rozpocznie się pobieranie odpowiedniego ROM'u fastboot:

xiaomitool-fastboot-rom-xiaomi-redmi-9-flash-linux

Problem z XiaoMiTool jest jednak taki, że nie możemy określić jaką wersję ROM'u dokładnie chcemy wgrać i w zasadzie wgrywana jest ta najnowsza dostępna. Być może XiaoMiTool pobiera ROM w oparciu o Androida, którego mamy wgranego aktualnie na smartfon. Przykładowo, jeśli mamy Androida 10, to pobierany jest najnowszy dostępny ROM z Androidem 10, a jeśli 11, to z Andkiem 11. Tak czy inaczej, nie idzie pobrać w ten sposób konkretnej wersji ROM'u Xiaomi, a to nie dobrze. Nie ma też opcji, by wskazać uprzednio pobraną paczkę .tgz .

Drugi problem z XiaoMiTool jest natury technicznej, bo coś to pobieranie ROM'u via XiaoMiTool nie działa najlepiej. Mniej więcej w połowie pojawia się błąd pobrania i cały proces trzeba rozpocząć od nowa. Pół biedy, gdyby ponowne pobieranie rozpoczynało się od tego momentu, w którym się urwało to poprzednie ale pobieranie rozpoczyna się zupełnie od początku i przerywane jest znów w połowie.

Nie byłem w stanie dokończyć tego procesu z poziomu linux'a, a biorąc pod uwagę fakt braku możliwości określenia jaki ROM dokładnie chciałbym wgrać, to pozostaje opcja z windows'em lub ręczne wgrywanie obrazów via fastboot .

Ręczne wgrywanie obrazów via fastboot

Nic nie stoi na przeszkodzie, by ręcznie wgrać te wszystkie obrazy z paczki .tgz wykorzystując narzędzie fastboot z dowolnego systemu operacyjnego, w tym z linux'a. Praktycznie wszystko co trzeba zrobić, to postępować według skryptu, który jest załączony w ROM'ie, pilnując tylko, by w poleceniu fastboot wskazać odpowiedni obraz i partycję, a efekt powinien być dokładnie taki sam, co przy korzystaniu z XiaoMiTool.

Choć lepszym rozwiązaniem będzie odpalić jeden ze skryptów, tj. flash_all.sh , flash_all_except_data_storage.sh albo flash_all_lock.sh . Te dwa pierwsze skrypty różnią się od siebie tym czy dane użytkownika zostaną wyczyszczone. Natomiast ten ostatni skrypt wyczyści dane użytkownika i dodatkowo zablokuje bootloader po całym procesie flash'owania, co przydaje się gdy powracamy do fabrycznego oprogramowania producenta telefonu.

Poniżej przykład wywołania skryptu flash_all_lock.sh :

$ ./flash_all_lock.sh
product: lancelot
./flash_all_lock.sh: 6: [: 2x: unexpected operator
Erasing 'boot'                                     OKAY [  0.006s]
Finished. Total time: 0.007s
Sending 'crclist' (0 KB)                           OKAY [  0.011s]
Writing 'crclist'                                  OKAY [  0.001s]
Finished. Total time: 0.013s
Sending 'preloader' (280 KB)                       OKAY [  0.020s]
Writing 'preloader'                                OKAY [  0.010s]
Finished. Total time: 0.053s
Sending 'logo' (1168 KB)                           OKAY [  0.042s]
Writing 'logo'                                     OKAY [  0.029s]
Finished. Total time: 0.076s
Sending 'tee1' (2488 KB)                           OKAY [  0.079s]
Writing 'tee1'                                     OKAY [  0.036s]
Finished. Total time: 0.115s
Sending 'tee2' (2488 KB)                           OKAY [  0.077s]
Writing 'tee2'                                     OKAY [  0.036s]
Finished. Total time: 0.114s
Sending 'scp1' (344 KB)                            OKAY [  0.020s]
Writing 'scp1'                                     OKAY [  0.009s]
Finished. Total time: 0.030s
Sending 'scp2' (344 KB)                            OKAY [  0.020s]
Writing 'scp2'                                     OKAY [  0.009s]
Finished. Total time: 0.031s
Sending 'sspm_1' (494 KB)                          OKAY [  0.025s]
Writing 'sspm_1'                                   OKAY [  0.010s]
Finished. Total time: 0.036s
Sending 'sspm_2' (494 KB)                          OKAY [  0.024s]
Writing 'sspm_2'                                   OKAY [  0.011s]
Finished. Total time: 0.036s
Sending 'lk' (1130 KB)                             OKAY [  0.041s]
Writing 'lk'                                       OKAY [  0.027s]
Finished. Total time: 0.069s
Sending 'lk2' (1130 KB)                            OKAY [  0.041s]
Writing 'lk2'                                      OKAY [  0.018s]
Finished. Total time: 0.060s
Sending sparse 'super' 1/46 (131071 KB)            OKAY [  3.883s]
Writing 'super'                                    OKAY [  2.770s]
Sending sparse 'super' 2/46 (130397 KB)            OKAY [  3.778s]
Writing 'super'                                    OKAY [  2.257s]
Sending sparse 'super' 3/46 (130574 KB)            OKAY [  3.829s]
Writing 'super'                                    OKAY [  2.490s]
Sending sparse 'super' 4/46 (130785 KB)            OKAY [  4.030s]
Writing 'super'                                    OKAY [  2.259s]
Sending sparse 'super' 5/46 (131064 KB)            OKAY [  4.136s]
Writing 'super'                                    OKAY [  1.822s]
Sending sparse 'super' 6/46 (130645 KB)            OKAY [  3.846s]
Writing 'super'                                    OKAY [  2.310s]
Sending sparse 'super' 7/46 (129901 KB)            OKAY [  4.038s]
Writing 'super'                                    OKAY [  3.337s]
Sending sparse 'super' 8/46 (130514 KB)            OKAY [  3.996s]
Writing 'super'                                    OKAY [  2.518s]
Sending sparse 'super' 9/46 (130511 KB)            OKAY [  4.121s]
Writing 'super'                                    OKAY [  2.693s]
Sending sparse 'super' 10/46 (131068 KB)           OKAY [  4.293s]
Writing 'super'                                    OKAY [  1.836s]
Sending sparse 'super' 11/46 (126823 KB)           OKAY [  3.999s]
Writing 'super'                                    OKAY [  5.190s]
Sending sparse 'super' 12/46 (131068 KB)           OKAY [  4.214s]
Writing 'super'                                    OKAY [  1.924s]
Sending sparse 'super' 13/46 (124176 KB)           OKAY [  3.960s]
Writing 'super'                                    OKAY [  1.819s]
Sending sparse 'super' 14/46 (131068 KB)           OKAY [  3.745s]
Writing 'super'                                    OKAY [  1.805s]
Sending sparse 'super' 15/46 (116312 KB)           OKAY [  3.346s]
Writing 'super'                                    OKAY [  1.622s]
Sending sparse 'super' 16/46 (128981 KB)           OKAY [  3.680s]
Writing 'super'                                    OKAY [  2.026s]
Sending sparse 'super' 17/46 (117493 KB)           OKAY [  3.258s]
Writing 'super'                                    OKAY [  1.984s]
Sending sparse 'super' 18/46 (131069 KB)           OKAY [  3.697s]
Writing 'super'                                    OKAY [  2.263s]
Sending sparse 'super' 19/46 (120084 KB)           OKAY [  3.299s]
Writing 'super'                                    OKAY [  1.775s]
Sending sparse 'super' 20/46 (121336 KB)           OKAY [  3.333s]
Writing 'super'                                    OKAY [  1.865s]
Sending sparse 'super' 21/46 (131068 KB)           OKAY [  3.636s]
Writing 'super'                                    OKAY [  1.841s]
Sending sparse 'super' 22/46 (131069 KB)           OKAY [  3.676s]
Writing 'super'                                    OKAY [  2.099s]
Sending sparse 'super' 23/46 (120810 KB)           OKAY [  3.551s]
Writing 'super'                                    OKAY [ 11.678s]
Sending sparse 'super' 24/46 (126768 KB)           OKAY [  3.542s]
Writing 'super'                                    OKAY [  1.744s]
Sending sparse 'super' 25/46 (116196 KB)           OKAY [  3.245s]
Writing 'super'                                    OKAY [  1.716s]
Sending sparse 'super' 26/46 (130900 KB)           OKAY [  3.685s]
Writing 'super'                                    OKAY [  1.885s]
Sending sparse 'super' 27/46 (131032 KB)           OKAY [  3.677s]
Writing 'super'                                    OKAY [  1.809s]
Sending sparse 'super' 28/46 (130984 KB)           OKAY [  3.717s]
Writing 'super'                                    OKAY [  1.905s]
Sending sparse 'super' 29/46 (130793 KB)           OKAY [  3.690s]
Writing 'super'                                    OKAY [  2.093s]
Sending sparse 'super' 30/46 (129879 KB)           OKAY [  3.785s]
Writing 'super'                                    OKAY [  3.913s]
Sending sparse 'super' 31/46 (130996 KB)           OKAY [  3.755s]
Writing 'super'                                    OKAY [  1.853s]
Sending sparse 'super' 32/46 (130007 KB)           OKAY [  3.681s]
Writing 'super'                                    OKAY [  3.912s]
Sending sparse 'super' 33/46 (130348 KB)           OKAY [  3.700s]
Writing 'super'                                    OKAY [  1.824s]
Sending sparse 'super' 34/46 (129941 KB)           OKAY [  3.666s]
Writing 'super'                                    OKAY [  3.348s]
Sending sparse 'super' 35/46 (129795 KB)           OKAY [  3.633s]
Writing 'super'                                    OKAY [  2.745s]
Sending sparse 'super' 36/46 (131052 KB)           OKAY [  3.629s]
Writing 'super'                                    OKAY [  1.813s]
Sending sparse 'super' 37/46 (131036 KB)           OKAY [  3.654s]
Writing 'super'                                    OKAY [  1.844s]
Sending sparse 'super' 38/46 (131036 KB)           OKAY [  3.724s]
Writing 'super'                                    OKAY [  1.812s]
Sending sparse 'super' 39/46 (115698 KB)           OKAY [  3.323s]
Writing 'super'                                    OKAY [  3.471s]
Sending sparse 'super' 40/46 (131068 KB)           OKAY [  3.840s]
Writing 'super'                                    OKAY [  4.703s]
Sending sparse 'super' 41/46 (131068 KB)           OKAY [  3.634s]
Writing 'super'                                    OKAY [  1.835s]
Sending sparse 'super' 42/46 (117208 KB)           OKAY [  3.240s]
Writing 'super'                                    OKAY [  1.684s]
Sending sparse 'super' 43/46 (131068 KB)           OKAY [  3.636s]
Writing 'super'                                    OKAY [  1.829s]
Sending sparse 'super' 44/46 (121936 KB)           OKAY [  3.386s]
Writing 'super'                                    OKAY [  1.741s]
Sending sparse 'super' 45/46 (127036 KB)           OKAY [  3.516s]
Writing 'super'                                    OKAY [  1.936s]
Sending sparse 'super' 46/46 (71052 KB)            OKAY [  1.975s]
Writing 'super'                                    OKAY [  1.026s]
Finished. Total time: 288.741s
Sending 'cache' (68 KB)                            OKAY [  0.013s]
Writing 'cache'                                    OKAY [  0.042s]
Finished. Total time: 0.056s
Sending 'recovery' (65536 KB)                      OKAY [  1.781s]
Writing 'recovery'                                 OKAY [  1.333s]
Finished. Total time: 3.116s
Sending 'boot' (65536 KB)                          OKAY [  1.998s]
Writing 'boot'                                     OKAY [  1.343s]
Finished. Total time: 3.366s
Sending 'dtbo' (129 KB)                            OKAY [  0.015s]
Writing 'dtbo'                                     OKAY [  0.008s]
Finished. Total time: 0.023s
Sending 'vbmeta' (4 KB)                            OKAY [  0.011s]
Writing 'vbmeta'                                   OKAY [  0.002s]
Finished. Total time: 0.014s
Sending 'spmfw' (48 KB)                            OKAY [  0.012s]
Writing 'spmfw'                                    OKAY [  0.005s]
Finished. Total time: 0.018s
Sending 'md1img' (58066 KB)                        OKAY [  1.615s]
Writing 'md1img'                                   OKAY [  1.195s]
Finished. Total time: 2.811s
Sending sparse 'cust' 1/3 (129728 KB)              OKAY [  3.969s]
Writing 'cust'                                     OKAY [  1.794s]
Sending sparse 'cust' 2/3 (129160 KB)              OKAY [  3.794s]
Writing 'cust'                                     OKAY [  1.763s]
Sending sparse 'cust' 3/3 (52632 KB)               OKAY [  1.600s]
Writing 'cust'                                     OKAY [  0.731s]
Finished. Total time: 13.684s
Sending 'vbmeta_system' (4 KB)                     OKAY [  0.011s]
Writing 'vbmeta_system'                            OKAY [  0.002s]
Finished. Total time: 0.027s
Sending 'vbmeta_vendor' (4 KB)                     OKAY [  0.011s]
Writing 'vbmeta_vendor'                            OKAY [  0.002s]
Finished. Total time: 0.014s
Invalid sparse file format at header magic
Sending sparse 'exaid' 1/1 (328 KB)                OKAY [  0.022s]
Writing 'exaid'                                    OKAY [  2.942s]
Finished. Total time: 3.060s
Sending sparse 'userdata' 1/13 (129064 KB)         OKAY [  3.920s]
Writing 'userdata'                                 OKAY [  1.754s]
Sending sparse 'userdata' 2/13 (129012 KB)         OKAY [  3.806s]
Writing 'userdata'                                 OKAY [  1.754s]
Sending sparse 'userdata' 3/13 (129028 KB)         OKAY [  3.826s]
Writing 'userdata'                                 OKAY [  1.736s]
Sending sparse 'userdata' 4/13 (129012 KB)         OKAY [  3.900s]
Writing 'userdata'                                 OKAY [  1.747s]
Sending sparse 'userdata' 5/13 (129028 KB)         OKAY [  3.832s]
Writing 'userdata'                                 OKAY [  1.732s]
Sending sparse 'userdata' 6/13 (129012 KB)         OKAY [  3.823s]
Writing 'userdata'                                 OKAY [  1.748s]
Sending sparse 'userdata' 7/13 (129028 KB)         OKAY [  3.834s]
Writing 'userdata'                                 OKAY [  1.748s]
Sending sparse 'userdata' 8/13 (129012 KB)         OKAY [  3.932s]
Writing 'userdata'                                 OKAY [  1.753s]
Sending sparse 'userdata' 9/13 (129028 KB)         OKAY [  3.803s]
Writing 'userdata'                                 OKAY [  1.741s]
Sending sparse 'userdata' 10/13 (129012 KB)        OKAY [  3.648s]
Writing 'userdata'                                 OKAY [  1.753s]
Sending sparse 'userdata' 11/13 (129024 KB)        OKAY [  3.699s]
Writing 'userdata'                                 OKAY [  1.746s]
Sending sparse 'userdata' 12/13 (129020 KB)        OKAY [  3.927s]
Writing 'userdata'                                 OKAY [  1.756s]
Sending sparse 'userdata' 13/13 (73608 KB)         OKAY [  2.178s]
Writing 'userdata'                                 OKAY [  1.013s]
Finished. Total time: 70.261s
FAILED (remote: 'unknown command')
fastboot: error: Command failed
(bootloader) Start lock flow

OKAY [  2.145s]
Finished. Total time: 2.145s

W tym powyższym logu pojawiło się trochę błędów ale żaden z nich nie jest krytyczny i nie wpływa na poprawne wgranie ROM'u na telefon.

FAILED (remote: 'update sparse crc list failed')

Czasami przy powrocie do fabrycznego oprogramowania producenta telefonu mogą się pojawić błędy uniemożliwiające wgranie ROM'u fastboot. Poniżej mamy właśnie taki przykład, w którym to z jakiegoś powodu próba wgrania sparsecrclist kończy się błędem:

$ ./flash_all_lock.sh
product: lancelot
./flash_all_lock.sh: 6: [: 2x: unexpected operator
Erasing 'boot'                                     OKAY [  0.006s]
Finished. Total time: 0.007s
Warning: skip copying crclist image avb footer (crclist partition size: 0, crclist image size: 277).
Sending 'crclist' (0 KB)                           OKAY [  0.011s]
Writing 'crclist'                                  OKAY [  0.001s]
Finished. Total time: 0.014s
Warning: skip copying sparsecrclist image avb footer (sparsecrclist partition size: 0, sparsecrclist image size: 725).
Sending 'sparsecrclist' (0 KB)                     OKAY [  0.011s]
Writing 'sparsecrclist'                            FAILED (remote: 'update sparse crc list failed')
fastboot: error: Command failed
Flash sparsecrclist error

Z jakiego powodu aktualizacja tego sparsecrclist kończy się niepowodzeniem, to nie mam pojęcia. Niektórzy winą obarczają program, który wypakowuje paczkę .tgz z ROM'em fastboot. W tym przypadku został użyty patool :

$ patool extract lancelot_eea_global_images_V13.0.3.0.SJCEUXM_20230111.0000.00_12.0_eea_04fc56f80c.tgz
INFO patool: Extracting lancelot_eea_global_images_V13.0.3.0.SJCEUXM_20230111.0000.00_12.0_eea_04fc56f80c.tgz ...
INFO patool: running /usr/bin/tar --force-local --help
INFO patool:     with stderr='-3', input=''
INFO patool: running /usr/bin/tar --extract -z --force-local --file lancelot_eea_global_images_V13.0.3.0.SJCEUXM_20230111.0000.00_12.0_eea_04fc56f80c.tgz --directory ./Unpack_mv6qph5g
INFO patool:     with input=''
INFO patool: ... lancelot_eea_global_images_V13.0.3.0.SJCEUXM_20230111.0000.00_12.0_eea_04fc56f80c.tgz extracted to `lancelot_eea_global_images_V13.0.3.0.SJCEUXM_20230111.0000.00_12.0_eea'.

No jak widać, patool woła bezpośrednio binarkę /usr/bin/tar , a co innego może się bardziej nadawać do wypakowania paczki .tgz niż tar , który te paczki tworzy?

Inni użytkownicy z kolei widzą problem w samym narzędziu fastboot, bo najwyraźniej Google ma swoją implementację tego narzędzia, a Xiaomi swoją. Wgyląda na to, ze na tym fastboot od Google mogą się pojawić tego typu błędy, gdy w grę wchodzi ROM od Xiaomi.

W moim przypadku, na jednym z telefonów podmiana binarki fastboot pomogła. I faktycznie problem się rozwiązał sam z siebie. Niestety w przypadku drugiego telefonu, ani jeden fastboot , ani drugi nie były w stanie tego błędu poprawić.

Czy to znaczy, że możemy zapomnieć o wgraniu takiego ROM'u i zwyczajnie uruchomić telefon ponownie i jakoś żyć dalej? Prawdę mówiąc to nie miałem odwagi tego sprawdzić, bo z tego powyższego logu można było wyczytać, że Erasing 'boot' OKAY , czyli partycja /boot/ została wyczyszczona i lepiej nie uruchamiać teraz tego telefonu ponownie.

Pozbycie się plików z sumami kontrolnymi CRC (crclist.txt oraz sparsecrclist.txt)

Analizując skrypt flash_all_lock.sh można w nim zauważyć te poniższe wpisy:

fastboot $* flash crclist `dirname $0`/images/crclist.txt
if [ $? -ne 0 ] ; then echo "Flash crclist error"; exit 1; fi
fastboot $* flash sparsecrclist `dirname $0`/images/sparsecrclist.txt
if [ $? -ne 0 ] ; then echo "Flash sparsecrclist error"; exit 1; fi

W tym przypadku to drugie wywołanie polecenia fastboot powoduje błąd ale może się też zdarzyć tak, że to pierwsze będzie przyczyną problemów. Jeśli nie możemy wgrać ROM'u fastboot na telefon, bo coś z tymi plikami (albo samymi sumami kontrolnymi CRC) jest nie tak, to te powyższe wpisy możemy zwyczajnie usunąć ze skryptu i jeszcze raz ten skrypt wywołać.

Czy usunięcie wpisów z crclist.txt oraz sparsecrclist.txt będzie miało jakiś wpływ na działanie telefonu? Tego nie jestem do końca pewny, bo telefon się uruchomił bez problemu na stock'owym ROM'ie i wszystko zdaje się działać bez najmniejszego problemu.

Windows i MiFlash

Oczywiście na moim laptopie nie ma windows'a i muszę posiłkować się maszyną wirtualną QEMU/KVM. Dobre wieści są jednak takie, że bez problemu można przy pomocy takiej maszyny wirtualnej przeprowadzić cały proces wgrywania ROM'u fastboot na smartfon, tylko trzeba naturalnie odpowiednio sobie wcześniej taką maszynę przygotować. Cały proces tworzenia maszyny wirtualnej został opisany przy okazji odblokowania bootloader'a w moim Xiaomi Redmi 9 i tutaj nie będę opisywał go ponownie. Jeśli mamy problemy z przygotowaniem odpowiedniej maszyny wirtualnej, to zapraszam pod ten podlinkowany wyżej artykuł.

Tutaj skupimy się jedynie na samym wgraniu takiego ROM'u na telefon. Zatem przełączamy nasze urządzenie w tryb fastboot (Power + VolumeDown), podłączamy je do portu USB komputera i uruchamiamy maszynę wirtualną. W systemie powinno pojawić się nowe urządzenie. W przypadku windows10 nie trzeba nic dodatkowo instalować w systemie. Pobieramy MiFlash i uruchamiamy go. Potrzebne nam naturalnie będą wypakowane pliki z paczki z ROM'em fastboot (możemy je wgrać na maszynę wirtualną via SMB). Po uruchomieniu MiFlash trzeba wskazać katalog, w którym te pliki się znajdują, po czym kliknąć przycisk flash :

xiaomitool-fastboot-rom-xiaomi-redmi-9-flash-windows-kvm-qemu

Cały proces flash'owania zajmie dłuższą chwilę. W tym przypadku trwało to prawie 20 minut. Gdy proces dobiegnie końca, uruchamiamy telefon ponownie.

Zablokowany bootloader po wgraniu ROM'u fastboot

Po ponownym uruchomieniu telefonu, powinniśmy mieć w nim oryginalne oprogramowanie i w zasadzie wszystkie problemy, które nas pchnęły do wgrania ROM'u fastboot powinny natychmiast zniknąć. Niemniej jednak, po wgraniu ROM'u fastboot zostanie w telefonie zablokowany bootloader. Z początku myślałem, że wystarczy w ustawieniach deweloperskich ściągnąć blokadę OEM i wydać to poniższe polecenie:

$ fastboot flashing unlock
(bootloader) Start unlock flow

FAILED (remote: 'Token verification failed')
fastboot: error: Command failed

Ale jak widać, został zwrócony błąd weryfikacji tokenu, tj. tego tokenu, który trzeba uzyskać od Xiaomi. By odblokować taki telefon, trzeba będzie przejść procedurę odblokowania bootloader'a, tj. przy pomocy MiUnlock (windows) lub XiaoMiTool (linux). Nie będzie trzeba za to czekać ponownie 7 dni na pozwolenie ze strony Xiaomi. Zatem odblokowanie bootloader'a będzie natychmiastowe, choć połączenie z internetem i możliwość nawiązania kontaktu z serwerami Xiaomi są wymagane, podobnie jak zalogowanie się w aplikacji na czas ściągania blokady z bootloader'a. Warto zatem pamiętać o tej niedogodności.

Podsumowanie

Dla osób mojego pokroju, które przed rozpoczęciem prac są w stanie zadbać o zrobienie kopi zapasowej całego ROM'u w swoim smartfonie, to taki ROM fastboot w zasadzie nie znajduje jakiegoś większego zastosowania, no może za wyjątkiem cofnięcia wersji fabrycznego softu. W przypadku innych osób, taki kawałek ROM'u może okazać się wielce użyteczny, choć naturalnie będą takie sytuacje, w których nic się nie da zrobić, no może poza wizytą w serwisie i wydaniem paru stów na naprawę. Niemniej jednak, postępując zdroworozsądkowo nie powinniśmy napotkać sytuacji, w których trzeba by z takiego ROM'u fastboot korzystać.

Mikhail Morfikov avatar
Mikhail Morfikov
Po ponad 10 latach spędzonych z różnej maści linux'ami (Debian/Ubuntu, OpenWRT, Android) mogę śmiało powiedzieć, że nie ma rzeczy niemożliwych i problemów, których nie da się rozwiązać. Jedną umiejętność, którą ludzki umysł musi posiąść, by wybrnąć nawet z tej najbardziej nieprzyjemniej sytuacji, to zdolność logicznego rozumowania.