Android开机脚本怎么写?这份保姆级指南请收好
2026/4/13 18:19:32 网站建设 项目流程

Android开机脚本怎么写?这份保姆级指南请收好

Android系统启动过程中执行自定义脚本,是嵌入式开发、设备定制、自动化测试等场景的刚需能力。但很多开发者第一次尝试时会遇到脚本不执行、权限拒绝、SELinux拦截、init.rc语法报错等问题,反复调试耗时又挫败。

本文不是照搬文档的理论复述,而是基于真实MTK平台实测经验整理的一份可直接上手、每步都验证过、避开90%常见坑的实践指南。全文不讲抽象概念,只说“你该敲什么命令”“文件放哪”“为什么这么写”“出错了怎么看”,尤其适合刚接触Android底层定制的工程师和测试同学。

无论你用的是Android 8.0、10、11还是12,只要系统启用了SELinux(默认开启),本文流程均适用。文中所有代码、路径、配置均已脱敏并适配主流厂商方案,可直接复制粘贴使用。


1. 明确目标:我们要实现什么

在Android设备完成系统启动、进入Home界面之前,自动运行一段Shell脚本。这个脚本可以:

  • 设置调试属性(如setprop test.prop 111
  • 拷贝预置配置文件到data分区
  • 启动一个后台守护进程(如日志采集服务)
  • 执行硬件初始化命令(如点亮LED、读取传感器)
  • 记录启动时间戳用于性能分析

注意:这不是App层的“开机自启”,而是系统init阶段的原生服务启动,无需用户授权,不依赖Activity或Service组件,更稳定、更底层、更早执行。


2. 准备工作:确认环境与权限

动手前,请确保你已具备以下条件:

  • 一台已解锁Bootloader的Android设备(如MTK公版板、高通开发板)
  • 已获取root权限(adb root可成功执行)
  • 设备已启用adb remount(即system分区可写)
  • 编译环境已配置好(需修改init.rc和SELinux策略,必须能编译刷机或使用adb push临时验证)

如果你只是想快速验证脚本能否跑通(比如做功能测试),推荐先走临时验证路径——跳过SELinux和init.rc修改,用init.d兼容方式或rc.local模拟启动,确认逻辑无误后再进正式流程。


3. 写一个真正能跑起来的Shell脚本

3.1 脚本内容:极简但健壮

新建文件init.test.sh,内容如下(注意:全部手动输入,不要复制隐藏字符):

#!/system/bin/sh # 1. 确保环境干净 export PATH=/system/bin:/system/xbin:/vendor/bin:/sbin # 2. 记录启动时间(便于后续排查) log -p i -t "INIT_TEST" "Script started at $(date)" # 3. 设置一个测试属性(最安全的验证方式) setprop test.prop "booted_$(date +%s)" # 4. 可选:创建一个标记文件(仅用于临时验证,生产环境慎用) # touch /data/local/tmp/init_test_ran # 5. 输出日志供adb logcat查看 log -p i -t "INIT_TEST" "Property set: $(getprop test.prop)"

3.2 关键细节说明

  • Shebang必须是/system/bin/sh:Android的shell路径与Linux不同,写成/bin/sh/system/xbin/sh在部分版本会失败;
  • 显式设置PATH:避免因环境变量缺失导致loggetprop等命令找不到;
  • log命令而非echoecho输出到stdout,在init阶段不可见;log写入kernel log buffer,可通过adb logcat -b main -b system查看;
  • 避免创建文件/写data分区:首次验证阶段,优先用setprop,规避权限和SELinux问题;
  • 务必先手动测试adb push init.test.sh /data/local/tmp/ && adb shell chmod 755 /data/local/tmp/init.test.sh && adb shell /data/local/tmp/init.test.sh,确认输出日志正常再进下一步。

4. 将脚本放入系统路径并设权

4.1 推送脚本到正确位置

Android要求开机脚本必须放在有执行权限的系统路径下。推荐路径:

  • /system/bin/(需remount system为read-write)
  • /vendor/bin/(更推荐,避免修改AOSP原生system分区)

执行命令:

adb root adb remount adb push init.test.sh /vendor/bin/ adb shell chmod 755 /vendor/bin/init.test.sh adb shell ls -l /vendor/bin/init.test.sh

预期输出应显示权限为-rwxr-xr-x,且属主为root:root

4.2 验证脚本可执行

adb shell /vendor/bin/init.test.sh adb logcat -b main -b system | grep "INIT_TEST"

若看到日志中出现"Script started at...""Property set:...",说明脚本本身完全OK。


5. 修改init.rc:注册为系统服务

5.1 不要直接改/init.rc

主流芯片平台(MTK/Qualcomm/Exynos)都提供了客户扩展入口:

  • MTK:/vendor/etc/init/hw/init.mtk.rcdevice/mediatek/sepolicy/basic/non_plat/init.mtk.rc
  • Qualcomm:/vendor/etc/init/vendor.qti.hardware.rc
  • 通用方案:/vendor/etc/init/<your_name>.rc

我们新建一个独立rc文件:/vendor/etc/init/init.test.rc,内容如下:

service test_service /vendor/bin/init.test.sh class main user root group root oneshot seclabel u:object_r:test_service_exec:s0

oneshot表示执行完即退出,适合初始化类脚本;
❌ 不要用restartdisabled,除非你真需要常驻;
seclabel行必须存在,即使SELinux未启用,否则init解析失败。

5.2 推送并生效

adb push init.test.rc /vendor/etc/init/ adb shell ls -l /vendor/etc/init/init.test.rc

重启设备后,该rc文件会被init自动加载。


6. SELinux策略:绕不开但可简化处理

SELinux是Android 8.0+强制启用的安全机制。跳过它,脚本一定失败。但不必从零写te文件——我们用最小化策略,直击核心。

6.1 创建te策略文件test_service.te

# test_service.te type test_service, domain; type test_service_exec, exec_type, file_type; # 允许init域域执行该脚本 init_daemon_domain(test_service) # 允许test_service域读取、执行自身文件 allow test_service test_service_exec:file { read execute open getattr };

6.2 添加文件上下文映射

编辑device/mediatek/sepolicy/basic/non_plat/file_contexts(MTK路径,其他平台类似),追加一行:

/vendor/bin/init\.test\.sh u:object_r:test_service_exec:s0

注意:.sh中的点号需转义为\.,否则匹配失败。

6.3 编译并刷入(或临时关闭SELinux验证)

  • 推荐方式(长期):将.tefile_contexts放入sepolicy目录,重新编译system.img刷机;
  • 快速验证(测试用):重启进recovery,执行adb shell setenforce 0临时关闭SELinux,再重启看脚本是否执行。若此时OK,说明纯SELinux问题,策略即可锁定。

查看SELinux拦截日志:adb logcat | grep avc,典型报错如avc: denied { execute } for path="/vendor/bin/init.test.sh",即对应上述策略缺失。


7. 验证与排错:三步定位问题

脚本没执行?别猜,按顺序查:

7.1 第一步:确认init.rc是否加载

adb shell getenforce # 应为 Enforcing 或 Permissive adb shell ls /vendor/etc/init/ | grep test adb shell cat /proc/1/cmdline # 看init进程是否带-vendor参数(影响rc加载路径)

7.2 第二步:检查init日志

adb logcat -b events | grep -i "test_service\|init\.test" # 正常应看到:init: starting service 'test_service'... # 若无此行,说明rc未被解析或语法错误

7.3 第三步:抓取完整启动日志

adb logcat -b all > boot_log.txt # 搜索关键词: # "test_service" → 是否启动 # "avc:" → SELinux拦截 # "Permission denied" → 权限或路径错误 # "No such file" → 脚本路径不对或未push

常见问题速查表:

现象最可能原因解决方案
logcat完全看不到任何INIT_TEST日志脚本根本没执行检查init.test.rc路径、权限、seclabel拼写
avc: denied { execute }SELinux策略缺失补全allow规则,确认file_contexts路径匹配
Permission denied脚本无x权限或路径不在白名单chmod 755+ 检查是否推送到/vendor/bin/等允许路径
sh: log: not foundPATH未设置或log命令不存在改用/system/bin/log绝对路径,或换echo > /dev/kmsg

8. 进阶建议:让脚本更可靠、更实用

8.1 加入防重入机制

多个rc服务可能并发启动,用属性锁避免重复执行:

if [ "$(getprop test.prop)" = "booted" ]; then log -p i -t "INIT_TEST" "Already ran, skip." exit 0 fi setprop test.prop "booted"

8.2 支持参数化启动

init.test.rc中传参:

service test_service /vendor/bin/init.test.sh arg1 arg2

脚本内用$1$2获取,便于同一脚本复用不同场景。

8.3 日志持久化(可选)

若需长期留存启动日志,可追加:

log -p i -t "INIT_TEST" "Saving log to /data/misc/test_boot.log" logcat -b main -b system -v time -d | grep "INIT_TEST" >> /data/misc/test_boot.log

需确保/data/misc/有写权限(默认有)。


9. 总结:一份能落地的开机脚本清单

回顾整个流程,你只需完成这5件事,就能让脚本稳稳跑在开机第一秒:

  1. 写一个以/system/bin/sh开头、用log打印日志的Shell脚本;
  2. adb push/vendor/bin/chmod 755
  3. 新建/vendor/etc/init/init.test.rc,声明service并指定seclabel
  4. file_contexts中添加脚本路径的SELinux上下文映射;
  5. 编译刷机(或临时setenforce 0验证),adb logcat | grep INIT_TEST看结果。

没有玄学,没有黑盒。每一步都有明确命令、明确路径、明确验证方式。你不需要成为SELinux专家,也不必啃完整本Android启动文档——按这份指南操作,今天下午就能看到test.prop被成功设置。

真正的工程能力,不在于懂多少概念,而在于能不能把一件事从0到1闭环跑通。开机脚本,就是这样一个小而完整的闭环。

--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

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

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

立即咨询