在实在受不了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評論。