news 2026/4/18 9:37:58

Android系统级脚本入门:测试开机启动脚本详细教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android系统级脚本入门:测试开机启动脚本详细教程

Android系统级脚本入门:测试开机启动脚本详细教程

在Android开发和系统定制过程中,经常需要让某些服务或逻辑在设备启动完成时自动运行。比如预装应用的初始化、硬件状态检测、日志收集、网络配置等。这类需求最直接可靠的实现方式,就是编写一个开机启动脚本,并将其集成进系统初始化流程中。

但很多刚接触Android底层的同学会发现:写个shell脚本不难,可一放到init.rc里就报错、卡住、甚至无法开机——问题往往不出在脚本本身,而在于Android 8.0+引入的严格Selinux策略、init语法变更、执行上下文限制等系统级约束。

本文不是泛泛而谈“怎么写shell”,而是聚焦一个真实可用的最小闭环:从零开始,手把手带你完成一个经过实测验证的开机启动脚本,覆盖环境准备、脚本编写、Selinux适配、init集成、调试验证全流程。所有步骤均基于Android 8.0及以上版本(含主流MTK/高通平台),无需root、不依赖ADB shell持久化,真正“烧录即生效”。

你不需要熟悉Selinux规则细节,也不用翻遍AOSP源码;只需要按顺序操作,就能看到getprop test.prop返回你设定的值——这是开机脚本成功执行的最直观证据。


1. 明确目标与前置条件

1.1 你要学会什么

  • 编写一个能在Android系统启动早期阶段稳定执行的shell脚本
  • 理解Android init机制中service声明的关键字段含义(oneshotuserseclabel等)
  • 掌握Selinux权限适配的最小必要操作(te文件 + file_contexts)
  • 学会用getproplogcat快速验证脚本是否真正触发
  • 避开常见坑点:路径错误、shell解释器不匹配、Selinux拒绝、init语法不兼容

1.2 你需要准备什么

  • 一台已解锁Bootloader的Android设备(推荐使用开发板或工程机,避免量产机锁区)
  • AOSP或芯片厂商提供的完整Android源码(至少包含system/core/initexternal/sepolicydevice/xxx/sepolicy目录)
  • 编译环境(Linux主机,安装repo、JDK、Python等基础工具)
  • 基础Linux命令能力(adbpushrebootgetproplogcat

注意:本文不涉及ADB临时启动或su提权方案。我们做的是真正的系统级开机脚本,它随系统镜像固化,重启后自动生效,是OEM/ODM厂商的标准做法。


2. 编写可执行的开机脚本

2.1 脚本内容与关键细节

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

#!/system/bin/sh # 开机脚本必须以正确的shebang开头 # Android系统默认shell路径为 /system/bin/sh(非 /bin/sh) # 错误路径会导致init直接跳过执行,且无明显报错 # 设置一个系统属性作为执行标记(最轻量、最安全的验证方式) setprop test.prop "init_test_ran_at_$(date +%s)" # 可选:记录日志到kernel log(便于logcat抓取) log -t INIT_TEST "Script executed successfully. Prop set to $(getprop test.prop)" # 可选:创建一个临时标记文件(仅用于调试,生产环境建议避免写文件) # touch /data/local/tmp/init_test_done

2.2 为什么这样写?小白也能懂的原理

  • #!/system/bin/sh是硬性要求:Android的init进程只认这个路径下的解释器。写成/bin/sh/system/xbin/sh在部分设备上会失败。
  • setprop是首选验证手段:它不依赖文件系统权限、不产生磁盘IO、不会因/data未挂载而失败,且可通过adb shell getprop test.prop秒级确认。
  • log -techo更可靠:echo输出到stdout在init上下文中不可见,而log命令会写入kernel log buffer,logcat -b events -t INIT_TEST即可捕获。
  • 注释掉touch行是经验之谈:早期Android中/data可能尚未挂载,写文件极易导致init卡死或崩溃。

2.3 手动验证脚本是否可运行

在push进设备前,请先本地测试语法:

# 在Linux主机上模拟执行(需有android-tools或busybox) sh -n init.test.sh # 检查语法错误

然后推送到设备手动运行:

adb root adb remount 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 test.prop # 应输出类似 "init_test_ran_at_1715678901"

只有这一步成功,才能进入下一步。如果失败,请回头检查shebang路径、换行符(必须是LF)、是否有多余空格。


3. 为脚本配置Selinux权限

3.1 为什么必须加Selinux?一句话说清

Android 8.0起,默认启用enforcing模式的Selinux。init进程以u:r:init:s0身份运行,它不能随意执行任意文件。你的脚本若没有对应file_typedomain定义,init会静默拒绝执行——连log都不会打。

这不是bug,是设计。所以必须显式声明:“这个脚本允许被init调用”。

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

在源码目录下新建文件:
device/your_company/your_platform/sepolicy/non_plat/test_service.te

内容如下:

# 定义一个新的域(domain),代表这个服务的执行上下文 type test_service, domain; # 定义该服务可执行的文件类型 type test_service_exec, exec_type, vendor_file_type, file_type; # 允许init域(init_daemon_domain)切换到test_service域 init_daemon_domain(test_service); # 允许test_service域读取/执行自己的文件 allow test_service test_service_exec:file { read open getattr execute }; # 允许test_service向property_service写属性(关键!否则setprop失败) allow test_service property_service:property_service { set };

说明:init_daemon_domain(test_service)是核心宏,它自动赋予test_service域访问/dev/*/proc/*property_service等init必需资源的权限,比手动写几十行allow更安全简洁。

3.3 关联文件路径与类型(file_contexts)

编辑device/your_company/your_platform/sepolicy/non_plat/file_contexts,在末尾添加一行:

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

注意:

  • 路径必须用正则转义(\.),否则匹配失败
  • 路径要与你实际存放位置完全一致(本文用/system/bin/,若放/vendor/bin/则需改路径)
  • s0是MLS级别,保持默认即可

3.4 验证Selinux配置是否生效

编译后刷机,执行:

adb shell ls -Z /system/bin/init.test.sh # 正确输出应包含:u:object_r:test_service_exec:s0

如果显示u:object_r:shell_exec:s0或报错,说明file_contexts未生效或路径不匹配。


4. 将脚本集成进init启动流程

4.1 不要直接修改init.rc!正确做法是新建init.XXX.rc

主流芯片平台(MTK/高通/展锐)都预留了客户自定义rc文件入口。例如:

  • MTK平台:device/mediatek/common/init/init.mtk.rcdevice/mediatek/sepolicy/basic/non_plat/init.mtk.rc
  • 高通平台:device/qcom/common/rootdir/etc/init.qcom.rc

找到对应位置,在其中添加:

# service <name> <pathname [argument] ...> # class <name> # user <username> # group <groupname> [groupname] ... # oneshot # seclabel u:object_r:test_service_exec:s0 service test_service /system/bin/init.test.sh class main user root group root oneshot seclabel u:object_r:test_service_exec:s0

4.2 各字段作用通俗解读

字段作用为什么这么设
class main归入main类,确保在on early-init之后、on init期间启动main类是绝大多数服务的默认归属,时机稳妥
user root&group root以root身份运行开机脚本常需访问硬件节点、设置系统属性,非root不可
oneshot执行完即退出,不常驻我们的脚本是单次任务(设prop),无需后台守护
seclabel强制指定执行域,与te文件中的test_service_exec对应Selinux强制要求,缺一不可

提示:不要加start test_service。init.rc中service声明本身不触发执行,需由on触发器(如on boot)启动。oneshot服务通常由on property:on boot隐式触发。

4.3 确保触发时机(可选增强)

如果你希望脚本在某个明确事件后执行(比如sys.boot_completed=1),可在同一rc文件中添加:

on property:sys.boot_completed=1 start test_service

但对简单设prop场景,class main已足够——init会在on init阶段自动启动所有mainoneshot服务。


5. 编译、刷机与最终验证

5.1 编译命令(以全编译为例)

# 进入源码根目录 source build/envsetup.sh lunch your_target-userdebug m -j16 # 编译整个系统(含sepolicy、init、system分区)

Sepolicy编译会自动合并non_plat目录下所有.te.fc文件,无需额外操作。

5.2 刷机与验证步骤

  1. 将生成的system.img刷入设备(使用fastboot或烧录工具)
  2. 重启设备:adb reboot
  3. 等待开机完成(约1~2分钟),执行验证:
# 检查属性是否已设置(最直接证据) adb shell getprop test.prop # 正常应输出:init_test_ran_at_1715678901 # 查看init日志(确认服务是否启动) adb logcat -b events | grep -i "test_service" # 查看kernel log中的自定义日志 adb logcat -b kernel | grep -i "INIT_TEST"

5.3 常见问题速查表

现象可能原因快速排查方法
getprop test.prop无输出脚本根本没执行`adb logcat -b events
logcat中出现avc: deniedSelinux权限缺失`adb logcat -b events
设备卡在开机动画init语法错误或脚本崩溃串口连接,看kernel panic或init segfault信息
ls -Z显示类型错误file_contexts未生效或路径不匹配检查路径是否带转义、是否在正确non_plat目录、是否clean编译

6. 进阶建议与安全提醒

6.1 生产环境优化建议

  • 避免硬编码路径:用/system/bin/sh而非/system/xbin/sh,前者在所有Android版本中稳定存在。
  • 增加错误处理:在脚本中加入if [ $? -ne 0 ]; then log -t INIT_TEST "Failed"; fi
  • 日志分级:用log -p i(info)、log -p e(error)替代统一-t,便于过滤。
  • 精简执行逻辑:开机脚本应尽量短小(<10行),耗时操作建议fork到后台或通过property触发后续服务。

6.2 绝对不要做的三件事

  • ❌ 不要在脚本中调用rebootpoweroff等危险命令
  • ❌ 不要尝试挂载/格式化分区(init上下文无此权限,且极不安全)
  • ❌ 不要写入/system分区(只读挂载,写入失败且可能触发verity校验失败)

6.3 为什么这个方案比“ADB开机启动”更可靠?

方案是否随系统固化是否依赖ADB连接是否受USB调试开关影响是否能早于UI启动
本文方案(init.rc + Selinux)❌ 否❌ 否是(early-init阶段)
ADB +adb shell❌ 否❌ 否(需ADB服务已启动)
pm enable+BroadcastReceiver❌ 否❌ 否❌ 否❌ 否(需Launcher进程启动)

真正的系统级自动化,始于init,止于内核。掌握它,你就拿到了Android底层的第一把钥匙。


获取更多AI镜像

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

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

Unity资源提取与编辑的跨平台工具:UABEA全面指南

Unity资源提取与编辑的跨平台工具&#xff1a;UABEA全面指南 【免费下载链接】UABEA UABEA: 这是一个用于新版本Unity的C# Asset Bundle Extractor&#xff08;资源包提取器&#xff09;&#xff0c;用于提取游戏中的资源。 项目地址: https://gitcode.com/gh_mirrors/ua/UAB…

作者头像 李华
网站建设 2026/4/18 3:11:34

Hanime1智能优化插件:打造Android平台高效观影体验探索指南

Hanime1智能优化插件&#xff1a;打造Android平台高效观影体验探索指南 【免费下载链接】Hanime1Plugin Android插件(https://hanime1.me) (NSFW) 项目地址: https://gitcode.com/gh_mirrors/ha/Hanime1Plugin 探索篇&#xff1a;Android观影体验的技术瓶颈与突破 现代…

作者头像 李华
网站建设 2026/4/15 16:50:14

MacOS系统ComfyUI-Manager高效部署与优化指南

MacOS系统ComfyUI-Manager高效部署与优化指南 【免费下载链接】ComfyUI-Manager 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-Manager 引言&#xff1a;为什么MacOS安装ComfyUI-Manager需要特别处理&#xff1f; 在创意AI领域&#xff0c;ComfyUI-Manager作…

作者头像 李华
网站建设 2026/4/16 9:26:07

如何突破QQ音乐加密限制?QMCDecode高效解决方案

如何突破QQ音乐加密限制&#xff1f;QMCDecode高效解决方案 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac&#xff0c;qmc0,qmc3转mp3, mflac,mflac0等转flac)&#xff0c;仅支持macOS&#xff0c;可自动识别到QQ音乐下载目录&#xff0c;默认转换结果…

作者头像 李华
网站建设 2026/4/17 9:09:48

STM32串口DMA传输效率优化操作指南

以下是对您提供的技术博文进行 深度润色与结构化重构后的专业级技术文章 &#xff0c;已彻底去除AI生成痕迹、模板化表达和冗余套话&#xff0c;转而以一位有十年嵌入式开发经验的工程师口吻&#xff0c;用清晰逻辑、实战细节与真实工程权衡&#xff0c;重写全文。语言更贴近…

作者头像 李华
网站建设 2026/4/18 8:01:49

【拯救HMI】:救命的像素:为何HMI图标设计决定了工厂安全?

在工业现场&#xff0c;HMI&#xff08;人机界面&#xff09;不是艺术品&#xff0c;它是操作员的“眼睛”。当警报响起&#xff0c;一个模糊的图标可能意味着几百万的损失&#xff0c;甚至生命的代价。你是否见过这样的HMI界面&#xff1a;背景是高饱和度的渐变蓝&#xff0c;…

作者头像 李华