☰
HTC老机型刷机全链路:S-ON解锁、Recovery覆盖与RUU救砖
2026/11/3 22:05:52 网站建设 项目流程

1. 抽屉里那台老 HTC,真正的门槛从来不是“解锁”这一步

每年总有那么几次,会有人抱着一台屏幕已经有点发黄的老机器来找我,说想把它救活。型号多半是 One 系列、Desire 系列或者 Butterfly——这些机器放在今天连当备用机都勉强,但当年确实是一批很有个性的产品。他们的诉求也很统一:解锁 bootloader、刷 recovery、刷 ROM,把原厂那套早就不更新的系统换掉。

我这些年帮人折腾下来,最常见的误区就是大家都把注意力全部放在“解锁”上。觉得只要拿到解锁码、跑完那几行 fastboot 命令,后面就是顺水推舟。实际情况恰恰相反:解锁往往是全流程里最省心的一步,真正让人卡住的是解锁之后那台机器开始不听话——recovery 明明刷进去了,一重启却变回原厂;ROM 包明明刷完了,机器卡在开机动画上十几分钟不动;或者更极端的,刷完之后连 fastboot 都进不去,只能当镇纸用。

这篇内容我想讲清楚的,就是 HTC 这一系列机型从 S-ON 到刷完第三方 ROM 的完整链路。不是那种“复制粘贴六行命令就完事”的速通攻略,而是把每一步背后的分区机制、安全标志位、固件匹配逻辑都摊开来讲。因为 HTC 在安卓阵营里算是把“安全限制”做得最重的一批厂商,它的 S-ON/S-OFF 双状态、CID/MID 双重校验、固件版本绑定,这几层门槛叠在一起,形成一个任何一环没对上就会失败的链条。你只有理解了这层结构,才知道报错码 160 和 170 的区别在哪,才知道为什么有些机型解锁之后依然刷不进 recovery。

适合读这篇的人大概分两类。一类是手上正好有一台 HTC 老机器,想把它刷活,需要一份能照着走的完整流程;另一类是对安卓底层分区、bootloader 安全机制感兴趣,想拿一台结构清晰的机器当样本研究。两类人的目标不同,但需要的底层知识是同一套。我下面会尽量把原理和操作穿插着讲,遇到必须动手的地方给出具体命令和预期输出,遇到容易翻车的地方单独拉出来说。

先说一个总的判断:HTC 刷机的难点不在于“会不会敲命令”,而在于信息核对。你得先知道自己手上这台机器是什么 CID、什么 MID、固件版本到哪一档,这三个信息决定了你能刷什么、不能刷什么。跳过这一步直接开刷,后面所有的坑基本都是这么埋下的。

1.1 S-ON 与 S-OFF:两张不同权限的门禁卡

理解 HTC 刷机,绕不开 S-ON 和 S-OFF 这对概念。S 指的是 Security,本质上是 bootloader 里的一个安全标志位,它决定了哪些分区对你开放写入权限。

用生活化的说法:S-ON 状态下的手机像一栋门禁管理严格的小区,你只有自己那一户的钥匙,公共区域(boot、system、recovery)的门是锁死的;官方解锁相当于给你办了一张访客卡,能进大堂和几部电梯,但配电房、水泵房(radio、hboot、splash 这些底层分区)依然进不去;S-OFF 则是给你配了物业总钥匙,整栋楼随便走。

这三种状态能做的事情差别很大,我整理成表更直观:

权限状态boot 分区system 分区recovery 分区radio / hboot / splash典型用途
S-ON 未解锁不可写不可写不可写不可写只能用官方 OTA
S-ON 已解锁可写可写可写不可写刷第三方 ROM 的主流状态
S-OFF可写可写可写可写刷固件包、改 CID、救砖

这里有个关键点很多人没意识到:官方解锁得到的是 S-ON 状态下的有限写入权限,它并没有把 S 标志位改成 OFF。所以你在 bootloader 界面看到的依然是 S-ON,只是多了一行 UNLOCKED。这也解释了为什么解锁之后你能刷 recovery 和 ROM,却刷不了 radio 和 hboot——那些分区不在访客卡的授权范围里。

S-OFF 在 HTC 的历史上是个敏感话题。早期有通过特定 HBOOT 版本漏洞实现的方案,后来主流是通过付费工具或者特定机型的工程模式实现。这块我不展开讲具体手段,因为不同批次、不同 HBOOT 版本的路径差异极大,而且操作本身风险不低——S-OFF 过程中断电或者操作失误,机器变砖的概率明显高于普通刷机。对于绝大多数“我只想刷个第三方 ROM”的需求来说,S-ON 加官方解锁完全够用,没必要为了追求 S-OFF 去冒额外的风险。这是我个人非常明确的一个建议。

1.2 CID 和 MID:决定“这个包能不能进”的两道门

如果说 S-ON/S-OFF 决定的是“能往哪写”,那 CID 和 MID 决定的就是“允许谁写”。

MID(Model ID)是机型标识,比如同一代 One 系列,不同地区版本、不同运营商版本的 MID 可能都不一样。CID(Customer ID)是客户标识,通常和销售区域、运营商绑定。常见的 CID 形式像HTC__001、HTC__621、CWS__001、T-MOB101这种,前面几位基本能看出归属。

这两个值在刷 ROM 时的作用,体现在 ROM 包的 updater-script 里通常会有一段 assert 校验:

assert(getprop("ro.product.device") == "m7" || getprop("ro.build.product") == "m7"); assert(htc_getcid() == "HTC__001" || htc_getcid() == "HTC__621");

如果你的机器 CID 不在这份白名单里,recovery 会直接中断刷入,报一个Status 7错误。很多人第一次遇到这个错误会懵,以为是包坏了,其实是 CID 对不上。

查 CID 和 MID 的方法很简单,进 fastboot 模式后跑:

fastboot getvar cid fastboot getvar mid

预期输出大概是这样:

cid: HTC__621 mid: PN0710000

把这两个值记下来,后面选 ROM 包、判断 RUU 能不能用,全靠它们。

至于 superCID——把 CID 改成11111111以绕过所有 CID 校验——属于 S-OFF 之后才能做的操作,而且改完之后部分官方 OTA 会失效。我一般不建议新手碰这个,除非你确实遇到了“找不到对应 CID 的 RUU”这种死局。

1.3 固件版本:一道看不见但有硬性约束的天花板

第三层限制是固件版本。HTC 的 bootloader 和 radio 打包在一起叫固件(firmware),不同大版本的固件对应的分区布局、boot 镜像格式可能不一样。

举个具体例子:一台机器如果固件停在 5.x 这一档,你直接刷一个要求 7.x 固件的 ROM 包,最常见的结果是刷入过程顺利、重启后卡在第一屏(白底绿字那个 HTC logo 界面)无限循环。因为新 ROM 的 boot.img 里内核期望的分区布局和老固件不匹配,内核起不来。

查固件版本用:

fastboot getvar version-main

输出类似6.09.401.5。这个号要和 ROM 包说明里要求的固件版本对得上,差一个大版本基本就不能刷。

所以一个完整的选包逻辑应该是:先看版本号能不能对上,再看 CID 在不在白名单,最后看 MID 是否匹配。三步都过了再动手,能省掉后面大量的排错时间。我见过太多人反过来——先下载一个看起来不错的 ROM,刷不进去再回头查信息,结果查出来是自己的固件版本差了两档,白折腾一晚上。

2. 开工前的三件事:驱动、平台工具、机型信息存档

动手之前的环境准备,是整个过程里最枯燥但最不能省的部分。HTC 这一系列机器对驱动和 USB 环境的要求,比同期很多品牌都要挑剔。我遇到过不止一次“命令没错、包没错,就是 fastboot devices 死活不显示设备”的情况,最后查出来都是驱动或者 USB 口的问题。

2.1 Windows 下的驱动,别指望系统自动装

Windows 10/11 对安卓设备的通用驱动支持其实还行,但 HTC 进 fastboot 模式后的设备标识和正常开机时不一样,系统经常会认成一个未知设备。表现就是adb devices能看到机器,fastboot devices一片空白。

我的做法是手动装驱动,路径是:设备管理器里找到那个带黄色感叹号的设备,右键更新驱动,手动指向解压好的驱动目录。驱动来源有两个选择,一个是 HTC 官方曾经提供的同步工具里自带的驱动包,另一个是通用的安卓 USB 驱动,需要手动编辑 inf 文件把 HTC 的厂商 ID 加进去。

HTC 的 USB 厂商 ID 是0bb4。在 inf 文件里加一段大概长这样:

;HTC %SingleAdbInterface% = USB_Install, USB\VID_0BB4&PID_0FF0 %CompositeAdbInterface% = USB_Install, USB\VID_0BB4&PID_0FF0&MI_01

改完之后记得关掉驱动签名强制检查,否则装不上。

这里还有一个特别容易被忽略的细节:别用 USB 3.0 口,也别用前置面板的口,更别接集线器。HTC 老机型在 fastboot 模式下对 USB 3.0 controller 的兼容性很差,插上去大概率识别不稳定,表现为命令能发出去但设备中途掉线。我一般固定用主板后置的 USB 2.0 口,一条质量好点的短线,这个组合的成功率最高。

2.2 平台工具的版本,不是越新越好

安卓的平台工具包(platform-tools)更新很频繁,但新版本对老设备的兼容性反而可能出问题。特别是一些老 HTC 机型,在极新的 fastboot 版本下会出现FAILED (remote: unknown command)这种莫名其妙的错误。

我自己的习惯是备一份相对老一些的版本专门用来刷这类机器,大概在 30 左右的版本号那一档,用下来最稳。新版留着刷新机器用。这个不是玄学,老版本对老协议的兼容处理确实更宽容。

另外提醒一下,平台工具解压出来之后,建议把整个目录加到系统环境变量里,或者干脆把命令都在这个目录下执行。我见过有人把 fastboot.exe 单独复制到桌面用,结果因为找不到同目录下的 AdbWinApi.dll 而报错,排查了半天。

2.3 把机器档案完整存一份下来

这一步是我强烈建议所有人都做的:在动任何东西之前,先把fastboot getvar all的完整输出存成一个文本文件。

fastboot getvar all > my_htc_info.txt

输出里会包含 CID、MID、version-main、imei、serialno、分区大小等一大堆信息。这份文件的价值在于,万一后面刷出问题需要救砖,你可以拿它去比对 RUU 包的匹配条件;万一需要找人求助,把这份文件发出去对方一眼就能判断你的机器状态。

getvar all的输出里有些字段涉及设备唯一标识,分享给别人的时候记得把 imei 和 serialno 那两行删掉。

顺带说一句,HTC 的getvar all在某些 HBOOT 版本上会有字段截断或者输出乱序的情况,属于正常现象,不影响使用。

3. 官方解锁的完整走法,以及那几个卡人的返回码

HTC 曾经提供过一条官方的 bootloader 解锁通道,流程是注册账号、提交设备标识、等待邮件、刷入解锁令牌。这套流程在当年算是比较开放的,但也设置了若干限制条件。虽然现在这条通道的实际可用性因机型而异,但流程本身值得完整讲一遍,因为里面涉及的 token 机制、返回码含义,是理解 HTC bootloader 安全模型的最好样本。

3.1 从设备上取出标识 token

第一步是在 fastboot 模式下取设备标识:

fastboot oem get_identifier_token

执行后终端会输出一大段以<<<< Identifier Token Start >>>>开头、<<<<< Identifier Token End >>>>>结尾的内容,中间是一堆十六进制字符块。这段内容需要原样完整复制,包括起始和结束标记行,中间不能有多余的空格或者换行错位。我见过有人复制的时候不小心把某一行合并了,提交上去直接报 token 无效。

取完 token 之后,把它粘贴到官方解锁页面的提交框里。如果设备型号在该渠道的支持列表内,几分钟到几小时内会收到一封邮件,附件是一个叫Unlock_code.bin的文件。

3.2 刷入解锁令牌时屏幕会接管操作

拿到Unlock_code.bin之后,把它放到平台工具目录下,机器保持 fastboot 模式,执行:

fastboot flash unlocktoken Unlock_code.bin

这条命令的执行结果和普通 fastboot 命令不太一样——它会先输出发送成功的提示,然后手机屏幕上会弹出一个确认界面,问你是否确认解锁。这个界面上需要用音量键移动光标,电源键确认选择。

这个设计当年是为了防止误操作,但也坑了不少人:有些人在电脑前等了半天没反应,以为命令失败了,实际上手机屏幕在等他们按电源键。所以执行完这条命令,眼睛要盯着手机屏幕,不是盯着终端。

选择确认之后,手机会自动重启并清空所有数据。注意,是清空所有数据,包括内置存储里的照片文件。这一步没有撤销余地,动手之前该备份的一定要备份。

3.3 返回码是诊断信息,不是故障编号

解锁过程中最常遇到的几个错误码,含义其实很明确,但官方从来不好好解释,我按实际遇到的情况整理一下:

返回码实际含义处理方向
Error Code: 160MID 不在该渠道的支持列表该机型不支持官方解锁,只能找其他路径
Error Code: 170CID 不在支持列表运营商定制机常见,需先改 CID(要 S-OFF)
Error Code: 130token 校验失败多半是复制粘贴时格式错位,重新取一次
Error Code: 155设备已是解锁状态无需重复操作
Error Code: 159电池电量过低充到 50% 以上再来

这里面 170 是最让人无奈的。运营商定制机在出厂时就锁死了 CID,官方渠道不给解锁,而改 CID 又需要先有 S-OFF,形成一个闭环。这类机器的处理路径会复杂很多,不是简单几步能解决的。

还有一个细节:解锁成功之后,bootloader 界面会显示*** UNLOCKED ***,同时 S 状态依然是 S-ON。很多人看到 S-ON 就以为没成功,反复重刷,其实已经到位了。

4. recovery 刷进去了又“消失”:分区覆盖机制与真实原因

这是整个流程里最高频的翻车点,也是我最想重点讲清楚的部分。现象很统一:fastboot flash recovery xxx.img提示成功,紧接着fastboot reboot,等系统起来之后关机再进 recovery——变回原厂那个简陋的蓝色 recovery 了,第三方 recovery 凭空消失。

第一次遇到这个现象的人通常会怀疑是镜像文件有问题,反复换包重刷,折腾半天没有进展。其实这不是刷失败,是刷成功了然后被覆盖了。

4.1 覆盖机制的来龙去脉

安卓系统里有一个机制叫 recovery-from-boot,作用是保证系统更新后 recovery 分区能自动恢复成官方版本。具体实现是 system 分区里放了一份官方 recovery 的备份(通常叫recovery-from-boot.p),在系统启动过程中由某个脚本检测 recovery 分区是否被改动,如果改动过就用备份覆盖回去。

这个机制的初衷是好的——防止恶意软件替换 recovery。但对刷机的人来说就是个障碍。

关键在于触发条件:它是在正常启动进入系统时触发的。所以如果你刷完 recovery 之后立刻重启进入 recovery(而不是重启进入系统),这个覆盖就不会发生。

正确的操作节奏是这样:

fastboot flash recovery twrp.img fastboot boot twrp.img # 部分机型支持直接从内存引导 # 或者刷完后手动断电,用组合键直接进 recovery

HTC 大部分机型不支持fastboot boot从内存引导 recovery,所以实际操作是:刷完之后拔数据线,长按电源键强制关机,然后按住音量下加电源进 bootloader,再用音量键选 RECOVERY 进去。

进去之后要做一件事:立刻在 recovery 里刷入一个能阻止覆盖的东西,或者直接把 system 分区挂载为可写并删掉那个备份文件。TWRP 里通常在高级设置或者文件管理器里能操作,路径是system/recovery-from-boot.p和system/etc/install-recovery.sh这两个,删掉或者改名都行。

4.2 除了覆盖,还有两种“recovery 消失”的假象

第一种假象是根本没写进去。HTC 部分机型的 recovery 分区有额外的写保护,fastboot flash recovery会返回 OKAY,但实际上什么都没写。判断方法是刷完之后不要重启,直接选 RECOVERY 进去看看,如果还是原厂的,那就是没写进去。这种情况多见于 S-ON 状态并且 bootloader 版本较新的机器。

第二种假象是进了错误的 recovery。有些 HTC 机型在 boot 分区里内置了一个简易的恢复模式,当检测到 recovery 分区损坏或者校验失败时会自动跳到这个内置模式。这个界面长得和原厂 recovery 很像,容易让人误判。区分方法是看界面上的版本号和菜单项,内置模式的菜单通常只有三四项,而且没有 adb 支持。

4.3 我总结的一套稳定操作顺序

折腾了这么多台之后,我固定用下面这个顺序,成功率最高:

  1. 确认机器已解锁(bootloader 显示 UNLOCKED)
  2. 进 fastboot,刷入 recovery
  3. 不重启,直接强制关机
  4. 组合键进 bootloader,选 RECOVERY
  5. 进入 TWRP 后第一件事:挂载 system,删掉覆盖脚本
  6. 再做后续的 ROM 刷入操作

第 3 步的“强制关机”看起来粗暴,但它能确保刷入的 recovery 不被系统启动流程干扰。长按电源键 10 到 15 秒,屏幕黑了就松手,这个操作对硬件没有损害。

还有一点提醒:刷 recovery 之前先确认电池电量。HTC 老机器电池老化严重,标称 30% 电量可能实际只剩几分钟。在 recovery 里刷 ROM 的过程中断电,是变砖的高发场景。我一般要求电量显示在 50% 以上才动手。

5. 刷 ROM 的完整链路:固件匹配、boot 分区和首次开机

刷 ROM 这件事,说简单也简单,recovery 里点几下就完事。但它包含了最多的隐性条件,任何一个条件不满足,结果都是同一个——卡第一屏。

5.1 S-ON 状态下 boot 分区要单独刷

这是 HTC 刷机区别于其他品牌的一个关键点,很多人不知道,直接导致刷完开不了机。

在 S-ON 已解锁的状态下,虽然 recovery 有能力写入 boot 分区,但部分机型的 bootloader 会在 recovery 环境下对 boot 分区做额外保护,导致 ROM 包里的 boot.img 写入失败——而且这个失败是静默的,刷机脚本不会报错。结果就是 system 分区更新了,boot 分区还是旧的,内核和系统版本对不上,开机直接卡死。

解决办法是刷完 ROM 包之后,单独把 boot.img 提取出来,用 fastboot 再刷一次:

# 从 ROM zip 里提取 boot.img unzip rom.zip boot.img # 刷入 fastboot flash boot boot.img fastboot erase cache fastboot reboot

fastboot erase cache这一步不要省。HTC 的 cache 分区里存着上一次启动的一些状态数据,跨版本刷机之后不清 cache,很容易出现开机动画循环或者应用频繁崩溃。

5.2 双清清的是哪几个分区,顺序有讲究

recovery 里的“双清”这个说法其实不太准确,实际操作涉及的分区不止两个。我一般按下面的顺序清:

  • Factory Reset / Wipe Data——清 data 和 cache,这是必须的
  • Wipe Cache——单独再清一次 cache,确保干净
  • Wipe Dalvik Cache——清虚拟机缓存,跨版本刷机必做
  • Format System——格式化 system 分区,可选但建议做

关于最后一项要说一句:format system 之后如果没有成功刷入 ROM,机器是开不了机的,会一直卡在开机界面。所以如果你对自己的 ROM 包没把握,可以先不清 system,等确认包能刷成功之后再考虑彻底格式化。

另外,清 data 会删掉内置存储里的所有东西,包括你自己放进去的 ROM 包。所以刷机包要放在外置 SD 卡上,或者刷之前先确认包在哪个分区。这个错误我见过太多次了,清完 data 发现包没了,只能重新拷。

5.3 首次开机慢到什么程度算正常

刷完 ROM 第一次开机,需要重建 dalvik 缓存、初始化应用数据,耗时明显长于日常开机。一台老 HTC 上,这个过程花 5 到 15 分钟都算正常。

判断标准是看开机动画有没有在动。如果动画在循环播放,说明系统还在初始化,耐心等;如果画面完全静止、卡在某个画面不动超过 20 分钟,那就是有问题了,大概率是 boot.img 不匹配或者固件版本对不上。

遇到卡死的情况,我的排查顺序是:先确认固件版本和 ROM 要求是否一致,再确认 boot.img 有没有单独刷过,最后才怀疑 ROM 包本身有问题。顺序很重要,因为前两个原因占了绝大多数。

还有个小技巧:如果机器支持 adb,卡开机的时候可以尝试adb logcat看内核日志。能连上说明 adb 服务起来了,日志里通常会直接写明是哪个分区挂载失败,比盲目试错高效得多。

6. 变砖抢救:RUU、rebootRUU 和返回码对照

刷机刷到进不去系统、也进不去 recovery,只剩 fastboot 能用的状态,行话叫“半砖”。这种状态其实还有救,只要 fastboot 还认设备,通过 RUU 恢复官方固件的成功率很高。

RUU 是 HTC 官方发布的完整固件包,包含 bootloader、radio、system 所有分区。它的限制条件很明确:CID 和 MID 必须完全匹配,固件版本不能低于当前版本(部分情况可以同版本刷)。

6.1 从 RUU 可执行文件里把 rom.zip 掏出来

官方 RUU 通常是一个 exe 自解压程序,直接运行会走图形界面,但那个界面在老机器上失败率很高。更可靠的做法是把里面的 rom.zip 提取出来手动刷。

提取方法:运行 RUU exe,等它解压到临时目录后(通常在你用户目录的临时文件夹下,会生成一个名字很长的随机目录),把里面的rom.zip复制出来。如果 exe 运行到一半就报错退出,可以在它解压的瞬间去临时目录里找,动作要快。

拿到 rom.zip 之后,确认一下包里的android-info.txt,里面写着这个包要求的 CID 和 MID:

modelid: PN0710000 cidnum: HTC__001 cidnum: HTC__621 mainver: 6.09.401.5

对照你自己记下来的机型档案,能对上才能刷。

6.2 为什么同一个包要刷两遍

手动刷 RUU 的流程是这样:

fastboot oem rebootRUU fastboot flash zip rom.zip

第一条命令会让手机进入一个黑底银字的 RUU 模式。第二条命令刷入时,第一次执行大概率会在中途返回FAILED (remote: 90 hboot pre-update!)。

这个 90 不是错误,是提示。它的意思是 hboot 部分已经更新完成,需要重新执行一次刷写来继续处理剩下的分区。所以看到 90 不要慌,再跑一遍同样的命令:

fastboot flash zip rom.zip

第二次会完整跑完,最后输出OKAY。然后执行:

fastboot reboot

如果两次都返回 90,那可能是包和机型不匹配,需要回头检查 CID/MID。

6.3 常见返回码与症状对照

返回码 / 症状可能原因处理方式
90 hboot pre-update正常的分段更新提示重新执行一次 flash zip
12 signature error包签名校验失败,包被修改过换官方原始包
41 model id check failMID 不匹配换对应机型的包
42/43 CID check failCID 不在白名单换对应 CID 的包,或先改 CID
99 unknown fail分区写入异常检查 USB 连接,换线换口重试
刷完卡第一屏boot.img 与 system 版本不匹配单独刷对应版本的 boot.img
进不了 recovery 但能进系统recovery 被覆盖见第 4 节的覆盖处理

最后说一个我自己的经验。老机器的 eMMC 闪存经过这么多年,坏块概率明显上升。如果同一个包反复刷都在同一个进度百分比失败,而且换包换线都一样,那要考虑是不是闪存本身出问题了。这种情况下再怎么折腾软件层面都是徒劳的,唯一的办法是接受它当前的系统版本,或者换一块主板。

还有一种情况值得单独提:有些机器刷完之后能开机、能用,但基带没了,表现为无信号、IMEI 显示未知。这一般是 radio 分区在刷写过程中被意外擦除。S-ON 状态下没法直接刷 radio,只能通过对应版本的 RUU 整包恢复。所以刷 ROM 之前把 RUU 包先下载备好,这个习惯能救不少急。

折腾这类老机器,说到底是个信息核对和耐心的活。命令本身没几条,难的是知道每条命令背后动了哪个分区、为什么必须按这个顺序。我自己这些年刷下来,最深的体会是:动手前花二十分钟把 CID、MID、固件版本、分区布局查清楚,能省掉后面两小时的排错。急着按教程复制粘贴的人,最后往往要花更多时间在“为什么我不一样”这个问题上。至于那些实在救不回来的机器,也别太执着,它们该退休了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询