news 2026/6/26 15:17:40

测试开机启动脚本使用全解,Android开发者少走弯路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
测试开机启动脚本使用全解,Android开发者少走弯路

测试开机启动脚本使用全解,Android开发者少走弯路

在Android系统开发中,让自定义脚本随系统启动自动运行,是很多功能实现的基础需求——比如设备初始化、硬件检测、日志收集、服务预热等。但实际操作中,不少开发者卡在“脚本写好了却没执行”“属性设了但读不到”“init.rc加了却报selinux拒绝”这类问题上,反复调试耗时又挫败。

本文不是照搬文档的理论复述,而是基于真实MTK平台实测经验整理的一套可直接落地、避坑优先、适配Android 8.0+的开机启动脚本全流程方案。所有步骤均经过真机验证(AOSP 8.1 + MTK公版),不讲抽象概念,只说“你该怎么做、为什么这么写、哪里最容易错”。

全文聚焦一个目标:让你写的脚本,在系统完成init阶段后,稳稳跑起来,并能被后续进程可靠读取状态

1. 明确前提:你的环境是否满足基本条件

在动手前,请先确认以下三点。跳过检查,90%的问题会出现在这里。

  • 系统已root或具备system分区写入权限
    开机脚本必须存放在/system/bin//vendor/bin/下,且需chmod 755。若用adb push失败,说明未获取system写权限(adb remount失败即为典型表现)。

  • SELinux处于enforcing模式(非permissive)
    Android 8.0起默认强制启用SELinux。即使临时setenforce 0能跑通,也不能代表最终方案可用。本文所有配置均按enforcing模式设计。

  • 你使用的不是user版本固件
    user版本会禁用adb root和system写入,调试阶段请务必使用userdebug版本。

提示:不要在未确认上述条件时就开始写te文件或改init.rc——很多“权限错误”本质是路径没写对,或脚本根本没成功push进去。

2. 脚本编写:三行代码定生死

脚本本身看似简单,但Android对shell解释器路径、执行上下文、输出重定向极为敏感。以下是最小可行模板:

2.1 标准脚本结构(init.test.sh)

#!/system/bin/sh # 必须以空行开头,避免BOM或不可见字符干扰解析 # 所有路径使用绝对路径,禁止相对路径或cd切换 # 第一步:快速标记脚本已触发(最轻量验证方式) setprop sys.boot.test_script 1 # 第二步:记录时间戳(便于后续排查是否真正执行) log -t BOOT_TEST "Script started at $(date)" # 第三步:可选——创建一个临时标记文件(仅用于调试,生产环境建议用属性替代) touch /data/misc/test_boot_done chmod 644 /data/misc/test_boot_done

2.2 关键细节说明(新手必看)

  • #!/system/bin/sh不可替换为/bin/sh/system/xbin/sh
    Android 8.0+的init进程只认/system/bin/sh为合法shell路径。写错将导致service状态始终为STOPPED,且无任何日志提示。

  • 禁止使用echo > fileprintf/system/vendor写文件
    这些分区在启动早期是只读挂载(ro),强行写入会静默失败。如需落盘记录,请统一写入/data/dev/log(通过log命令)。

  • 不要依赖sleep或复杂逻辑
    init阶段资源紧张,长时间阻塞可能触发watchdog重启。如需延时,请用start service_name配合on property:触发,而非脚本内sleep。

  • 调试技巧:先手动执行再进init
    推送后立即执行:

    adb push init.test.sh /system/bin/ adb shell chmod 755 /system/bin/init.test.sh adb shell /system/bin/init.test.sh adb shell getprop sys.boot.test_script # 应返回1

    若这步失败,init.rc环节必然失败——请先解决此问题。

3. SELinux策略配置:te文件与file_contexts双到位

Android 8.0后,SELinux策略拆分为platform和non-platform两层。MTK等芯片方案通常要求将自定义策略放入non_plat目录,否则编译会报错或策略不生效。

3.1 创建te策略文件(test_service.te)

将以下内容保存为device/mediatek/sepolicy/basic/non_plat/test_service.te

# 定义域类型 type test_service, domain; type test_service_exec, exec_type, vendor_file_type, file_type; # 允许init域启动该服务 init_daemon_domain(test_service) # 允许test_service域读取/执行自身脚本 allow test_service test_service_exec:file { read open getattr execute }; # 允许test_service设置系统属性(关键!) allow test_service system_file:file { read }; allow test_service system_prop:property_service { set }; # 允许写入/data(如需创建标记文件) allow test_service data_file:dir { add_name write search }; allow test_service data_file:file { create read write getattr };

说明:相比参考博文中的简化版,本策略明确放行property_service { set }data_file操作,覆盖实际调试中最常遇到的两个拒绝项(avc denied { set } property_service 和 avc denied { add_name } dir)。

3.2 配置file_contexts映射

device/mediatek/sepolicy/basic/non_plat/file_contexts末尾添加一行:

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

注意:

  • 正则转义:.sh中的点号必须写成\.,否则匹配失败;
  • 路径必须与实际存放位置完全一致(本文示例为/system/bin/,若放/vendor/bin/则需同步修改此处及init.rc路径);
  • 修改后必须重新编译sepolicy(m sepolicy),否则烧录后策略不生效。

4. init.rc集成:service定义与启动时机选择

Android 8.0起,init.rc被拆分为多个片段,厂商通常提供init.<chip>.rc供客户扩展。强烈不建议直接修改system/core/rootdir/init.rc,易被上游更新覆盖且违反模块化原则。

4.1 推荐写法:在vendor或chip专属rc中添加

以MTK平台为例,在device/mediatek/common/init/init.mt6765.rc(路径依芯片而异)中追加:

# 开机启动测试脚本 service test_service /system/bin/init.test.sh class main user root group root oneshot seclabel u:object_r:test_service_exec:s0 disabled # 触发时机:确保zygote已启动、property服务就绪 on property:sys.boot_completed=1 start test_service

4.2 关键参数解读

参数作用为什么这样设
oneshot执行完即退出,不驻留避免被init误判为崩溃服务反复重启
disabled默认不自动启动防止与其他service冲突,由property显式触发更可控
on property:sys.boot_completed=1等待系统完全就绪后启动sys.boot_completed是Android标准boot完成标志,比early-initlate-init更可靠

进阶提示:若需更早启动(如硬件初始化),可监听init.svc.zygote=running,但需确保te策略已允许访问zygote相关属性。

5. 验证与排错:四步定位问题根源

写完所有配置,编译烧录后,如何快速判断哪一环出错?按以下顺序逐级验证:

5.1 检查service是否被init识别

adb shell getenforce # 确认返回Enforcing adb shell ls -Z /system/bin/init.test.sh # 查看SELinux上下文是否为test_service_exec adb shell ls -l /system/bin/init.test.sh # 确认权限为-rwxr-xr-x adb shell getprop | grep boot_test # 若无输出,说明脚本未执行

5.2 查看init日志(最有效手段)

adb logcat -b events | grep -i "test_service\|avc" # 或过滤init专属日志 adb logcat -b main | grep -i "init.test"

常见错误及对应解法:

日志关键词原因解决方案
avc: denied { execute } for ... test_service_execfile_contexts未生效或路径不匹配检查ls -Z输出,确认路径正则和实际一致
init: cannot find '/system/bin/init.test.sh'脚本未push成功或路径写错adb shell ls /system/bin/init.test.sh确认存在
init: starting service 'test_service'...但无后续日志脚本语法错误或解释器路径错误手动执行脚本,观察报错
init: Service 'test_service' is being restarted...oneshot未设或脚本退出码非0确保脚本末尾exit 0,或移除oneshot改用restart

5.3 使用logcat验证执行流

在脚本中加入多点日志:

log -t BOOT_TEST "Step 1: prop set" setprop sys.boot.test_script 1 log -t BOOT_TEST "Step 2: log written" log -t BOOT_TEST "Step 3: end of script"

然后实时抓取:

adb logcat -b main -v time | grep BOOT_TEST

若只看到Step 1,说明setprop后脚本异常退出;若全无输出,说明service根本未启动。

6. 生产环境加固建议:从调试走向稳定

完成基础功能后,以下三点可显著提升脚本在量产设备上的鲁棒性:

6.1 属性命名规范

避免使用test.*等易冲突的命名空间。推荐格式:

  • vendor.<company>.<feature>.status(如vendor.myco.hwinit.status
  • persist.<company>.<feature>(需在te中额外放行persist_file

6.2 错误隔离机制

在脚本开头加入保护:

#!/system/bin/sh # 防止重复执行 if getprop vendor.myco.hwinit.status | grep -q "done"; then log -t BOOT_TEST "Already executed, skip" exit 0 fi

6.3 启动超时控制

避免因某一步卡死导致整机启动延迟:

# 设置最大执行时间5秒 timeout 5s sh -c ' setprop vendor.myco.hwinit.status "running" # 实际初始化逻辑 setprop vendor.myco.hwinit.status "done" '

7. 总结:一条清晰的落地路径

回顾整个流程,真正让开发者少走弯路的核心,不是记住所有命令,而是建立正确的验证闭环:

  1. 先手动验证脚本可行性→ 排除语法、路径、权限问题
  2. 再验证SELinux上下文与策略ls -Z+logcat -b events双确认
  3. 最后验证init启动逻辑getprop+logcat -b main交叉印证
  4. 上线前做降级兼容→ 添加if [ -f /system/bin/init.test.sh ]; then ... fi防止ota后脚本丢失

你不需要成为SELinux专家,也不必深究init源码。只要守住“手动能跑 → 策略能放行 → init能触发 → 日志可追踪”这四条线,开机脚本就能稳稳落地。

现在,打开你的终端,从adb push第一行开始吧。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/25 13:12:56

零基础玩转AutoGen Studio:Qwen3-4B大模型低代码开发指南

零基础玩转AutoGen Studio&#xff1a;Qwen3-4B大模型低代码开发指南 你是否想过&#xff0c;不用写一行Python代码&#xff0c;就能让多个AI智能体协作完成复杂任务&#xff1f;比如让一个AI负责分析用户需求&#xff0c;另一个AI调用工具生成图表&#xff0c;第三个AI整合结…

作者头像 李华
网站建设 2026/6/25 17:03:28

开箱即用!Cute_Animal_Qwen镜像让AI绘画变得如此简单

开箱即用&#xff01;Cute_Animal_Qwen镜像让AI绘画变得如此简单 你是否曾想过&#xff0c;只需输入一句话&#xff0c;就能生成一张专为孩子设计的可爱动物图片&#xff1f;不需要复杂的绘图技巧&#xff0c;也不需要长时间学习AI模型参数——现在&#xff0c;这一切都可以通…

作者头像 李华
网站建设 2026/6/22 1:03:50

SenseVoice跨平台部署全攻略:多语言集成与性能调优实践

SenseVoice跨平台部署全攻略&#xff1a;多语言集成与性能调优实践 【免费下载链接】SenseVoice Multilingual Voice Understanding Model 项目地址: https://gitcode.com/gh_mirrors/se/SenseVoice 还在为语音AI模型在不同平台上的部署挑战而烦恼&#xff1f;SenseVoic…

作者头像 李华
网站建设 2026/6/22 1:32:18

5分钟部署Qwen3-4B-Instruct-2507,阿里开源大模型一键启动文本生成

5分钟部署Qwen3-4B-Instruct-2507&#xff0c;阿里开源大模型一键启动文本生成 1. 引言&#xff1a;为什么你该关注这个40亿参数的轻量级大模型&#xff1f; 如果你正在寻找一个既能跑在消费级显卡上&#xff0c;又能处理复杂任务、理解超长上下文的文本生成模型&#xff0c;…

作者头像 李华
网站建设 2026/6/26 3:01:40

ManiSkill机器人仿真平台:从零构建高性能机器人学习环境

ManiSkill机器人仿真平台&#xff1a;从零构建高性能机器人学习环境 【免费下载链接】ManiSkill 项目地址: https://gitcode.com/GitHub_Trending/ma/ManiSkill ManiSkill是一个功能强大的开源机器人仿真平台&#xff0c;为研究人员和开发者提供了构建、测试和验证机器…

作者头像 李华
网站建设 2026/6/21 22:31:21

5分钟快速上手:如何在Windows上免费实现全自动文件备份

5分钟快速上手&#xff1a;如何在Windows上免费实现全自动文件备份 【免费下载链接】MissionControl Use controllers from other consoles natively on your Nintendo Switch via Bluetooth. No dongles or other external hardware neccessary. 项目地址: https://gitcode.…

作者头像 李华