在實在受不了System進程持續佔用15-30%的CPU導致發熱和電池消耗過快之後,我決定給我的一加6刷個機(之前是OOS)。然而我卻大意了,以爲自己憑藉着以前的經驗,可以不用嚴格按照貼子中的刷機步驟(當然其中另一部分原因在於許多貼子的步驟是複製粘貼的)。最終結果是手機變磚,按現在的分類屬於硬磚——只能充電,fastboot都進不去。
之後經過了艱苦的拯救(主要是花時間翻閱資料,以及下載合適的工具),最終將其恢復。正好以前就想寫一下刷機之類的東西(因爲多數刷機教程要麼語焉不詳,要麼有所錯漏,尤其中文資料往往兩者同時存在),這裏就完全寫一下。
本文首先描述一下我最初的操作過程以及其導致的結果,然後梳理一下Android刷機的理論通用模型,最後陳述救磚過程(一加6專用,或許其他一加產品類似)。這個救磚工具其實也可以當刷機工具用,就是有點殺機用牛刀。
錯事經過
因爲我以前兩部手機(HTC One S和一加X)都刷過機,而且也刷過一些別人的手機,所以覺得這次不需要太過在意。雖然一加6像許多新近(按推出時間算)手機一樣使用了A/B分區,和我之前的手機不同,不過這並不是什麼特別神奇的設計,畢竟 1) 我本科時想過給學校圖書館的查詢機製作專們的Linux發行版,上面就使用A/B啓動(然而和其他項目一樣,由於響應者寥寥,最終放棄);2) CoreOS的模式在某種意義上也是A/B啓動。然而我這次出問題,其很大程度上就是和A/B分區相關。
於是我一開始就按通常方法做備份:OAndBackupX去備份app和數據(我已經root),微信聊天記錄備份到電腦上(我電腦上留着有Windows),通話記錄和短信之類備份到手機上。我的重要文件都使用Syncthing進行同步,於是本就有分佈式備份。照片之類同時通過Syncthing進行同步,也使用Qfile備份到NAS上。最後,我把手機的密碼刪除,以便可以在recovery中進行有意義的備份(否則恢復後不會識別正確的密碼)。
由於我之前一直在用官方的OOS,於是我就直接放了ROM到手機存儲上,在twrp下刷之。一開始很正常,刷的前兩個ROM都正常啓動起來了。我簡單試用後覺得不合適(系統功能不合適),於是打算繼續刷。
這裏開始就有了問題了。我一開始刷的兩個ROM(SyberiaProject, ShapeShiftOS)都是要求最新的OOS做基底,然後直接刷;而第三個ROM(ColtOS)則是需要更早一些的版本的OOS做基底,而且明確寫了A、B兩個槽都需要是該版本。如前面所述,我以爲這個只是複製粘貼的要求,因爲我在好幾個貼子中都看到一模一樣的說法,而且這些貼子的時間都比較早。於是我想當然地以爲這個沒事,而且覺得這只是爲了保證基帶之類是最新的而已,故而直接開刷。
然而刷完就直接bootloop了——在「該設備已解鎖」的提示後,直接進入到recovery(該ROM自帶了twrp)。然而該recovery無法正確解開存儲器的加密,於是看到的文件名都是一串無法解釋的字符(如這樣)。然而切換啓動分區至B區後,再進入twrp(通過fastboot自行啓動),這時候可以正常解密。我在這裏又做了一個蠢事,那就是沒有將文件複製出來。於是在後面不得不放棄手機上的所有文件,其中最重要的是我對一些其他app的備份。
之後我覺得是不是我應該刷個OOS,然後或許能解決。然而……我給B區刷了OOS,再次bootloop,進入官方recovery。這時候就出事了——無論我怎麼操作,twrp均無法正確解密我的存儲設備。
然後就是不斷尋找,甚至我還試圖去弄明白Android的加密究竟是如何設計,以及如何手動解密的([1] [2] [3])。
當然,最終結果是我沒弄懂。Android在這方面的文檔似乎很欠缺,或着根本沒打算讓個人弄懂。再加上其中有一定靈活度,每個廠商大約自己會在其上進行損益吧。
然後我又作死,調調這個,調調那個,又去刷了另一個ROM。最終結果是我連fastboot都進不去了,於是就只能救磚了,數據不得不放棄掉。
Android刷機通識
Android手機的刷機原理是相似的,但由於每個廠商許可的口子不盡相同,故而表現出的刷機方案不大一樣。但究其本質,其實就是和計算機一樣,只不過一些步驟需要在外接機器(計算機)上操作。我在這裏描述我所瞭解以及理解到的通用模型,以方便其他人參考。如有錯漏,敬請指正。
概念區分
Android手機的啓動(或者說引導)過程和典型的GNU/Linux引導過程幾乎一樣——首先進入引導加載器(bootloader,在Android上也常直接被叫做fastboot),然後引導加載器載入內核以及初始化(在GNU/Linux上是linux內核與initramfs,在Android上則是boot.img),最後進入給用戶的操作系統界面(在GNU/Linux上是tty或圖形界面,在Android上就是Android)。
但就我理解,兩者又似乎有所不同。計算機(PC)上會首先進入BIOS或UEFI,由BIOS或UEFI進行硬件初始化和自檢(POST?),然後由BIOS或UEFI載入bootloader;但Android方面似乎是用bootloader同時完成兩個職能。
在bootloader和操作系統之外,Android還有一個recovery:如其名稱所示,recovery的功能就是在系統異常時可以進行恢復。顯然,recovery和Android系統不會同時運行,所以它一般也承擔了系統升級的功能。官方recovery的功能一般十分簡單粗暴,要麼抹掉所有app數據,要麼抹掉全部數據。而第三方recovery則會提供更多功能,尤其是刷機所需功能。
Android上的這個區分便造就了需要使用fastboot和adb兩個工具:fastboot控制bootloader,而adb控制Android。特殊地,recovery一般也支持使用adb命令來指揮。
另外,出於歷史和習慣的因素,Android系統一般會被稱爲ROM。這裏不表。
刷機基本邏輯
有了上面的認識,刷機的邏輯就很清楚了:
1. 進行準備工作; 1. 寫入新的操作系統(ROM); 1. 清理任何干擾新操作系統運行的數據; 1. 刷後續包(如果需要或想要); 1. 啓動新操作系統。
各個廠商的最大不同就在準備工作上,而這也是決定了一個手機能否被刷機的關鍵部分。
當然,部分手機有其特殊方式,比如一部分(或全部)三星手機是直接通過刷機工具線刷,完全不考慮通用模式。
對每個具體的手機,仍然需要去查詢相應的方案。這件事一般都需要到相關論壇查找,比如去很知名的XDA論壇找自己手機的分區,然後找相應版塊。而且無論手機是哪個方案,總是需要下載想刷入的ROM的,也一般都是要去論壇找的。
當然,多數人在刷機前會考慮進行備份,然後刷完後恢復回去;或者在recovery中進行備份,刷機不理想時恢復回去。這些請自行尋找相應教程。
通常模式
對於我所知的大多數手機,刷機的第一步都是解鎖。解鎖後需要引導進入第三方recovery。加上下載第三方ROM,這三步共同構成了準備工作。
準備工作
由於Android用在手機上,許多廠商大約是認爲用戶不需要自定義能力,所以其bootloader一般都會加鎖。該加鎖也同時可以承擔防篡改的功能,類似UEFI的secure boot。然而刷機時我們就是在寫入自定義(非官方)的系統,所以需要關閉該防篡改功能。這一步就是「解(bootloader)鎖」。
早期的廠商普遍是不允許解鎖的。HTC算是比較早的解鎖較爲方便的廠商——在提交「解鎖申請」後,一般當時就可以拿到解鎖許可(應當是密鑰)。後來大部分廠商都支持解鎖了。然而最近幾年一些曾經支持解鎖的廠商又宣佈不再支持解鎖,或縮緊解鎖審批。
不同廠商乃至不同型號的手機的解鎖方法不完全一樣,但其基本流程都是首先在電腦上要求解鎖(這時候手機一般都會在bootloader下),然後或許需要等待批准,最後在——如果需要的話——獲取到許可後操作手機確認解鎖。一般情況下,解鎖都會導致所有數據的清除。
在我所用過的HTC和一加手機上,解鎖都是通過電腦,使用fastboot的一個子命令要求解鎖。其中HTC會在電腦方面打印一串文本(大約是加密的本機信息);然後你需要手動打開HTC的解鎖申請網站,將打印出來的文本貼進去,提交申請;再然後HTC會給你發一封郵件,內容也是一串文本(大約是加密的許可),你需要將該文本貼到命令行,輸入給手機;最後你需要操作手機,選擇「我確定要解鎖」。而一加則要簡單得多:手機先在Android裏打開「允許OEM解鎖」,然後進入bootloader,再然後電腦上輸入fastboot oem unlock
,最後手機上選擇「我確定要解鎖」。整個流程都是離線完成,不需要考慮廠商是否會不批准。
在解鎖後,你可以刷入自定義/第三方的recovery,或是不刷入而直接引導自定義recovery。我一開始接觸的時候在用的是clockworkmod recovery(CWM),而後來在用的普遍都是TWRP(Team Win Recovery Project)。個人感覺變化的主要因素是CWM不支持觸屏(後來有修改版支持,但已經不如當時的TWRP好用了),而TWRP支持。
假如你可以找到適用於你的手機的recovery,從bootloader進入recovery的方法是(假如你的recovery文件名叫twrp.img):
fastboot boot twrp.img
這裏你還可以選擇傳統方法,就通過bootloader直接刷入自定義recovery,然後你再啓動進入自定義recovery。這兩者的區別就在於你是想一次性還是想長期(直到刷入另一個recovery前)使用這個recovery。我個人傾向於每次都手動進入,除非ROM要求刷入。刷入recovery的命令不知是否統一,但我所見過的應該都是這個命令(執行前一定要注意查證資料,以免造成問題):
fastboot flash recovery twrp.img
在進入了recovery後準備工作一般就完成了,下一步就是刷入你的新ROM。
對於多數ROM來說,在刷入前還是刷入後再執行清理沒有什麼區別。但部分ROM有特殊要求,會要求你在刷入前執行一些額外操作。這裏不表,請參照具體的ROM說明。
刷入新ROM
刷入ROM的一般方法是將ROM複製到手機中,然後在(第三方)recovery下執行刷機。比如在TWRP中,就是通過「安裝」菜單,選擇該ROM,然後刷入。
這種模式也被稱爲「卡刷」。因爲早期Android手機普遍內置閃存較小,因而都允許插閃存卡/存儲卡(MicroSD/TF卡)。早期的卡刷模式都是將ROM放在閃存卡的根目錄下,然後在手機上刷入。
另一種早期使用較多的方法是通過sideload來刷入,比如將手機置於recovery下然後在電腦上執行adb sideload XXX.zip
。
這種模式有時也被稱爲「線刷」,因爲需要通過數據線向手機傳輸ROM。但更典型的「線刷」是指使用專門的工具來刷機(寫入ROM),更類似我所用的救磚工具。
以我所知,現在一般都採用第一種方式,畢竟該方式不太受數據線和接口素質影響,更不容易出錯,而且可以手機獨立完成,更爲便利。
早期在刷機前經常會要求(用戶)擦除System分區,大約是爲了減小尺寸,或是降低干擾的可能性——ROM會直接向System中寫入新數據,而沒有被覆蓋的數據都還留在原處。而現在普遍的要求是不要擦除System分區,大約是各個ROM會自己進行規定。
清理數據
在刷入新ROM之後,一般都還需要對舊ROM的數據進行清理,以免干擾新系統的運行——因爲系統會去讀取這些數據,然後一般都會讀取失敗,導致無法正常啓動。
這一步驟經常被稱爲「雙清」。事實上,早期清除的內容實際上是三部分:Dalvik Cache、Cache分區以及Data分區。而現在的清除一般都寫的是清除Dalvik Cache/Cache,以及抹去/data/
——不再是抹掉整個Data分區,因爲/sdcard/
現在合併到了Data分區中(以便1.更靈活地使用空間;2.進行加密;3.多用戶共存)。 我至今也沒有明白,現在Dalvik Cache是否還存在——畢竟從Android 5開始,Dalvik應該已經被ART取代了。
多數recovery應該都設計了專門的清除選項,只要在刷完ROM後執行即可。對於跨ROM刷機的,一般都會要求完整的雙清,因爲不這樣做幾乎必然導致bootloop。對於本ROM(升級)或兼容ROM(比如OOS和H2OS)刷機的,可以考慮只清除各種緩存(cache),但也並不總是可以。
刷入後續包
對於多數ROM,完成上一步就可以認爲已經完成了,可以考慮重啓進入系統了。但部分ROM會要求再繼續刷入其他包,部分用戶也想自己刷入其他東西(比如進行root),這就要進入本步了。
對於以前的沒有A/B分區的手機,這一步可以直接在recovery中繼續。但對於進行了A/B分區的手機,這一步需要你重啓,以便切換當前槽爲新刷的系統所在槽,然後再次進入recovery後進行。
TWRP中有「切換A/B分區」的選項,但我不確定選擇它在這裏是否可用,而且也沒有資料提到。
一些典型的需要刷後續包的事情如刷入GApps(Google套件,一般都是第三方的,如OpenGApps),或者刷入Magisk(一種很優秀的root方案)。
A/B雙槽啓動
爲了理解爲什麼需要重啓,這裏就要解釋一下A/B分區模式下手機的啓動和刷機。
其基本模式就是讓手機存儲器上同時存在兩份系統,其中一份(假如是A)是「當前」使用的,另一份(假如是B)是「後備」系統。系統更新時,會將B更新爲新系統,不修改A。而在更新完成後,會切換B爲「當前」使用的系統,使得A成爲後備系統。
刷機時也是類似的,刷機包會安裝到後備槽上。但後續的附加包一般都是對「當前」槽進行操作,所以重啓是必須的。
個人猜測,其實recovery並不管你要安裝到哪個槽,而是由刷機包決定。
特殊模式
上面描述了一下典型的Android刷機模式,但總有一些手機比較奇特,不遵循這個範式。
最典型的是需要使用線刷工具來刷機(可以自己選擇ROM),不能在手機上自主完成。我所知道的有部分三星手機和部分摩托羅拉手機都要這樣,不確定這裏的「部分」究竟有多大比例。有的需要解鎖,有的不需要。
所以具體到某個手機,還是需要尋找其相關刷機教程,確定怎麼做。
我似乎記得還有一種方案,是先獲取root權限,然後直接在已有Android系統中寫入。這種方案感覺更危險,而且我現在找不到例子,沒準是我記錯了。
額外事項
由於手機畢竟不是PC,每個廠商有自己的一些特殊設計/設置,而這些設計/設置是有可能隨着手機升級而調整的。比如說,由於手機的fastboot同時承擔了BIOS/UEFI和bootloader的功能,部分手機在升級時偶爾會調整其具體細節。所以,在刷機時一定要確定好自己所使用的recovery和想要刷入的ROM與你的手機(版本)相兼容(比如可能會體現爲fastboot版本,可能會體現爲基帶版本,可能會體現爲原系統版本)。
比如說我的HTC One S,在其HBoot(其實就是它的bootloader)從3.13升級到3.14版本(好像是這兩個版本號)的時候,會調整分區表,從固定/靜態劃分/data
和/sdcard
對應分區的方式轉換成動態劃分的方式。HBoot的這個升級是伴隨系統升級而來的(一般用戶是感覺不到的),所以後來的刷機包一般都會強調自己所兼容的HBoot版本。
另外,理所當然的,每個ROM和recovery一般都是對某「一款」手機開發的(當然也有例外,但一般都是手機的另一個變種,比如一加6和一加6t的一些ROM就是共用的)。所以在刷機時一定要選擇適用於自己手機型號的對應軟件。又由於上面提到的因素,請務必檢查自己手上的軟件和自己的手機相兼容。一般而言官方(比如twrp的官方)的最新版總是最佳選擇,但有時社區的第三方版可能是更好的選擇(比如官方不再提供支持,或者官方還沒推出解決某個問題的版本)。
最後,一般建議在刷機前解除手機的設備保護(也就是手機鎖)。因爲它會和數據加密相連,而有時這些加密會導致不便。一個典型場景是加密狀態下進行nandroid備份(在recovery中進行的備份一般都是nandroid備份),後來使用該備份進行恢復後,輸入密碼不識別。
救磚
在翻閱了大量資料後,我找到了一加6的救磚工具(救磚工具合集1 救磚工具合集2)。該工具是Windows程序。從應用程序名稱上推斷,它是直接用於高通處理器的(甚至是高通提供的)數據寫入器。
該工具很簡單,但相關說明寫得不夠詳盡,甚至有錯誤(不需要的要求)。我摸索着用起來了,但出現了意外,卡在了某個步驟上。當時這個現象嚇得我一緊,因爲我知道在該模式下出錯更危險。後來翻閱了好久,發現有驚無險,最終找到解決方案。
使用該工具前需要先安裝專門的串行設備驅動程序。救磚工具合集1給出了驅動貼子。該驅動的貼子中說需要手機可以加載fastboot,但實際上不需要——因爲我的手機就無法正常進入fastboot/bootloader。
安裝驅動的方法是:首先在關機狀態下,長按VolUp+電源鍵(音量上+電源)進入高通刷機模式。進入該模式後會亮起黃色呼吸燈。將手機和電腦用數據線連起,電腦會提示找到新的串行設備,然後嘗試自動搜索驅動。
2021-11-07更新:本日進入該模式時候,手機並沒有亮起呼吸燈。當然,這次手機也沒有完全磚掉,不知道是否是受此影響。
按照貼子的描述,這時候要卸載那個設備的驅動。然後用管理員權限開啓一個命令行,執行下面的命令,重啓進入測試模式,重新將手機連上電腦,再安裝驅動:
bcdedit /set testsigning on
然而我的經驗發現,Windows 10沒法自動找到合適的驅動,所以似乎不需要進入測試模式也可以。當然,我爲了保險,還是按照了他的說明進了測試模式操作。
進入測試模式是因爲測試模式不會自動安裝驅動,可以避免干擾。
當然,在一切執行完畢以後,不知道重啓是否直接進入普通模式的我最後執行了這個命令,再重啓電腦進入普通模式:
bcdedit /set testsigning off2021-11-07補:之前安裝好驅動,本次沒有進入測試模式,也完成了救磚。不過救磚工具在「發送文件」後就沒受到後續消息/指令了;但手機自動繼續了,似乎是正常救好了。
在安裝完驅動後,不要動手機,使用管理員權限執行救磚工具。我這裏打開會需要等待一下。然後在工具中應該就能看到一個串行設備,已經插入。我爲了穩妥,又校驗了一次文件。完畢後,執行寫入即可。寫入需要一點時間,不過也不是很久,之後手機會自動重啓(工具裏有這個選項),進入系統。這時候的手機可以類比爲相應的出廠狀態——當然,已經被使用損耗的部分肯定不會回去。
我下載的第一個工具(OOS 10.3.5版本)在寫入時出了問題,卡在一個早期步驟上。查閱後發現,我需要換更早期版本的工具使用。也有人說可以換個其他版本的驅動,不過我沒有試。
每個版本的救磚工具都對應了一個特定的ROM,是隨着那個工具一起下載下來的(不是一般所用的.zip
形式的ROM)。我猜測裏邊有簽名或者文件描述一類的信息,以保證只能刷所規定的文件。
OOS 9.0版本的工具是可用的,但我發現手機無法繼續接收更新,手動選擇文件更新會被拒絕。進入twrp後發現直接刷入新版本OOS,會導致bootloop。同時我還試了在這種狀況下刷其他ROM,無果。
無意中,我發現連接到電腦上時,內核會打印出設備型號,而該版本下打印的型號是A6003。而我記得我的手機之前是A6000。查閱維基百科的一加6設備頁面,發現該型號對應的是歐美地區版本。我沒有細究這個版本是否會影響手機官方升級。
最終我使用了更早版本的救磚工具,而且用了氫OS的版本(H2OS5.1.3救磚工具),以降低可能的影響升級的因素。該版本在我的手機上可以正常升級。
刷上來的是H2OS 5.1.3版本。該版本第一次升級會升級到H2OS 9.x.x,然後第二次升級到H2OS 10.x.x。如果想要切換到OOS,需要在H2OS 9.x.x的時候刷對應的稍微更新版本的OOS 9.x.x,然後更新到OOS 10.x.x,否則會拒絕升級。目測原因是系統不允許降級,而10.x.x的OOS比H2OS版本號更低。
2021-11-07補1:線刷完後,設備型號顯示的是ONEPLUS A6000,也就是中國(大陸)出售的設備對應型號。對我來說這是正確的型號。在通過前述方法切換到OOS後(以及再繼續刷其他ROM),不記得什麼時候就變成了A6003,也就是國際(歐洲?)版本。但今日又失誤出了問題,於是重新刷機,按下面的操作流程執行,在切換到OOS 10.0.1、10.3.9及最終的11.1.1的時候仍然是A6000。
2021-11-07補2:線刷完後,H2OS一次更新到的是9.0.8版本(然後會繼續提示更新,這裏是H2OS 10.x版)。該版本可以通過安裝10.0.1版的OOS包切換到OOS,其文件名爲
OnePlus6Oxygen_22_OTA_041_all_1911142043_dde113e53cd0f9.zip
。同時我還測試過OnePlus6Oxygen_22.J.52_OTA_052_all_2103022341_f3ff04643ea24e51.zip
和OnePlus6Oxygen_22.J.55_OTA_055_all_2107132218_71d1c06b31fc.zip
,均無法更新,直接提示「安裝失敗」。注意這裏的52版(對應OOS 10.3.9)是從官網下載的,和XDA上有人提供的OOS鏡像合集中的52版並不一樣(官方是2021-03-30更新,XDA的看名稱是2021-03-02更新)。注意,由於未知原因,該版本在解鎖後,無法正確執行fastboot boot twrp-xxx.img
,會在傳輸完畢後Booting階段提示FAILED (remote: 'unknown command')
。受這裏討論的啓發,在使用前述52版本更新後(未嘗試其他版本),可以正常執行該fastboot命令。2021-11-07補3:由於一加未給出內核源代碼,所以TWRP無法完全正確支持OOS 11,無法在更新後刷入或引導加載進入(如這裏)。但根據這裏的說明,最終使用了一些技巧以保留Magisk和TWRP,並更新到OOS 11。
小結後記
事情的直接原因當然是我麻痹大意,以爲憑着過去的經驗可以橫行無阻。然而事實給我教育了一下,前後一共浪費了快兩天的時間。
但這側面也反映了一個問題,就是Android的機制弄得夠麻煩,而且文檔很不明確。一加還是一個對刷機非常友好的廠商,都能出一些不夠直覺化的現象,那麼其他廠商應當會有更奇怪的現象了。這也可以解釋他們爲什麼不願意支持刷機——當然,名義上肯定是說這是爲了用戶可以「使用受信任的系統」或是「爲了用戶體驗」。
Android的第三方ROM開發其實也是很迷的一件事。我感覺他們應該有一些文檔(比如解釋每個模塊都是什麼用處,如何port其他ROM上的模塊過來),但我始終找不到在哪(我唯一找到的就是CM/LOS的編譯指導,而且也不夠清晰)。刨去許多不開源的,明明也有一些ROM是開源的,但給我的感覺還是在圈地自萌。
我後來又試了AncientROM和BlissROM,最終由於功能更多以及漢化更完善,選了BlissROM。目前用下來沒什麼問題,電量消耗可以接受——但電量消耗統計仍然和實際電量消耗對不上號。然而它還是Android 10,算是一個缺憾吧。
您可以在Hypothesis上的該群組內進行評論,或使用下面的Disqus評論。