news 2026/4/16 23:41:33

Android开机启动脚本命名规范与路径说明

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android开机启动脚本命名规范与路径说明

Android开机启动脚本命名规范与路径说明

在Android系统定制开发中,实现自定义服务或工具的开机自动运行是常见需求。但很多开发者在首次尝试时会遇到脚本不执行、权限拒绝、SELinux拦截等问题,其中很大一部分原因源于对脚本命名规则和存放路径缺乏系统理解。本文不讲抽象原理,只聚焦一个核心问题:你的开机启动脚本该叫什么名字?该放在哪里?为什么必须这样?所有内容均基于Android 8.0及以上版本实测验证,适用于高通、MTK等主流平台,已在“测试开机启动脚本”镜像中完成全流程验证。

1. 脚本命名不是随便起的:4条硬性规范

很多人以为init.xxx.shxxx.shstart.sh都可以,其实Android init机制对脚本名称有明确约束。命名错误会导致init进程根本不会识别该文件,更谈不上执行。

1.1 必须以init.开头,且后缀为.sh

这是Android init解析器的硬编码规则。init进程在扫描/system/bin/等目录时,仅识别符合init.*.sh模式的可执行文件(注意:不是所有.sh文件,而是必须带init.前缀)。

  • 正确示例:init.test.shinit.network.shinit.logrotate.sh
  • ❌ 错误示例:test.sh(无init.前缀)、init_test.sh(下划线非点号)、init.test(无.sh后缀)

关键提示:这个规则写死在system/core/init/builtins.cppdo_chdirimport_parser相关逻辑中,并非约定俗成。即使你用chmod +x赋予执行权限,test.sh也永远不会被init加载。

1.2 名称中禁止使用空格、中文、特殊符号(除点号和字母数字外)

init解析器使用空格作为参数分隔符,若脚本名含空格(如init my service.sh),会被截断为initmyservice.sh三段,导致路径错误。同理,中文字符在UTF-8与ASCII混合环境中极易引发编码解析失败。

  • 安全组合:小写字母、数字、点号(.
  • ❌ 高危字符:空格、@#$%&*()+={}[]|\;:"'<>,?/~^-(连字符在部分旧版本中也有兼容问题,建议避免)

1.3 避免与系统已有init脚本重名

Android系统自带大量init.*.sh脚本,如init.qcom.rcinit.mdm.shinit.recovery.sh等。若你的脚本命名为init.qcom.sh,可能被系统覆盖或引发冲突。

  • 推荐做法:在init.后加入项目缩写或功能标识,如init.csdn_test.shinit.myservice.sh
  • ❌ 风险操作:直接复用芯片厂商命名空间(如init.mtk.shinit.qualcomm.sh

1.4 名称长度建议控制在24字符以内

虽然Linux文件系统支持长文件名,但init进程在早期解析阶段使用固定长度缓冲区(通常为32字节)。过长名称可能导致截断,尤其在带路径拼接时(如/system/bin/init.very_long_custom_script_name.sh)易触发边界错误。

  • 实践建议:init.test.sh(12字符)、init.netmon.sh(13字符)足够清晰且安全
  • 警惕:init.custom_network_monitor_service_v2.sh(37字符)存在潜在风险

2. 脚本存放路径:3个合法位置与选择逻辑

脚本命名正确只是第一步,放错位置同样无法启动。Android init仅从特定目录加载脚本,且不同目录对应不同执行时机与权限上下文。

2.1 首选路径:/system/bin/—— 系统级服务,root权限,最稳定

这是官方推荐且兼容性最好的路径。/system/bin/下的脚本由init进程以root用户身份直接执行,无需额外配置用户组,SELinux上下文也最易适配。

  • 适用场景:需要访问硬件设备节点(如/dev/ttyS0)、修改系统属性(setprop)、启动守护进程(daemon
  • 实操步骤:
# 在PC端编译好脚本后push adb root adb remount adb push init.test.sh /system/bin/ adb shell chmod 755 /system/bin/init.test.sh
  • 注意:需确保/system分区已remount为可写,且脚本必须有+x权限

2.2 次选路径:/vendor/bin/—— 厂商扩展区,适合SoC定制化功能

在Android Treble架构下,/vendor分区独立于/system,专供芯片厂商放置驱动、HAL及配套脚本。将脚本放在此处可避免系统升级时被覆盖。

  • 适用场景:MTK/高通平台特有的初始化逻辑(如基带校准、射频参数加载)
  • SELinux适配关键:必须在file_contexts中声明类型,例如:
/vendor/bin/init.test.sh u:object_r:test_service_exec:s0
  • ❌ 常见误区:直接放入/vendor/bin/却不更新SELinux策略,会导致avc: denied { execute }错误,即使关闭SELinux也会因file_contexts缺失而失败。

2.3 特殊路径:/data/local/tmp/—— 仅限调试,不可用于量产

此路径无需recovery刷机或adb remount,适合快速验证脚本逻辑是否正确。但因其属于用户数据分区,重启后内容可能被清除,且init默认不从此处加载脚本。

  • 调试技巧:在init.rc中临时添加一行指向该路径(仅测试用):
service test_debug /data/local/tmp/init.test.sh class main user root group root oneshot seclabel u:object_r:shell_exec:s0
  • ❌ 严禁行为:将此路径用于正式开机启动,因/data可能延迟挂载,导致脚本执行失败。

3. init.rc服务声明:路径、权限与执行时机三要素

脚本文件就位后,必须通过init.rc或其导入文件声明服务。声明错误是开机不执行的第二大原因。

3.1 路径必须与实际存放位置严格一致

service指令后的路径是绝对路径,不能省略/system/bin/等前缀。常见错误是写成service test /init.test.sh(缺少/system/bin/)或service test init.test.sh(相对路径)。

  • 正确写法(脚本在/system/bin/):
service test_service /system/bin/init.test.sh class main user root group root oneshot seclabel u:object_r:test_service_exec:s0
  • ❌ 错误写法:
    • service test_service init.test.sh(init会尝试在当前工作目录找,通常是/,找不到)
    • service test_service ./init.test.sh(不支持.语法)

3.2 用户与组设置决定脚本能访问的资源范围

  • user root:可访问所有设备节点、修改系统属性、绑定特权端口(<1024)
  • user system:权限受限,无法操作/dev/下多数节点
  • group root:必须显式声明,否则即使user root也无法获得root组权限(影响/dev/节点访问)

实测案例:某脚本需向/dev/block/mmcblk0p1写入数据,仅设user root但未设group root,报错Permission denied;添加group root后正常。

3.3oneshotdisabled标志决定启动时机与重试逻辑

  • oneshot:执行一次即退出,适合初始化类脚本(如setprop、创建临时文件)。这是绝大多数开机脚本的正确选择。
  • disabled:默认不启动,需通过start <service_name>命令手动触发。可用于按需启动的调试服务。
  • ❌ 禁止对shell脚本使用restartclass main以外的class:class late_start等在脚本执行阶段尚未就绪,会导致超时失败。

4. SELinux策略:3个必须配置的文件与1个调试技巧

在Android 8.0+强制启用SELinux的环境下,缺少策略配置是脚本静默失败的最常见原因。策略涉及三个文件,缺一不可。

4.1test_service.te:定义域类型与基础权限

此文件声明脚本运行的SELinux域(domain)及其可执行类型。内容必须包含三要素:

# 定义服务域(必须与init.rc中seclabel一致) type test_service, coredomain; # 定义可执行文件类型(必须与file_contexts中一致) type test_service_exec, exec_type, vendor_file_type, file_type; # 允许init以该域启动服务 init_daemon_domain(test_service); # 关键:允许该域执行自身文件 allow test_service test_service_exec:file { read open getattr execute };

注意init_daemon_domain宏已隐含allow init test_service:process transition;,无需重复声明。

4.2file_contexts:绑定文件路径与SELinux类型

此文件将物理路径映射到SELinux类型,是init加载脚本前的必经校验。路径必须精确匹配,包括末尾斜杠(如有)。

  • 正确(脚本在/system/bin/):
/system/bin/init.test.sh u:object_r:test_service_exec:s0
  • 正确(脚本在/vendor/bin/):
/vendor/bin/init.test.sh u:object_r:test_service_exec:s0
  • ❌ 错误:/system/bin/init.*.sh(通配符不被file_contexts支持)、/system/bin/(目录级匹配无效)

4.3sepolicy加载位置:non_plat vs plat 的选择逻辑

  • non_plat目录(如device/mediatek/sepolicy/basic/non_plat/):存放芯片厂商或OEM定制策略,优先级高于plat,且不会被AOSP更新覆盖。强烈推荐将自定义策略放在此处
  • plat目录:AOSP标准策略,修改后可能被上游更新冲掉。

4.4 调试技巧:串口日志比logcat更直接

当脚本无输出时,adb logcat往往捕获不到init早期错误。连接串口(UART)并执行:

# 在串口终端中查看实时avc拒绝日志 dmesg | grep avc

每条avc: denied日志都明确指出缺失的权限,可直接转化为allow规则。例如:

avc: denied { write } for name="test.prop" dev="tmpfs" ino=12345 scontext=u:r:test_service:s0 tcontext=u:object_r:shell_prop:s0 tclass=file

→ 补充规则:allow test_service shell_prop:file write;

5. 完整验证流程:5步确认脚本真正生效

命名、路径、init.rc、SELinux全部配置完成后,必须按顺序验证,避免遗漏环节。

5.1 第一步:手动执行验证脚本逻辑

adb shell su /system/bin/init.test.sh echo $? # 检查返回值,0表示成功 getprop test.prop # 检查脚本内setprop是否生效

通过:说明脚本语法、路径、权限均正确
❌ 失败:先解决此步,再进行后续

5.2 第二步:检查init.rc是否被正确加载

adb shell cat /proc/1/cmdline # 确认init进程启动参数 ls -l /system/etc/init/ # 查看是否有对应.rc文件 getenforce # 确认SELinux状态(Enforcing/Permissive)

5.3 第三步:确认服务已注册但未启动

adb shell getprop | grep init.svc.test_service # 应返回空(未启动) dumpsys activity services | grep test_service # 应无输出

5.4 第四步:手动触发服务并观察状态

adb shell start test_service sleep 2 getprop init.svc.test_service # 应返回"stopped"(oneshot特性) getprop test.prop # 应返回脚本中设置的值

5.5 第五步:重启验证全自动执行

adb reboot # 等待开机完成 adb shell getprop test.prop # 重启后仍应有值,证明开机自动执行成功

6. 总结:命名与路径的黄金法则

回顾全文,Android开机启动脚本的命名与路径并非随意选择,而是由init进程设计逻辑、SELinux强制策略、Treble分区架构共同决定的工程约束。记住这三条黄金法则,可避开90%的坑:

  • 命名法则init.开头 + 小写字母数字点号 +.sh结尾 + 长度≤24字符,杜绝一切非常规字符;
  • 路径法则/system/bin/为首选,/vendor/bin/为次选,/data/local/tmp/仅限调试,路径必须与init.rc中声明的绝对路径完全一致;
  • 验证法则:不跳过任何一步验证,从手动执行→服务触发→重启测试,层层递进,用getpropdmesg代替猜测。

遵循这些规范,你的“测试开机启动脚本”镜像就能稳定可靠地完成每一次开机初始化任务。


获取更多AI镜像

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

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

基于STM32单片机汽车尾气检测蓝牙 WIFI MQ135+MQ-7

目录STM32单片机汽车尾气检测系统概述硬件组成软件设计系统工作流程应用场景注意事项源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;STM32单片机汽车尾气检测系统概述 该系统基于STM32单片机&#xff0c;结合MQ-135&#xff08;检测CO…

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

verl金融风控模型训练实战:多场景落地详解

verl金融风控模型训练实战&#xff1a;多场景落地详解 1. verl 是什么&#xff1f;一个为大模型后训练而生的强化学习框架 你可能已经听说过用强化学习&#xff08;RL&#xff09;来优化大语言模型——比如让模型更懂用户偏好、更会写营销文案、更擅长逻辑推理。但真正把 RL …

作者头像 李华
网站建设 2026/4/16 16:11:58

Qwen-Image-Edit-2511功能测评:文本/外观/语义编辑全掌握

Qwen-Image-Edit-2511功能测评&#xff1a;文本/外观/语义编辑全掌握 这是一次实打实的深度体验。不是看参数表&#xff0c;也不是读技术白皮书&#xff0c;而是把Qwen-Image-Edit-2511镜像拉进ComfyUI&#xff0c;从第一张图开始编辑&#xff0c;到完成十组不同难度的修改任务…

作者头像 李华
网站建设 2026/4/16 13:04:22

Multisim14.3安装教程:虚拟机中部署实操完整示例

以下是对您提供的博文内容进行 深度润色与结构重构后的专业级技术文章 。整体风格更贴近一线嵌入式/EDA工程师的真实写作口吻&#xff1a;语言精炼、逻辑严密、有实战温度&#xff0c;摒弃模板化表达和空泛总结&#xff1b;所有技术点均围绕“ 为什么这么干&#xff1f;不这…

作者头像 李华
网站建设 2026/4/16 13:01:27

视频融合平台EasyCVR构建智慧水利全域可视化智能监管体系

在水利现代化建设的进程中&#xff0c;视频监控系统正从传统的“看得见”向“看得懂、管得好”演进。水利工程分布广泛、环境复杂、业务多样的特点&#xff0c;对视频监控提出了更高要求。EasyCVR视频融合平台作为兼容性强大、功能完备的视频解决方案&#xff0c;正在成为智慧水…

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

Multisim14.0安装教程:适配Win10的全面讲解

以下是对您提供的技术博文进行深度润色与重构后的专业级技术文章。我以一位长期从事高校电子实验平台部署、嵌入式教学系统集成及NI工具链支持的工程师视角&#xff0c;彻底重写了全文——摒弃所有AI腔调、模板化结构与空泛总结&#xff0c;代之以真实工程语境下的逻辑流、踩坑…

作者头像 李华