如何确保脚本仅在设备开机时运行一次?
嘿,我来帮你搞定这个「只在手机开机时跑一次脚本」的问题!先梳理下你之前踩的坑,再给你几个靠谱的解决方案:
先分析你遇到的问题原因
init.qcom.post_boot.sh/init.sec.boot.sh无效:这俩是高通/三星特定机型的厂商脚本,你的设备可能不匹配,或者有SELinux权限限制导致没执行debuggerd重复执行:没错,这个进程是调试相关的,每次启动都会触发关联脚本,本来就不是用来做单次开机启动的mkshrc的问题:它是shell的初始化配置文件,不管是开机时系统自动启动的shell,还是你手动通过adb shell打开的交互shell,都会加载它——这就是为啥每次连adb都会跑一遍的原因
最可靠的解决方案:用Android原生init机制
Android的开机流程由init进程主导,这是最稳定的单次开机执行途径,有两种方式:
方法1:添加自定义init服务
- 把你的脚本放到
/system/bin(或者/vendor/bin),给它加执行权限:chmod 755 /system/bin/your_boot_script.sh - 编辑设备的init配置文件(比如通用的
init.rc,或者厂商特定的init.qcom.rc/init.sec.rc),添加一个oneshot服务:service my_boot_script /system/bin/your_boot_script.sh class main user root group root oneshot seclabel u:r:init:s0- 重点是
oneshot:告诉init进程这个服务只运行一次,不会重启 class main:让它和系统核心服务同步启动- 如果SELinux开启,
seclabel要对应正确的上下文,不然会被权限拦截
- 重点是
- 重启设备后,这个脚本就会在开机时仅执行一次,完全不会被adb shell触发
方法2:用Magisk的service.d(适合已root设备)
如果你的设备已经root,用Magisk会更简单:
- 写一个带标记的脚本,避免重复执行:
#!/system/bin/sh MARKER="/data/.boot_script_done" # 如果标记文件存在,直接退出 [ -f "$MARKER" ] && exit 0 # 这里放你的核心逻辑 echo "Executing boot script once..." # 比如:am start -n com.example.myapp/.MainActivity # 创建标记文件,防止下次开机重复执行 touch "$MARKER" - 把这个脚本放到
/data/adb/service.d/目录,给它加执行权限 - Magisk会在开机完成后自动执行这个目录下的脚本,而且只会跑一次
临时 workaround:修改mkshrc区分场景
如果你暂时不想动init配置,可以修改/system/etc/mkshrc,通过环境变量判断是不是adb shell:
# 在mkshrc末尾添加这段判断 if [ -z "$ADB_SHELL" ] && [ -z "$SSH_TTY" ]; then # 只有非adb/ssh的系统shell(也就是开机时的shell)才会执行 echo "Running boot-only logic..." # 这里放你的脚本内容 fi
原理是:adb shell启动时会自动设置ADB_SHELL环境变量,而开机时的系统shell没有这个变量,这样就能精准区分开,避免每次连adb都执行脚本
内容的提问来源于stack exchange,提问作者Kevin




