news 2026/6/10 15:19:48

手把手教你写Android开机启动shell脚本(附测试)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手把手教你写Android开机启动shell脚本(附测试)

手把手教你写Android开机启动shell脚本(附测试)

1. 前言:为什么需要开机启动脚本?

在做Android系统级开发或定制时,经常会遇到这样一个需求:设备一开机,就自动执行某个任务。比如:

  • 自动开启某个后台服务
  • 设置系统属性用于后续流程判断
  • 挂载特殊分区或初始化硬件
  • 清理缓存、备份日志等维护操作

这些任务如果靠应用层去监听BOOT_COMPLETED广播来做,不仅延迟高,还可能因权限问题失败。而通过init 进程启动的 shell 脚本,可以在系统早期阶段运行,权限更高、时机更早。

本文将带你从零开始,完整实现一个 Android 开机启动 shell 脚本,并提供实际测试方法。内容基于 Android 8.0 环境验证通过,适用于大多数 AOSP 或 MTK/高通平台的定制系统开发。

你不需要是 SELinux 专家,也不用对 init.rc 了如指掌——只要跟着步骤走,就能成功跑通。


2. 实现原理简述

Android 的启动流程中,init进程是第一个用户空间进程(PID=1),它会解析/init.rc及其包含的.rc文件,根据配置启动各种服务和执行命令。

我们可以通过以下方式让一个 shell 脚本在开机时自动运行:

  1. 编写一个可执行的 shell 脚本
  2. 将脚本放入系统镜像的指定路径(如/system/bin/
  3. .rc文件中定义一个service来调用该脚本
  4. 配置 SELinux 策略允许该服务运行
  5. 编译刷机后验证效果

整个过程看似简单,但最容易卡住的地方就是SELinux 权限问题。别担心,我们会一步步解决。


3. 第一步:编写你的开机启动脚本

3.1 创建脚本文件

新建一个名为init.test.sh的文件,内容如下:

#!/system/bin/sh # 设置一个系统属性,用于验证脚本是否执行 setprop sys.boot.test 1 # 输出日志到 dmesg,方便调试 log -t "InitTest" -p i "开机启动脚本已执行" # 可选:创建一个标记文件(需注意目录权限) # touch /data/local/tmp/boot_script_ran

3.2 注意事项

  • 解释器路径必须正确:Android 系统通常使用/system/bin/sh,不是 Linux 常见的/bin/sh
  • 不要写错 shebang 行#!/system/bin/sh前不能有空格或 BOM
  • 避免操作敏感目录:测试阶段建议只设置属性或打日志,避免因文件权限导致失败
  • 脚本要可执行:确保编译进系统时权限为755

你可以先手动 push 到手机试试看能否运行:

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 adb shell getprop sys.boot.test # 应该输出 1

如果这步都跑不通,说明脚本本身有问题,请先修复。


4. 第二步:为脚本添加 SELinux 策略

这是很多人踩坑最多的地方。即使关闭了 SELinux(enforcing=0),Android 仍然会检查类型标签(file_contexts)是否匹配,否则init不会启动服务。

4.1 新建 TE 策略文件

在你的设备目录下创建 SELinux 策略文件,例如 MTK 平台常见路径:

device/mediatek/sepolicy/basic/non_plat/test_service.te

内容如下:

# 定义服务类型 type test_service, coredomain; # 定义可执行文件类型 type test_service_exec, exec_type, file_type, vendor_file_type; # 允许 init 启动这个域的服务 init_daemon_domain(test_service) # 如果你想调试,可以临时设为宽容模式(不推荐长期使用) # permissive test_service;

4.2 添加 file_contexts 映射

编辑或创建:

device/mediatek/sepolicy/basic/non_plat/file_contexts

添加一行,告诉系统这个脚本文件应该属于什么安全上下文:

/(system\/vendor|vendor)/bin/init\.test\.sh u:object_r:test_service_exec:s0

注意:这里路径是/system/bin//vendor/bin/,取决于你把脚本放哪。正则表达式要用转义点号。

如果你把脚本放在/system/bin/init.test.sh,那最终打包时必须确保它在这个位置,并且上下文正确。


5. 第三步:在 .rc 文件中注册服务

不要直接修改/init.rc,而是找厂商提供的扩展.rc文件,比如:

  • init.mtk.rc
  • init.vendor.rc
  • 或者你自己加一个init.custom.rc

推荐做法是在init.${project}.rc中添加服务定义。

5.1 添加 service 定义

在合适的.rc文件中加入:

service test_service /system/bin/init.test.sh class main user root group root oneshot seclabel u:object_r:test_service_exec:s0
参数说明:
字段说明
class main属于主类服务,随 main class 启动
user/group root以 root 身份运行(谨慎使用)
oneshot只运行一次,适合脚本任务;如果不加,会不断重启
seclabel必须与 file_contexts 中定义的类型一致

5.2 替代方案:直接执行 command

如果你想更轻量,也可以不用 service,直接在.rc中写:

on property:sys.boot_completed=1 exec u:object_r:test_service_exec:s0 root root -- /system/bin/init.test.sh

这种方式更适合一次性命令,且能控制触发时机(比如等 boot_completed 再执行)。


6. 第四步:编译并刷入系统

6.1 放置脚本到源码目录

init.test.sh放入系统镜像中,例如:

system/bin/init.test.sh

并在Android.mkAndroid.bp中声明为可执行文件。

示例Android.mk

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := init.test.sh LOCAL_SRC_FILES := init.test.sh LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES) LOCAL_MODULE_TAGS := optional LOCAL_STRIP_MODULE := false include $(BUILD_PREBUILT)

或者Android.bp

prebuilt_executable { name: "init.test.sh", srcs: ["init.test.sh"], owner: "your_company", relative_install_path: "bin", mode: "0755", }

6.2 编译系统镜像

mka systemimage -j$(nproc)

烧写后重启设备。


7. 第五步:如何测试脚本是否生效?

7.1 方法一:检查系统属性

最简单的验证方式:

adb shell getprop sys.boot.test

如果返回1,说明脚本成功执行了。

7.2 方法二:查看内核日志

使用dmesg查看是否有我们的日志输出:

adb shell dmesg | grep InitTest

预期输出:

<info>[ 5.123456] InitTest: 开机启动脚本已执行

7.3 方法三:使用 logcat 查看日志

因为我们用了log -t命令,所以也能在 logcat 中看到:

adb logcat -s InitTest

输出类似:

I/InitTest( 1234): 开机启动脚本已执行

7.4 方法四:串口日志(高级调试)

如果有串口调试工具,可以在早期阶段看到init解析.rc和执行脚本的过程。当出现如下错误时,基本可以定位问题:

init: Unable to spawn service 'test_service'... Permission denied

这通常是 SELinux 上下文不匹配导致的。


8. 常见问题与解决方案

8.1 脚本没执行,没有任何反应

可能原因

  • .rc文件未被加载
  • 路径拼写错误(大小写、斜杠)
  • 脚本没有放入最终镜像

排查方法

  • adb shell ls /system/bin/init.test.sh看是否存在
  • adb shell getprop ro.product.device确认.rc是否针对当前设备加载
  • 检查 build log 是否包含你的脚本模块

8.2 提示 “Permission denied” 或 SELinux 报错

典型日志

avc: denied { execute } for comm="init" name="init.test.sh" dev="sdaXX" scontext=u:r:init:s0 tcontext=u:object_r:system_file:s0 tclass=file

解决办法

  • 确保file_contexts正确映射了文件路径和类型
  • 确保.te文件中定义了exec_type
  • 使用permissive test_service;临时放开策略测试(仅调试用)

8.3 脚本反复重启(未加 oneshot)

如果你忘了加oneshotinit会认为服务异常退出并不断重启。

加上oneshot后,执行完即结束,不会重复运行。

8.4 脚本执行太早,依赖的服务还没起来

有些操作需要等到特定属性设置后才执行,可以用on property:触发:

on property:sys.usb.config=adb exec u:object_r:test_service_exec:s0 root root -- /system/bin/init.test.sh

或者监听boot_completed

on property:sys.boot_completed=1 start test_service

配合disabled使用更灵活:

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

9. 最佳实践建议

9.1 小心使用 root 权限

尽量避免长期以 root 身份运行服务。如果只是初始化配置,完全可以执行完就退出。

9.2 日志先行,结果可验

每次调试都加一条logsetprop,确保你能通过外部手段验证执行状态。

9.3 使用专用命名空间

不要用test_service这种通用名,建议加上公司或项目前缀:

mycompany_init_service

避免与其他模块冲突。

9.4 脚本尽量简洁

.rc启动的脚本应专注于“初始化”,不要做耗时操作或网络请求。复杂逻辑建议交给后续服务处理。


10. 总结

通过本文的详细步骤,你应该已经掌握了如何在 Android 系统中实现一个可靠的开机启动 shell 脚本。回顾一下关键点:

  1. 编写正确的 shell 脚本,shebang 路径不能错
  2. 将脚本编译进系统镜像,并赋予可执行权限
  3. .rc文件中定义service并设置oneshotseclabel
  4. 添加 SELinux 策略(.te+file_contexts),这是成败关键
  5. 通过getproplogcatdmesg等方式验证执行结果

虽然整个过程涉及多个系统组件(init、SELinux、build 系统),但只要按部就班操作,完全可以掌握这一核心技能。

无论是做 ROM 定制、自动化测试还是硬件适配,这项能力都会成为你手中的一把利器。


获取更多AI镜像

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

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

5个核心价值:Zotero Style插件高效使用与核心技巧完全掌握指南

5个核心价值&#xff1a;Zotero Style插件高效使用与核心技巧完全掌握指南 【免费下载链接】zotero-style zotero-style - 一个 Zotero 插件&#xff0c;提供了一系列功能来增强 Zotero 的用户体验&#xff0c;如阅读进度可视化和标签管理&#xff0c;适合研究人员和学者。 项…

作者头像 李华
网站建设 2026/6/5 14:49:25

如何用XXMI-Launcher实现多游戏模组高效管理?超实用指南

如何用XXMI-Launcher实现多游戏模组高效管理&#xff1f;超实用指南 【免费下载链接】XXMI-Launcher Modding platform for GI, HSR, WW and ZZZ 项目地址: https://gitcode.com/gh_mirrors/xx/XXMI-Launcher XXMI-Launcher是一款专为原神、星穹铁道、鸣潮和绝区零等游戏…

作者头像 李华
网站建设 2026/6/10 11:09:16

Llama3-8B文档摘要功能实战:长文本处理部署与效果评估

Llama3-8B文档摘要功能实战&#xff1a;长文本处理部署与效果评估 1. 为什么选Llama3-8B做文档摘要&#xff1f; 你有没有遇到过这样的情况&#xff1a;手头有一份50页的技术白皮书、一份2万字的行业分析报告&#xff0c;或者一封密密麻麻的项目需求邮件&#xff1f;想快速抓…

作者头像 李华
网站建设 2026/6/10 13:33:20

零门槛小红书数据采集:Python工具高效合规实战指南

零门槛小红书数据采集&#xff1a;Python工具高效合规实战指南 【免费下载链接】xhs 基于小红书 Web 端进行的请求封装。https://reajason.github.io/xhs/ 项目地址: https://gitcode.com/gh_mirrors/xh/xhs 在数据驱动决策的时代&#xff0c;高效采集与合规爬取成为数据…

作者头像 李华
网站建设 2026/6/10 11:40:20

游戏模组管理深度评测:XXMI启动器的技术架构与实用价值分析

游戏模组管理深度评测&#xff1a;XXMI启动器的技术架构与实用价值分析 【免费下载链接】XXMI-Launcher Modding platform for GI, HSR, WW and ZZZ 项目地址: https://gitcode.com/gh_mirrors/xx/XXMI-Launcher 游戏模组管理工具是现代游戏生态的重要组成部分&#xff…

作者头像 李华
网站建设 2026/6/10 11:43:30

革新性PDF翻译全攻略:学术文档处理的高效解决方案

革新性PDF翻译全攻略&#xff1a;学术文档处理的高效解决方案 【免费下载链接】BabelDOC Yet Another Document Translator 项目地址: https://gitcode.com/GitHub_Trending/ba/BabelDOC 在学术研究与专业工作中&#xff0c;PDF翻译工具已成为跨语言交流的核心枢纽&…

作者头像 李华