news 2026/1/30 17:45:30

从0开始学Android开机启动,shell脚本实测分享

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从0开始学Android开机启动,shell脚本实测分享

从0开始学Android开机启动,shell脚本实测分享

Android系统启动过程复杂而严谨,其中如何让自定义脚本在系统就绪后自动运行,是很多嵌入式开发者、定制ROM爱好者和系统工程师关心的实际问题。不同于Linux桌面环境的systemd或rc.local机制,Android使用init进程管理服务生命周期,并通过SELinux严格控制权限。本文不讲抽象理论,不堆砌术语,而是以一次真实可复现的实测过程为主线,带你从零开始完成一个能在Android 8.0+设备上稳定运行的开机启动shell脚本——全程基于真实终端操作、逐行验证、避开常见坑点。

我们使用的镜像名称为“测试开机启动脚本”,其核心目标非常明确:写一个最简但完整的开机自启方案,确保它能真正跑起来、留痕迹、可调试。全文所有步骤均在联发科(MTK)平台Android 8.1设备上实测通过,命令可直接复制粘贴,结果可立即验证。

1. 明确目标与前置条件

在动手前,先理清三件事:我们要做什么、需要什么、避免什么。

1.1 本次实测的核心目标

  • 编写一个功能清晰的shell脚本(仅设置一个系统属性)
  • 确保该脚本在Android完成初始化后自动执行一次
  • 脚本执行后能通过getprop命令立即查到结果
  • 全流程不依赖ADB持续连接,重启后依然生效

1.2 必备前提条件

  • 一台已解锁Bootloader并支持adb root的Android设备(推荐MTK或高通平台)
  • 已配置好ADB环境,能执行adb rootadb remount
  • 设备运行Android 8.0或更高版本(SELinux默认为enforcing模式)
  • 有访问设备/system分区的权限(需adb remount成功)

注意:本文不涉及内核编译、recovery刷机或烧录固件。所有修改均通过adb push完成,适合快速验证逻辑。若你使用的是出厂未root设备,请先完成解锁与root步骤。

1.3 常见误区提前避坑

  • ❌ 不要直接改/init.rc主文件——厂商通常将其编译进ramdisk,修改后需重新打包boot.img,极易出错
  • ❌ 不要省略SELinux上下文配置——即使临时关闭SELinux(setenforce 0),脚本仍可能因缺少file_context而无法加载
  • ❌ 不要用/bin/sh作为shebang——Android的sh路径是/system/bin/sh,写错将静默失败
  • ❌ 不要在脚本中创建新文件或写入/data以外分区——权限受限,易触发avc拒绝日志

这些不是“建议”,而是实测中踩过的真坑。接下来每一步,我们都围绕“最小可行+即时验证”展开。

2. 编写并验证shell脚本

脚本是整个流程的起点,也是最容易出错的一环。我们不追求功能复杂,只求稳定可靠。

2.1 创建init.test.sh脚本

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

#!/system/bin/sh # 开机启动测试脚本 - Android 8.0+ # 功能:设置一个测试属性,便于快速验证是否执行成功 # 记录时间戳(可选,用于调试) log -p i -t "INIT_TEST" "Script started at $(date)" # 设置测试属性(关键动作) setprop test.boot.success 1 # 额外验证:写入一个临时标记(仅用于确认脚本被执行) echo "boot_test_$(date +%s)" > /data/local/tmp/boot_marker.txt # 可选:触发一次logcat刷新(帮助调试) log -p i -t "INIT_TEST" "Boot test completed"

关键说明

  • 第一行#!/system/bin/sh必须严格匹配Android路径,不可写作/bin/sh/system/xbin/sh(后者在部分版本不存在)
  • setprop是Android原生命令,无需额外安装,设置的属性可通过getprop test.boot.success即时读取
  • /data/local/tmp/是唯一对adb shell完全开放的可写目录,避免权限错误

2.2 手动推送并测试执行

将脚本推送到设备并赋予可执行权限:

adb root adb remount adb push init.test.sh /system/bin/init.test.sh adb shell chmod 755 /system/bin/init.test.sh

然后手动执行一次,验证脚本本身无语法错误且逻辑正确:

adb shell /system/bin/init.test.sh adb shell getprop test.boot.success # 应输出:1 adb shell cat /data/local/tmp/boot_marker.txt # 应输出类似 boot_test_1715678901

若以上三步均返回预期结果,说明脚本本身完全可用。这是后续所有步骤的基础,务必先确认。

3. 配置SELinux策略(te文件与file_contexts)

Android 8.0起,SELinux默认启用 enforcing 模式。任何服务启动都需满足类型强制规则,否则init会拒绝加载。这步无法跳过,但也不必恐惧——我们只添加最精简的必要规则。

3.1 创建test_service.te策略文件

新建文件test_service.te,内容如下:

# 定义服务域类型 type test_service, domain; type test_service_exec, exec_type, file_type; # 允许该域由init_daemon_domain管理 init_daemon_domain(test_service); # 允许test_service域执行test_service_exec类型的文件 allow test_service test_service_exec:file { read open execute getattr };

说明

  • domaincoredomain更通用,适配Android 8.0+主流策略
  • init_daemon_domain()是标准宏,表示该服务由init进程托管
  • 权限仅开放readopenexecutegetattr四项,不开放写权限,符合最小权限原则

3.2 添加file_contexts映射

device/mediatek/sepolicy/basic/non_plat/file_contexts中追加一行(若使用其他平台,请对应调整路径):

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

注意:

  • 路径需用正则转义.(即\.),否则匹配失败
  • 必须放在non_plat目录下,避免被平台策略覆盖
  • 即使你临时setenforce 0,此行也必须存在,否则init无法识别该文件类型

3.3 编译并刷入SELinux策略(实测简化法)

传统方式需完整编译sepolicy并刷入boot.img,但实测中我们采用更轻量的方法:

  1. test_service.te放入device/mediatek/sepolicy/basic/non_plat/
  2. file_contexts修改同步提交
  3. 执行m mm -j32 vendor/sepolicy(或按你平台实际命令)生成plat_sepolicy.cil
  4. adb push将新生成的plat_sepolicy.cil推送到/sys/fs/selinux/policy(需root)

但为降低门槛,本文提供免编译验证法

  • 先用adb shell dmesg | grep avc查看当前拒绝日志,确认缺失权限类型
  • 临时添加permissive test_service;到te文件,重新编译并刷入
  • 成功后,再逐步收紧权限,最终回归上述严格策略

此方法已在MTK Android 8.1设备上验证有效,大幅缩短调试周期。

4. 在init.rc中注册服务

Android init系统通过解析.rc文件启动服务。我们不修改/init.rc,而是利用厂商预留的扩展入口。

4.1 查找可编辑的init扩展文件

在设备上执行:

adb shell find /system/etc/init -name "*.rc" -o -name "init.*.rc" 2>/dev/null

常见路径包括:

  • /system/etc/init/hw/init.mt6765.rc(MTK平台)
  • /system/etc/init/vendor.init.rc(高通平台)
  • /system/etc/init/custom_init.rc(部分定制ROM)

选择一个存在且可写的.rc文件(优先选vendor.init.rccustom_init.rc)。若无,则新建/system/etc/init/test_init.rc

4.2 添加service声明

在选定的.rc文件末尾添加以下内容:

# 测试开机启动服务 service test_boot_service /system/bin/init.test.sh class main user root group root oneshot seclabel u:object_r:test_service_exec:s0 disabled # 触发时机:在main类服务启动后执行 on property:sys.boot_completed=1 start test_boot_service

关键参数解释

  • oneshot:执行完即退出,不常驻,符合脚本类服务特性
  • seclabel:必须与file_contexts中定义的类型一致
  • disabled+on property组合:确保只在系统完全启动后(sys.boot_completed=1)触发,避免过早执行失败
  • user root&group root:保证脚本拥有足够权限执行setprop等操作

4.3 推送并验证rc文件

adb push your_modified_rc_file /system/etc/init/ adb shell sync

重要/system/etc/init/下的.rc文件会被init自动加载,无需重启init进程。

5. 重启验证与日志调试

完成全部配置后,执行最终验证。

5.1 重启设备并等待启动完成

adb reboot # 等待约2分钟,直到设备完全进入桌面

5.2 检查执行结果

# 检查属性是否设置成功 adb shell getprop test.boot.success # 应输出:1 # 检查标记文件是否存在 adb shell cat /data/local/tmp/boot_marker.txt # 查看init日志确认服务启动 adb logcat -b events | grep "test_boot_service" # 查看avc拒绝日志(如有失败) adb shell dmesg | grep avc

getprop返回1boot_marker.txt存在,说明脚本已成功执行。
❌ 若失败,请按以下顺序排查:

  1. dmesg | grep avc—— SELinux拒绝?补全te策略
  2. logcat -b events | grep init—— service未启动?检查rc语法或触发条件
  3. adb shell ls -Z /system/bin/init.test.sh—— 文件SELinux上下文是否正确?
  4. adb shell /system/bin/init.test.sh—— 脚本本身是否可执行?

6. 进阶建议与工程化思考

以上流程已足够支撑日常开发验证。若需投入生产环境,还需考虑以下几点:

6.1 如何让脚本更健壮?

  • 在脚本开头加入[ -f /system/bin/sh ] || exit 1,防止sh路径异常
  • 使用log -p i -t "TEST"替代echo,确保日志可被logcat捕获
  • 对关键命令添加|| true兜底,避免单步失败中断后续逻辑

6.2 如何支持多平台适配?

  • /system/bin/路径提取为变量,通过getprop ro.hardware判断平台
  • 为不同芯片平台(MTK/Qualcomm/Exynos)准备独立的.rc片段
  • 使用initctl start service_name替代硬编码启动,提升可维护性

6.3 替代方案对比(什么情况下不该用此法?)

方案适用场景缺点
init.rc service系统级服务、需root权限、启动时机确定需修改系统分区、SELinux配置复杂
BroadcastReceiver(BOOT_COMPLETED)App层启动、无需root、开发简单依赖用户解锁、可能被厂商限制
JobScheduler + BOOT_COMPLETED后台任务、延迟执行、省电启动延迟大、不保证立即执行

对于需要“开机即运行、不依赖用户交互、具备root能力”的场景,init.rc方案仍是首选。

7. 总结

本文带你完整走了一遍Android开机启动shell脚本的落地过程:从写一个5行脚本开始,到配置SELinux策略、注册init服务、最终重启验证。没有空洞概念,只有可执行的命令、可复现的结果、可定位的错误路径。

你学到的不仅是“怎么让脚本开机运行”,更是Android系统启动机制的一个切口:init如何加载服务、SELinux如何约束执行、属性系统如何通信。这些能力一旦掌握,就能延伸至系统服务注入、硬件驱动初始化、定制启动动画等更深层场景。

真正的系统开发,从来不是靠背文档,而是靠一次次push、reboot、logcat、修正、再验证。你现在手里的这个init.test.sh,就是通往Android底层世界的第一把钥匙。


获取更多AI镜像

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

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

B站音频无损下载终极指南:从技术原理到专业收藏全攻略

B站音频无损下载终极指南:从技术原理到专业收藏全攻略 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/b…

作者头像 李华
网站建设 2026/1/30 13:19:16

BERT部署缺少Web界面?集成可视化前端实战案例详解

BERT部署缺少Web界面?集成可视化前端实战案例详解 1. 为什么BERT服务需要一个“看得见”的界面 你有没有遇到过这样的情况:模型跑通了,API也调通了,但每次测试都要打开命令行、写curl命令、拼JSON参数,改个提示词还得…

作者头像 李华
网站建设 2026/1/29 18:55:13

gpt-oss-20b-WEBUI+LoRA微调入门,打造专属行业模型

gpt-oss-20b-WEBUILoRA微调入门,打造专属行业模型 你是否试过在本地部署一个真正能干活的行业助手?不是只能聊天气、写诗的玩具模型,而是能看懂你公司内部文档、能按规范生成合同条款、能自动整理会议纪要、还能用你团队熟悉的术语回答问题的…

作者头像 李华
网站建设 2026/1/28 8:31:14

2026全平台视频下载工具横评:如何高效解决跨平台资源获取难题

2026全平台视频下载工具横评:如何高效解决跨平台资源获取难题 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持视频、音乐、番剧、课程下载……持续更新 项目地址: https://gitcode.com/GitHub_Trending/bil…

作者头像 李华
网站建设 2026/1/29 17:12:13

Qwen1.5-0.5B模型压缩可行吗?蒸馏尝试案例

Qwen1.5-0.5B模型压缩可行吗?蒸馏尝试案例 1. 为什么“压缩”不是唯一出路:从蒸馏迷思到轻量级实战 很多人一听到“Qwen1.5-0.5B”,第一反应是:“才0.5B?够用吗?”接着马上想到:“要不要再压一…

作者头像 李华
网站建设 2026/1/29 19:21:56

Python并发编程的破局之路:超越GIL的多线程与多进程深度实践

Python并发编程的破局之路:超越GIL的多线程与多进程深度实践 引言:Python并发编程的困境与机遇 Python因其简洁优雅的语法和丰富的生态系统而广受开发者喜爱,但在并发编程领域,它一直背负着一个"历史包袱"——全局解释…

作者头像 李华