2026/5/18 22:43:40
网站建设
项目流程
网站建设预算模板,上海网络广告公司,logo设计说明,假网站网站怎么做为什么脚本不执行#xff1f;Android开机启动常见问题
在Android系统开发中#xff0c;让自定义脚本随系统启动自动运行看似简单#xff0c;实则暗藏多个关键陷阱。很多开发者遇到“脚本写好了、rc文件改了、也push进去了#xff0c;但开机后属性没设、日志没打、文件没生…为什么脚本不执行Android开机启动常见问题在Android系统开发中让自定义脚本随系统启动自动运行看似简单实则暗藏多个关键陷阱。很多开发者遇到“脚本写好了、rc文件改了、也push进去了但开机后属性没设、日志没打、文件没生成——脚本就像没存在过一样”。这不是代码逻辑错了而是被几个隐蔽却致命的环节卡住了。本文聚焦真实工程场景不讲抽象理论只说你正在踩的坑为什么脚本明明存在却完全不执行从Shell解释器路径、SELinux策略、init.rc语法细节到调试验证的最小闭环方法全部基于实测经验整理。所有操作均在Android 8.0主流平台包括高通、MTK验证通过适用于“测试开机启动脚本”这类轻量级镜像的快速验证与排障。1. 第一关Shell解释器路径写错脚本根本不会被加载很多人复制Linux脚本直接改个名字就往Android里放结果第一行#!/bin/sh成了最大障碍。1.1 Android和Linux的Shell路径完全不同正确路径Android系统分区/system/bin/sh—— 大多数AOSP设备默认使用/system/xbin/sh—— 部分定制ROM或带busybox的设备错误路径Linux习惯Android上会静默失败/bin/sh/usr/bin/sh#!/sh关键提示#开头的行不是注释是shebang机制的硬性声明。内核在fork进程时会严格按这个路径去加载解释器。路径不存在 → 进程启动失败 → 脚本一行都不执行连log都看不到。1.2 验证方法不依赖开机先手动跑通在push脚本后务必执行这三步验证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 # 直接调用看是否报错如果输出类似/system/bin/sh: cant execute /system/bin/init.test.sh: No such file or directory说明shebang路径错误如果是Permission denied则是权限或SELinux拦截只有成功返回且adb shell getprop test.prop能查到值才代表脚本本身可执行。2. 第二关SELinux策略缺失脚本被静默拒绝Android 5.0之后默认启用SELinux enforcing模式。即使你把脚本放在/system/bin/没有对应策略init进程也无法以test_service身份执行它。2.1 策略文件必须成对出现仅写.te文件远远不够必须同时配置三处文件位置文件名关键内容作用device/xxx/sepolicy/basic/non_plat/test_service.tetype test_service_exec, exec_type, vendor_file_type;init_daemon_domain(test_service);声明服务类型与执行域关系device/xxx/sepolicy/basic/non_plat/file_contextsfile_contexts/(system\/vendor|vendor)\/bin\/init\.test\.sh u:object_r:test_service_exec:s0将脚本文件打上正确安全上下文标签init.rc或init.xxx.rcservice定义块seclabel u:object_r:test_service_exec:s0明确指定该service使用此标签启动注意file_contexts中的正则表达式必须精确匹配你的脚本路径。例如脚本放在/system/bin/就写/system/bin/init\.test\.sh若放在/vendor/bin/则需对应修改。路径不匹配 → 标签打不上 → SELinux拒绝执行。2.2 快速验证SELinux是否拦截开机后立即执行adb shell dmesg | grep avc # 或 adb shell cat /proc/kmsg | grep avc如果看到类似以下日志就是SELinux拦截avc: denied { execute } for path/system/bin/init.test.sh devdm-0 ino123456 scontextu:r:init:s0 tcontextu:object_r:shell_data_file:s0 tclassfile permissive0此时tcontext显示的是文件当前标签shell_data_file而非你期望的test_service_exec说明file_contexts未生效或路径不匹配。3. 第三关init.rc语法细节出错service根本未注册init.rc不是普通脚本它是Android init进程解析的配置语言对空格、缩进、换行极其敏感。3.1 最易忽略的四个语法雷区错误写法正确写法后果service test_service /system/bin/init.test.shclass mainuser rootservice test_service /system/bin/init.test.shclass mainuser root缩进必须是4个空格不能用Tab否则整段service被忽略oneshot写在seclabel后面oneshot必须在seclabel之前属性顺序错误 → 解析失败service不注册路径含空格/system/bin/ init.test.sh/system/bin/init.test.sh路径中多一个空格 → init认为命令是/system/bin/参数是init.test.sh执行失败on property:sys.boot_completed1放在service块内on property:sys.boot_completed1必须独立成段不能嵌套触发条件失效脚本永不执行3.2 推荐写法用标准模板避免手写错误# 在 init.xxx.rc 中添加不要动 init.rc 原文件 service test_service /system/bin/init.test.sh class main user root group root oneshot seclabel u:object_r:test_service_exec:s0 # 单独触发段确保系统完全就绪后再运行 on property:sys.boot_completed1 start test_serviceoneshot表示执行完即退出适合一次性初始化任务on property:sys.boot_completed1是最稳妥的触发时机比early-init或late-init更可靠所有行首缩进统一为4空格无Tab混入。4. 第四关脚本内部逻辑被静默终止即使前三个环节全对脚本也可能因内部问题“执行了但没效果”。4.1 Android Shell环境限制多不是所有命令都能用source xxx.sh、.命令在Android/system/bin/sh中不支持$(command)命令替换在旧版mksh中可能失败优先用反引号commandecho -n的-n参数在部分ROM中无效换行用printf更稳妥所有路径必须用绝对路径/system/bin/log而非log设置属性必须用setprop不能用export后者只在当前shell有效。4.2 推荐最小化健壮脚本模板#!/system/bin/sh # init.test.sh - 开机启动测试脚本已验证Android 8.0 # 1. 记录启动时间验证是否执行 /system/bin/log -t TEST_INIT Starting at $(/system/bin/date) # 2. 设置测试属性最简验证点 setprop test.prop booted_$(/system/bin/date %s) # 3. 创建标记文件验证文件系统可写 /system/bin/touch /data/local/tmp/test_init_done /system/bin/chmod 644 /data/local/tmp/test_init_done # 4. 写入日志验证log功能 printf Init script executed successfully at %s\n $(/system/bin/date) /data/local/tmp/test_init.log # 5. 清理临时变量可选 unset i j k每行都加注释便于快速定位哪一步失败所有命令用绝对路径避免PATH不可靠关键动作后加log -t方便adb logcat -s TEST_INIT实时追踪使用/data/local/tmp/而非/tmp/Android中/tmp常为内存挂载重启丢失。5. 第五关调试闭环不完整无法定位真实失败点很多开发者只看getprop或ls却漏掉最关键的两层日志。5.1 五步闭环调试法推荐顺序执行步骤命令判断依据说明1. 查init是否识别serviceadb shell getenforceadb shell ls -Z /system/bin/init.test.shEnforcingu:object_r:test_service_exec:s0确认SELinux状态与文件标签正确2. 查service是否注册adb shell getpropgrep init.svc.test_service输出stopped或running3. 查是否触发启动adb logcat -b eventsgrep boot_completed看到boot_completed1事件4. 查脚本是否被调用adb logcat -s TEST_INIT看到Starting at ...日志确认脚本第一行已执行5. 查最终效果adb shell getprop test.propadb shell ls -l /data/local/tmp/test_init*属性值存在 文件存在确认脚本逻辑完整走通5.2 一个真实排障案例现象getprop test.prop始终为空logcat -s TEST_INIT无输出排查Step1ls -Z显示标签是shell_data_file→file_contexts路径写错应为/system/bin/init\.test\.sh而非/system/bin/init.test.sh少转义点Step2修正后重编译烧写getprop init.svc.test_service仍无输出Step3logcat -b events发现boot_completed1已触发 → 触发正常Step4检查init.xxx.rc发现seclabel行缩进用了Tab → 整个service块被忽略修复缩进后getprop init.svc.test_service显示running日志立即出现这就是典型的“多层拦截”必须逐层验证不能跳步。6. 总结开机脚本执行失败的五大根因与应对清单真正让脚本“不执行”的从来不是某一行代码写错而是整个启动链路上某个环节彻底断开。根据上百次实测排障经验我们归纳出最常发生的五类根因并给出可立即执行的检查清单6.1 根因清单与速查表根因类别典型表现一句话诊断命令立即修复建议Shell路径错误dmesg无avc日志logcat无任何输出手动执行报No such file or directoryadb shell ls -l /system/bin/sh改shebang为#!/system/bin/sh重新pushSELinux标签缺失dmesg大量avc denied日志ls -Z显示非test_service_execadb shell ls -Z /system/bin/init.test.sh检查file_contexts正则确认路径转义重刷sepolicyinit.rc语法错误getprop init.svc.test_service无输出logcat -b events有boot_completedadb shell cat /proc/last_kmsg | grep test_service检查缩进4空格、oneshot位置、路径空格用标准模板重写触发时机不当脚本执行但/data未挂载导致touch失败adb shell getpropgrep vold.decrypt脚本内部命令失效log -t有输出但setprop不生效touch失败adb shell /system/bin/sh -x /system/bin/init.test.sh替换source为.若支持用printf替代echo -n所有路径绝对化6.2 给新手的三条铁律铁律一永远先手动验证再依赖开机adb shell /system/bin/init.test.sh能跑通才是脚本正确的起点否则一切优化都是空中楼阁。铁律二日志是唯一真相不要猜dmesg | grep avc看SELinuxlogcat -s TEST_INIT看脚本getprop init.svc.xxx看service状态——三者结合99%问题可定位。铁律三用最小闭环验证每一步不要一上来就写100行脚本。先写setprop test.prop 1验证能设置属性再加log -t验证能打日志最后加文件操作。层层递进稳扎稳打。当你下次再遇到“脚本不执行”请打开这篇清单按顺序执行五步闭环。你会发现所谓玄学问题不过是几个确定性极强的工程细节没对齐而已。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。