记一次把旧手机刷成原生 Linux 服务器的完整折腾过程

手头有一台闲置很久的乐视第 2 代手机,具体型号是 Le X620。平时放在抽屉里一直吃灰,刚好最近想搭一台低功耗的本地服务器跑点服务,就寻思着能不能把这台旧手机利用起来。

先看下这台手机的硬件:搭载的是联发科 MT6797也就是 Helio X20处理器,ARM64 架构,内存大概 3GB,内置存储的数据分区有 24GB,而且手机自带屏幕、Wi-Fi、USB 接口和电池。原机系统我之前刷了 MIUI,内核版本是 3.18.22+,之前也已经刷好了 Magisk root 和 TWRP recovery。

网上很多旧手机改服务器的教程,基本都是在 Android 系统里装个 Termux,或者在 Termux 里套一层 chroot 跑 Linux。但说实话,那种方式底层还是拖着一整套庞大的 Android 系统,资源占用高不说,跑后台服务也经常被杀。我这次的目标是彻底干掉 Android,不跑 Android framework 和 Zygote,直接让 Linux 的 init 作为 PID 1 启动,把这台手机真正变成一台用 SSH 管理的无界面 Alpine Linux 服务器。

这篇文章就把我从前期查资料、备份分区、踩坑 fastboot 回锁,到点亮全套手机硬件的全部过程完整记录一下。全文都是在这台 Le X620 上实测出来的结论,不同手机硬件差异很大,大家千万不要直接照搬镜像硬刷。

一、前期调研:网上有没有现成的包可以刷?

在动手刷机之前,第一步肯定是先去网上查资料,看看有没有前人做好的现成镜像。

我去翻了一圈公开资料,找到了乐视 2在 postmarketOS 和 LineageOS 上的页面,但仔细一看,那些全是基于高通骁龙 652 平台的机型比如 X520、X522、X526、X527,跟联发科 MT6797 的 X620 完全不是一码事,底层的东西根本不能混刷。

图1:postmarketOS 项目 logo(图源:Wikimedia Commons,postmarketOS developer team,CC BY-SA 3.0)

接着我又顺着 MT6797 这颗 SoC 去查,发现同系列的几款设备确实有人做过原生 Linux 移植:

  • Gemini PDA:用的是下游 3.18.41 内核,USB 网络可以用,Wi-Fi 部分支持,不过这个移植项目已经归档了。

  • Lenovo K8 Note:基于 MT6797D 和 3.18.60 内核,能启动原生系统,USB 网络也正常,但 Wi-Fi 是坏的。

  • 红米 Note 4:同样是 MT6797,但在官方页面上直接标了 Not booting。

图2:同为 MT6797 平台的 Gemini PDA(图源:Wikimedia Commons,Gareth Halfacree,CC BY-SA 2.0)

图3:同为 MT6797 平台的红米 Note 4,关于手机页显示十核处理器(图源:Wikimedia Commons,Dqwyy,CC0)

看到这里心里就有数了:首先,MT6797 这颗芯片跑原生 Linux 在技术上是绝对可行的;其次,网上找不到成品 Linux 镜像。而且玩手机移植最忌讳的就是看到同品牌或者同款 CPU就直接拿别人的 boot.img 过来刷,因为每台手机的分区布局、设备树、供电管理、屏幕和无线配置都不一样,乱刷必变砖。

既然没有现成的,那就自己动手丰衣足食。我最终定下来的方案是:保留这台手机原本就已经验证稳定的 3.18.22+ 原厂内核、设备树和底层固件,只把上面的 Android 用户空间抽掉,自己构建一套 Alpine Linux 3.24.2 ARM64 的根文件系统和启动配置。

图4:Alpine Linux logo(图源:Wikimedia Commons,Alpine Linux Development Team,MIT 许可)

二、刷机前准备:备份比刷机更重要!

在往手机分区里写任何东西之前,我先把退路给铺好了,这一步无论怎么强调都不为过:

  1. 在手机上打开 USB 调试,连上电脑确认 ADB 授权正常。

  2. 把 boot、recovery、system、LK、NVRAM、nvdata、nvcfg、protect、persist、seccfg 这些关键分区全部导出来备份到电脑。

  3. 实测用 adb reboot recovery 和物理按键(电源键 + 音量上)都能顺利进入 TWRP,确认 TWRP 能正常挂载分区,在后面的所有折腾里,recovery 分区绝对不动,确保随时有救砖通道。

  4. 去 Alpine 官方镜像站下载了 Alpine 3.24.2 的官方 ARM64 minirootfs,。

图5:手机上的 TWRP Recovery 主界面(实拍)

这里放一下我整理出来的原机关键分区对应表:

三、踩了个巨坑:这台手机的 fastboot 会自动回锁

按我们平时刷机的习惯,肯定是用 fastboot boot 命令先在内存里临时引导一下,看看 Linux 能不能跑起来对吧?

结果就在这里踩了第一个大坑: 我先用 fastboot getvar 确认了手机状态是 unlocked=yes、secure=no。接着执行 fastboot boot,电脑终端上明明返回了 OKAY 提示成功,但手机那边既没有出来 USB 网卡,也连不上 SSH。更吓人的是,手机重启后屏幕直接提示非官方系统无法启动,然后就开始无限循环重启了!

图6:fastboot 自动回锁后,开机提示“非官方系统无法启动”(实拍)

我赶紧重新进 fastboot 模式一查,发现 bootloader 的状态居然自己变成了 unlocked=no、secure=yes,回去翻刚抓下来的控制台输出才发现,当我执行 fastboot boot 的时候,乐视的 bootloader 竟然输出了 Fastboot oem devices is unlock -> Start lock flow -> Lock Pass...continue to fastboot——它返回 OKAY 的同时,居然在后台自己跑了一遍上锁流程,把手机给重新锁上了!

我重新执行 oem unlock 恢复解锁状态后,试了一下普通的 fastboot reboot,结果它又触发了一模一样的自动上锁!

再次解锁后,我老老实实用物理按键进到 TWRP,把手机里的诊断日志(logs/native-diagnostics-20261015-230635/)拉出来看,这才搞明白刚才发生了什么:其实第一次测试的时候,原生 Linux 的 BusyBox 已经成功作为 PID 1 跑起来了,只是当时网络初始化失败,240 秒看门狗正常触发了重启;结果因为 fastboot 刚才偷偷把 bootloader 给锁了,重启的时候校验不过,这才卡死在开机报错上。

吃一堑长一智,针对这台 X620,为了防止烧心,我给 deepseek 立下四条规矩:

  1. 绝对不用 fastboot boot。

  2. 绝对不用 fastboot reboot。

  3. 绝对不用 fastboot continue。

  4. 绝对不信 fastboot 返回码里的成功提示。

后面所有的刷写操作,我都改成进 TWRP,在 TWRP 里用命令写分区,写完立刻从分区把数据完整读回来算一遍 SHA256,核对无误后直接用 TWRP 重启或者在 Linux 里用 reboot 重启,再也没有触发过自动上锁的毛病。

四、临时启动排障:打通 USB 网卡、联发科 Wi-Fi 和 SSH

在正式清空 Android 之前,我靠着临时启动测试,先把最核心的网络和远程连接问题给挨个解决了。期间主要碰到了四个问题:

1. USB 复合设备互相卡死

一开始我想省事,打算在 USB 上同时开启 RNDIS(USB 网络)和 FunctionFS(ADB 调试)。结果实测发现,只要 FunctionFS 那边的服务还没准备好,整个 USB 复合设备就会被卡死,电脑上什么都认不出来。 解决方法很简单:我把原生系统下的 ADB 给砍了,改成只开 RNDIS(18d1:4ee3,设置 WCEIS=1)。这样一插上电脑,Windows 就会自动绑定系统自带的 Remote NDIS 驱动,手机端固定 IP 为 192.168.92.1/24,电脑直接通过 USB 就能连上手机。万一需要用 ADB,进 TWRP 也能用。

2. 联发科 Wi-Fi 驱动等不到 Android 属性报错

在手机上搞 Linux,Wi-Fi 绝对不是简单装个 wpa_supplicant 就能连的。这台 MT6797 的无线网卡需要先跑原厂的 wmt_loader,然后再用 6620_launcher 去加载固件。 但我在纯 Alpine 下跑的时候,内核一直报 no hif info 错误。排查后发现,原厂的 6620_launcher 启动时会去读 Android 的 property,而在纯 Linux 下根本没有 Android 的 init 和属性服务,它就一直在那傻等! 为了不把 Android 那套东西塞回来,我直接用 C 写了一个很小的动态库 scripts/mtk-native-properties.c,编译成没有任何外部 libc 依赖的 libnativeprops.so,只针对 6620_launcher 设置 LD_PRELOAD,在它读取属性时直接返回本机的 chipid 0x6797 和驱动就绪状态。接着把 /etc/firmware 和 /lib/firmware 软链接指向原厂固件所在的 /system/etc/firmware,只读挂载 /nvdata,再把 wpa_supplicant 不支持的 -f 参数去掉,Wi-Fi(wlan0)终于顺利连上路由器并拿到了 IP!

图7:终端里 ip a 显示 wlan0 已获取 192.168.0.118(实拍)

3. 连 SSH 卡死,按音量键才恢复

网络通了之后,我第一次连 SSH 时发现终端一直卡着不动,手机看起来就像死机了一样。结果我随手按了几下手机侧面的音量键,SSH 突然就连上了! 原因很蛋疼:老旧的 3.18.22+ 内核在刚开机时,系统随机数熵池里的数据不够,SSH 握手在傻等随机数生成;我按音量键刚好给内核产生了中断随机事件。找到原因就好办了,直接在系统里装上官方的 haveged 服务并设为开机自启,自动初始化随机池,以后重启再也不用去人工按音量键了。

4. 插着 USB 关机会进充电模式,一拔线就关机

在测试电源的时候我还发现一个问题:如果手机插着 USB 线执行 Linux 的 poweroff,它会重启进入 boot_mode=8(也就是内核参数带 androidboot.mode=charger 的关机充电模式)。在这个模式下,USB 会变成不工作的 MTP 状态,而且按原厂内核 mt_kpoc_power_off_check() 的逻辑,只要你一拔掉 USB 线,手机就会立刻自动关机;我想往 sysfs 的 boot_mode 里写 0 退出去,发现内核里那个写函数根本是空的! 于是我写了个 /usr/local/sbin/native-boot-mode 脚本放在开机早期执行:只要检测到当前是 boot_mode=8,就先在磁盘上记一个标记(防止万一失败陷入无限重启循环),然后自动执行一次正常的 Linux reboot。实测插着电关机后,它进到 mode 8 会自动重启一次跳回正常的 mode 0,USB 网络和所有服务全部自动恢复。

五、正式刷入 Alpine Linux 与持久化验收

临时启动把所有核心链路都跑通之后,就可以正式干掉 Android 了。整个安装过程是在 TWRP 里完成的,步骤如下:

  1. 再次核对电脑上备份好的原厂 boot、recovery、system 镜像哈希值和分区大小。

  2. 使用兼容旧版 3.18 内核的 ext4 参数,把 system 分区(mmcblk0p36)和 userdata 分区(mmcblk0p38)格式化掉。

  3. 把 Alpine 3.24.2 ARM64 的 rootfs 解压到 system 分区,作为 Linux 的根目录 /(解压出来大概也就 23 MB)。

  4. 把 userdata 分区挂载到 /srv,专门用来存服务数据和用户文件(可用空间约 23.8 GiB)。

  5. 把打包好的 16 MiB Linux boot 镜像写入 boot 分区(mmcblk0p31)。

  6. 写完之后,把分区内容完整读回来重新算一遍 SHA256,确认写入完全正确。

  7. 保持 TWRP recovery 分区原样不动,直接重启进入 Linux。

开机之后等了一两分钟,我按服务器标准做了一轮完整验收:检查 PID 1 确实已经是 /sbin/init;USB 网卡(固定 192.168.92.1)和 Wi-Fi 双路 SSH 都能用固定密钥连上;8080 端口的静态网页返回 200;SFTP 传文件正常;往 /srv 写了一个 1 MiB 的测试文件,重启后再算 SHA256 分毫不差。到这里,这台手机就已经是一台合格的 Linux 小服务器了。

图8:手机上的应用抽屉,可见 Thunar、Xfce 终端等(实拍)

图9:Xfce 桌面应用菜单(实拍)

更多游戏资讯请关注:电玩帮游戏资讯专区

电玩帮图文攻略 www.vgover.com