ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

安卓旧设备通电自启:修改boot.img实现无人值守开机

安卓旧设备通电自启:修改boot.img实现无人值守开机 1. 老旧安卓设备通电自启的需求拆解手里有一批安卓6.0的旧设备平板也好、广告机也好、工控板也好用久了都会碰到同一个烦人的问题设备老化之后电池鼓包或者彻底失效插着充电器能用但一断电再上电设备就停在充电图标界面不动了必须手动按一下电源键才能开机。如果是放在机柜里、挂在墙上、装在配电箱里的设备每次断电恢复都要派人去按一下电源键这个运维成本高得离谱。这个需求的核心就是让设备通电即开机不需要人工干预。听起来简单但安卓系统从设计上就不是这么想的——手机厂商默认的逻辑是插上充电器只充电不自动开机防止放在口袋里误触。这个逻辑写在boot.img里的init.rc和charger相关配置中要改掉它就得把boot.img拆开、改配置、重新打包、刷回去。适合看这篇内容的人手里有旧安卓设备想做无人值守部署的、搞广告机/数字标牌运维的、做安卓工控定制的、以及单纯喜欢折腾旧设备的玩家。不需要你是安卓系统开发工程师但至少要会用fastboot、能看懂基本的Linux命令、知道什么是镜像文件。下面我会从原理讲到实操把每一步为什么这么做都讲清楚。2. 为什么通电自启要改boot.img而不是别的地方2.1 安卓启动链条里boot.img扮演什么角色安卓设备的启动流程大致是这样的上电后先跑芯片内部的BootROM然后加载引导程序不同芯片叫法不同高通叫ABL/XBL联发科叫LK瑞芯微叫U-Boot引导程序再去加载boot.img。boot.img里面打包了Linux内核和ramdisk一个精简的根文件系统内核启动后会执行ramdisk里的init程序init读取init.rc配置文件按里面的指令一步步把系统拉起来。关键点在于当设备检测到只插了充电器、没有按电源键时引导程序不会走正常启动流程而是加载一个特殊的充电模式。这个充电模式下系统只会显示一个电池图标和充电百分比不会启动完整的安卓系统。这个行为的控制逻辑一部分在引导程序里一部分在boot.img的ramdisk里。2.2 充电模式与正常启动的分叉点具体来说引导程序会根据PMIC电源管理芯片上报的启动原因来决定走哪条路。如果启动原因是“电源键按下”就走正常启动如果启动原因是“插入充电器”就走充电模式。充电模式下引导程序会加载boot.img但传给内核的启动参数里会带一个类似androidboot.modecharger的标记init看到这个标记后就不启动完整系统只跑充电相关的服务。所以我们的思路就是让init忽略这个charger标记无论什么启动原因都走正常启动流程。这个改动落在init.rc或者init.rc引用的其他.rc文件里。改完之后重新打包boot.img刷回设备通电就会直接开机。2.3 为什么不动system分区有人会想能不能在系统层面改比如装个应用监听电源事件然后自动解锁屏幕这条路走不通因为充电模式下安卓系统根本没起来应用层的东西完全没机会执行。也有人想改引导程序但引导程序通常是签名校验的改了刷不进去而且不同芯片的引导程序差异极大风险太高。相比之下boot.img在很多旧设备上是不校验签名或者可以解锁后刷入的改动成本最低可控性最好。注意部分设备有AVBAndroid Verified Boot校验改了boot.img会导致校验失败无法开机。安卓6.0时代的设备大部分还没有强制AVB但刷之前一定要确认自己的设备是否已解锁bootloader以及是否有dm-verity校验。3. 动手前的准备工作与工具清单3.1 硬件与软件环境准备工欲善其事先把家伙什备齐。你需要的东西不多但每一样都不能少一台电脑Windows、Linux、macOS都行我习惯用Linux因为解包打包工具在Linux上最顺手。Windows的话需要装好驱动。设备对应的fastboot驱动Windows上尤其重要驱动没装好fastboot会一直显示waiting for device。platform-tools工具包里面包含adb和fastboot版本越新越好但旧设备用旧版本反而更稳建议备一份2018年左右的版本。boot.img解包打包工具Linux下推荐mkbootimg/unpackbootimg这套或者用Android Image Kitchen跨平台图形化新手友好。设备原厂固件包里面能找到原版的boot.img这是你的“后悔药”改坏了可以刷回去。一台能正常开机的同型号设备用来提取原版boot.img如果固件包里没有的话。3.2 确认设备已解锁bootloader这一步是前提没解锁的话后面全白搭。解锁方法因厂商而异一般是进开发者选项打开“OEM解锁”和“USB调试”然后adb reboot bootloader进fastboot模式执行fastboot oem unlock或fastboot flashing unlock。解锁会清空数据提前备份。解锁成功的标志是fastboot界面会显示Device unlocked之类的字样。如果显示Device locked后面的刷入操作会被拒绝。3.3 提取原版boot.img的两种途径途径一从固件包里找。大部分厂商的固件包.zip或.tgz格式解压后里面有个boot.img直接拿来用。途径二从设备里提取。设备能正常开机的话adb shell进去dd if/dev/block/bootdevice/by-name/boot of/sdcard/boot.img然后adb pull出来。注意分区名可能是boot也可能是boot_a/boot_bA/B分区设备用ls -l /dev/block/bootdevice/by-name/看一下。实操心得提取出来的boot.img一定要先校验一下完整性md5sum记下来改完之后对比。我踩过一次坑提取过程中断电导致镜像损坏刷进去直接变砖还好有固件包救回来。4. 解包boot.img并定位充电模式配置4.1 用Android Image Kitchen解包以Android Image Kitchen为例把boot.img拖到unpackimg.batWindows或执行./unpackimg.sh boot.imgLinux。工具会自动把镜像拆成kernel、ramdisk、dtb等部分放在split_img目录下ramdisk会被解压到ramdisk目录。解包成功的标志是看到ramdisk目录里有init、init.rc、sbin、etc等文件。如果解包报错可能是镜像格式不标准试试用unpackbootimg手动解。4.2 在init.rc里找到charger相关逻辑进到ramdisk目录用grep -r charger .搜一下通常会命中几个地方init.rc里的on charger段落init.rc里的class_start charger指令sbin/charger可执行文件这个是充电模式的二进制程序etc/init/目录下可能有独立的.rc文件安卓6.0的init.rc里典型的结构是这样的on charger class_start charger这行的意思是当启动原因是charger时启动charger这个class的服务。而正常启动走的是on boot或on init段落。我们要做的就是让on charger段落不执行或者让它执行正常启动的流程。4.3 修改策略的三种选择策略一直接注释掉on charger段落。最简单粗暴但可能导致充电模式下系统完全不响应插上充电器也没反应得按电源键才开机。这个策略适合确定不需要充电模式的场景。策略二把on charger段落改成和on boot一样的内容。这样无论什么启动原因都走正常启动充电模式被彻底绕过。这个策略最符合“通电自启”的需求。策略三在on charger里加一个延时然后触发正常启动。比如延时几秒后执行setprop触发启动。这个策略比较绕不推荐。我一般用策略二直接把on charger段落替换成正常启动的指令。具体改法看下一节。5. 修改init.rc实现通电自启的完整操作5.1 定位并备份原始配置先cp init.rc init.rc.bak备份一份改坏了能还原。然后打开init.rc找到on charger段落。安卓6.0的init.rc通常长这样on charger class_start charger on boot ... class_start core class_start mainon boot段落里有一堆class_start把核心服务、主服务都拉起来。我们要做的就是把on charger段落改成和on boot一样或者干脆把on charger删掉让init找不到charger的处理逻辑默认走正常启动。5.2 具体修改内容与原理说明我的改法是把on charger段落改成on charger setprop ro.boot.mode normal class_start core class_start main class_start late_startsetprop ro.boot.mode normal这行是关键它把启动模式属性强制设为normal后续init判断启动模式时会认为这是正常启动。然后手动把几个主要的service class拉起来效果等同于正常开机。改完之后保存注意文件权限要保持和原来一致一般是750或644属主root:root。权限不对会导致init拒绝加载。5.3 重新打包boot.img回到Android Image Kitchen目录执行repackimg.bat或./repackimg.sh。工具会把修改后的ramdisk重新打包成boot.img输出文件通常叫image-new.img。把它重命名为boot.img备用。打包完成后用md5sum对比一下新镜像和原镜像确认确实变了。再用unpackimg解一遍新镜像确认init.rc的修改还在里面这一步是防止打包工具出bug。注意有些设备的boot.img里还有dtb设备树和ramdisk的压缩格式问题重新打包时如果压缩格式和原来不一致可能导致内核无法解压ramdisk。Android Image Kitchen一般会自动识别但保险起见打包前记下原镜像的压缩格式gzip/lz4/xz打包后用file命令确认新镜像格式一致。6. 刷入boot.img并验证通电自启效果6.1 fastboot刷入操作步骤设备进fastboot模式adb reboot bootloader或者关机后按住特定组合键通常是音量下电源。连上电脑fastboot devices确认设备被识别。刷入命令fastboot flash boot boot.img如果是A/B分区设备要指定槽位fastboot flash boot_a boot.img刷完执行fastboot reboot重启。第一次重启可能会比较慢因为init要重新走一遍正常启动流程耐心等。6.2 验证是否真的通电自启验证方法很简单设备完全关机拔掉电源等10秒然后插上电源。如果设备直接亮屏进入系统说明改成功了。如果还是停在充电图标说明改动没生效需要排查。排查方向确认刷入的boot.img是修改过的fastboot getvar all看boot分区信息、确认init.rc修改正确、确认设备没有AVB校验拦截。有些设备刷完boot.img后会被dm-verity检测到篡改导致卡在开机logo这时候需要fastboot disable-verity或者刷入vbmeta关闭校验。6.3 常见刷入失败与应对现象可能原因解决办法fastboot devices无输出驱动没装好或线材问题换USB口、换线、重装驱动fastboot flash报错FAILED (remote: not allowed)bootloader未解锁先解锁bootloader刷入后卡开机logoAVB/dm-verity校验失败关闭校验或刷回原版刷入后无限重启init.rc改错导致init崩溃进recovery刷回原版boot.img通电仍不进系统改动未生效或引导程序拦截检查init.rc、确认引导程序逻辑实操心得刷boot.img之前一定一定先用fastboot boot boot.img临时启动测试确认能正常进系统再fastboot flash永久刷入。fastboot boot不会写入分区重启就恢复原样是零风险的测试方法。我早期不知道这招直接flash改错一次就得拆机短接进9008模式救砖血的教训。7. 不同芯片平台的差异与适配要点7.1 高通平台的特殊处理高通设备的引导程序对启动原因判断比较严格有些机型即使改了init.rc引导程序在检测到charger启动时还是会传androidboot.modecharger参数。这种情况下除了改init.rc还需要在内核命令行里加androidboot.modenormal覆盖。内核命令行在boot.img的cmdline字段里Android Image Kitchen解包后能看到split_img/boot.img-cmdline文件直接编辑它。另外高通有个qcom,charger相关的PMIC配置部分机型在引导程序层面就拦截了这种只能通过修改引导程序实现但引导程序签名校验严格基本无解。买设备前最好确认一下社区有没有人成功改过同型号。7.2 联发科平台的注意事项联发科设备的boot.img结构和高通略有不同ramdisk里可能有init.mtXXXX.rc这样的平台专属配置文件。充电逻辑可能写在这些文件里而不是主init.rc。用grep -r charger .全目录搜一遍别漏了。联发科还有个preloader阶段部分机型在preloader里就决定了启动模式这种情况改boot.img无效。判断方法如果改了init.rc刷入后通电仍然停在充电图标且fastboot boot临时启动能进系统说明拦截在preloader或引导程序boot.img层面解决不了。7.3 瑞芯微与全志平台瑞芯微RK和全志Allwinner的工控板、广告机用得很多这类设备的引导程序通常是U-Boot启动逻辑和手机不一样。RK平台的boot.img可能是resource.imgkernel.img的组合充电模式逻辑可能在U-Boot的环境变量里。这类设备改通电自启有时候直接在U-Boot里改bootcmd更简单不一定要动boot.img。全志平台类似boot.img可能是boot.fex格式需要用全志专用的打包工具。这类设备的社区资料相对少动手前多搜搜同型号的帖子。8. 实操避坑与长期运维建议8.1 改机过程中的高频坑点第一个坑文件权限。init.rc改完保存后权限变成644或者被改成当前用户init加载时会报权限错误。刷入前用chmod 750 init.rc chown root:root init.rc修正。第二个坑换行符。Windows下编辑init.rc会引入CRLF换行符init解析时可能出错。用dos2unix转一下或者直接在Linux下编辑。第三个坑压缩格式。前面提过ramdisk的压缩格式必须和原来一致。Android Image Kitchen默认用gzip但有些设备用lz4打包后内核解压失败。打包前看split_img/boot.img-ramdiskcomp文件里写的什么格式打包时指定。第四个坑A/B分区。A/B分区设备刷了boot_a但设备从boot_b启动改动不生效。用fastboot getvar current-slot确认当前槽位刷对应的分区。8.2 批量部署时的效率技巧如果手里有一批同型号设备要改没必要一台台解包打包。改好一个boot.img批量刷入就行。写个脚本#!/bin/bash for i in $(seq 1 20); do echo 请连接第 $i 台设备按回车继续... read fastboot flash boot boot.img fastboot reboot sleep 30 done每台设备刷完等30秒重启人工换线。20台设备半小时搞定。8.3 长期运行的稳定性考量通电自启改完之后设备长期插电运行电池是个隐患。老化的电池鼓包、发热严重时可能起火。建议把电池拆掉直接用电源适配器供电。有些设备拆电池后会检测不到电池而拒绝开机这种情况需要在电池接口上并一个电阻模拟电池存在具体阻值因机型而异一般10kΩ左右能骗过检测。另外长期运行建议关掉不必要的动画、降低屏幕亮度、设置定时重启减少系统卡顿。安卓6.0本身比较老内存管理不如新版本跑久了容易卡定时重启能缓解。最后分享一个小技巧改好的boot.img和对应的init.rc修改记录一定要存档标注设备型号、安卓版本、修改日期。过半年再遇到同型号设备直接拿来用不用重新折腾。我建了个目录专门放这些命名规则是型号_版本_修改内容_日期找起来很快。
返回列表