当前位置: 首页 > news >正文

Android平台开机启动shell脚本,快速落地实践

Android平台开机启动shell脚本,快速落地实践

在Android系统开发中,让自定义脚本在设备启动时自动运行是一项常见但容易踩坑的需求。无论是调试验证、环境初始化,还是硬件检测、服务预加载,一个稳定可靠的开机启动机制都至关重要。但很多开发者反馈:脚本写好了却没执行、SELinux报错卡住、init.rc修改后不生效、push进去能跑但开机就失效……这些问题往往不是逻辑错误,而是Android特有的启动流程和安全机制没对齐。

本文不讲抽象原理,不堆砌术语,只聚焦“怎么让一个shell脚本真正在Android 8.0+设备上稳稳跑起来”。所有步骤均基于真实MTK平台实测(Android 9/10/11),适配主流AOSP及厂商定制系统,覆盖从脚本编写、权限配置、init集成到问题排查的完整闭环。你不需要是SELinux专家,也不用翻遍整个sepolicy目录——只要按顺序操作,15分钟内就能看到getprop test.prop返回预期值。

1. 明确目标与前提条件

1.1 你要实现什么

  • 脚本在系统完成基本初始化后自动执行一次(非常驻服务)
  • 执行结果可通过getprop或日志验证
  • 不依赖ADB连接,断电重启后依然有效
  • 避免因SELinux拒绝、路径错误、权限不足导致静默失败

1.2 你需要准备什么

  • 一台已解锁Bootloader的Android设备(推荐使用用户调试版或工程机)
  • ADB调试环境正常(用于推送、验证、日志抓取)
  • 编译环境可选:若需修改init.rcfile_contexts,需有对应平台的源码或可编辑镜像;若仅测试,可用adb root && adb remount临时挂载修改
  • 基础Linux shell知识(会写#!/system/bin/shsetproplog即可)

关键提醒:Android 8.0+默认启用强制SELinux模式,关闭SELinux(setenforce 0)仅用于快速验证,不能作为最终方案。本文所有步骤均在enforcing模式下通过测试。

2. 四步极简落地流程

我们把整个过程压缩为四个清晰、可验证、可回退的步骤。每一步完成后都有明确的验证方式,避免“以为成功实则失败”。

2.1 第一步:编写并本地验证shell脚本

脚本必须满足三个硬性要求:解释器路径正确、无语法错误、不依赖未就绪环境。

新建文件init.test.sh,内容如下:

#!/system/bin/sh # 注意:Android系统默认shell路径是 /system/bin/sh,不是 /bin/sh 或 /system/xbin/sh # 若设备为64位且/system/xbin/sh存在,也可用,但优先用 /system/bin/sh # 开机阶段/system分区已挂载,/data可能尚未就绪,避免写入/data # 推荐用setprop记录状态,轻量且可跨进程读取 setprop test.boot.status "started" log -t INIT_TEST "Script executed: $(date)" # 示例:创建临时标记(仅用于验证,实际项目请勿滥用) echo "booted_at_$(date +%s)" > /dev/null 2>&1 # 可选:触发后续动作,如启动服务 # am startservice -n com.example/.BootService exit 0

验证方法(务必执行)

# 推送脚本到设备可执行目录 adb push init.test.sh /data/local/tmp/ adb shell chmod +x /data/local/tmp/init.test.sh # 手动执行并检查输出 adb shell "/data/local/tmp/init.test.sh" adb shell getprop test.boot.status # 应输出 "started" adb logcat -t INIT_TEST -d # 查看日志是否打印

验证通过标志:getprop返回值正确,logcat可见时间戳日志。

常见失败原因:

  • sh: /data/local/tmp/init.test.sh: not found→ 解释器路径错误或脚本编码含BOM
  • Permission deniedchmod未执行或目标目录不可执行(/data/local/tmp安全)
  • setprop: permission denied→ SELinux未放行或属性未在property_contexts中声明(本例无需声明,属系统属性)

2.2 第二步:配置SELinux策略(te文件 + file_contexts)

Android 8.0+启动服务必须通过SELinux策略授权。跳过此步,脚本在init.rc中会被直接拒绝,无任何日志提示。

创建test_service.te策略文件
# test_service.te # 定义新域类型 type test_service, domain; 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 }; # 允许设置系统属性(关键!) allow test_service system_file:file { read }; allow test_service property_socket:sock_file { write }; allow test_service self:capability { setuid setgid };

说明:相比参考博文中的简化版,本策略显式声明了setprop所需权限(property_socketsystem_file),避免因属性写入失败导致静默退出。

file_contexts中声明脚本文件类型

找到设备对应平台的file_contexts文件(常见路径:device/mediatek/sepolicy/basic/non_plat/file_contextsvendor/xxx/sepolicy/file_contexts),添加一行:

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

注意正则转义.sh中的点号需用\.转义,否则匹配任意字符。

若无法修改源码,可临时用ADB注入(仅限调试):

adb shell su -c 'echo "/system/bin/init\.test\.sh u:object_r:test_service_exec:s0" >> /sepolicy'

验证SELinux配置

# 检查脚本文件是否获得正确上下文 adb shell ls -Z /system/bin/init.test.sh # 正确输出应包含:u:object_r:test_service_exec:s0 # 检查策略是否加载(需root) adb shell su -c 'sesearch -A -s test_service | grep -E "(execute|property)"'

验证通过标志:ls -Z显示test_service_execsesearch输出含executeproperty_socket相关规则。

2.3 第三步:集成到init启动流程

不要直接修改/system/etc/init.rc(易被OTA覆盖),优先使用厂商提供的扩展入口。MTK平台通常提供init.mtXXX.rcinit.project.rc;高通平台常用init.qcom.rc

在对应init.XXX.rc中添加服务声明
# service test_service /system/bin/init.test.sh service test_service /system/bin/init.test.sh class main user root group root oneshot seclabel u:object_r:test_service_exec:s0 disabled # 初始禁用,避免冲突

关键参数说明

  • oneshot:执行完即退出,适合初始化脚本
  • seclabel:必须与file_contexts中声明的类型一致
  • disabled:防止与其他服务冲突,后续启用
启用服务(两种方式任选)

方式一:通过init命令动态启用(推荐首次测试)

adb shell su -c 'start test_service' adb shell getprop test.boot.status # 立即验证

方式二:修改rc文件启用(长期生效)
disabled行删除或改为enable,然后重启设备。

验证通过标志:重启后getprop test.boot.status返回started,且logcat -b events | grep boot可见服务启动记录。

2.4 第四步:开机自启验证与日志追踪

单纯看getprop不够,需确认脚本确实在开机早期执行。

抓取完整启动日志
# 清空日志缓冲区 adb logcat -c # 重启设备 adb reboot # 重启后立即抓取events和main日志(关键!) adb logcat -b events -b main -v threadtime | grep -E "(test|INIT_TEST|test_service)" > boot_log.txt
日志关键线索识别
  • init: starting service 'test_service'...→ init已识别服务
  • test_service: I/INIT_TEST(XXXX): Script executed: ...→ 脚本成功执行
  • init: Service 'test_service' (pid XXXX) exited with status 0→ 正常退出

若日志中出现avc: denied,说明SELinux仍有缺失权限,根据avc行提示补充test_service.te

3. 常见问题速查与修复指南

以下问题均来自真实项目踩坑记录,按发生频率排序,附带一键修复命令。

3.1 脚本完全不执行(无任何日志)

现象最可能原因快速诊断命令修复方案
getprop无返回,logcat无INIT_TESTinit.rc未加载或服务名拼写错误adb shell su -c 'ls /system/etc/init/*.rc | xargs grep test_service'确认rc文件路径正确,服务名全小写无空格
init: cannot find '/system/bin/init.test.sh'脚本未放入/system/bin/或路径权限错误adb shell ls -l /system/bin/init.test.shadb push init.test.sh /system/bin/ && adb shell chmod 755 /system/bin/init.test.sh
init: service 'test_service' is disabledrc文件中残留disabledadb shell su -c 'grep -n "test_service" /system/etc/init/*.rc'删除disabled行或执行adb shell su -c 'start test_service'

3.2 SELinux拒绝执行(avc denied)

典型日志:avc: denied { execute } for path="/system/bin/init.test.sh" dev="dm-0" ino=12345 scontext=u:r:init:s0 tcontext=u:object_r:unlabeled:s0 tclass=file permissive=0

问题类型修复命令说明
文件上下文未生效adb shell su -c 'restorecon -v /system/bin/init.test.sh'强制重置SELinux上下文
策略未编译进sepolicyadb shell su -c 'sepolicy-inject -s init -t test_service -c process -p transition -l'临时注入策略(调试用)
缺少关键权限test_service.te中追加:
allow test_service self:process { fork execmem };
allow test_service sysfs:dir { read getattr open };
根据avc日志中tclass{ ... }内容精准添加

3.3 属性设置失败(setprop permission denied)

即使脚本执行,setprop仍失败,日志显示avc: denied { set } for property="test.boot.status"

根本原因:Android 8.0+对属性名有严格白名单,自定义属性必须在property_contexts中声明。

临时解决(调试)

adb shell su -c 'setprop persist.test.boot.status "started"' # persist.* 属性无需额外声明,且重启后仍保留

正式方案
system/sepolicy/public/property_contexts中添加:

test\.boot\.status u:object_r:default_prop:s0

重新编译sepolicy并刷入。

4. 工程化建议与安全边界

落地只是开始,生产环境需考虑可维护性与安全性。

4.1 脚本设计最佳实践

  • 路径安全:只读取/system/vendor,避免写/data(可能未挂载)或/cache(可能被清理)
  • 超时控制:添加timeout 30s包裹关键命令,防止单点阻塞整个启动流程
  • 幂等设计:脚本多次执行应无副作用,例如用[ -f /tmp/boot_done ] || { ...; touch /tmp/boot_done; }
  • 日志分级:用log -t INIT_TEST -p i "info"log -t INIT_TEST -p e "error"区分级别,便于过滤

4.2 SELinux策略最小化原则

永远遵循“最小权限”:

  • 不要轻易取消注释permissive test_service;(这等于关闭防护)
  • sesearch -A -s test_service定期审计已授权权限,移除未使用的规则
  • 生产环境禁用allow test_service self:capability { dac_override };(绕过文件权限)

4.3 OTA升级兼容性保障

  • 将脚本和rc片段放入/vendor分区(如/vendor/bin/init.test.sh+/vendor/etc/init/vendor.test.rc),避免被系统OTA覆盖
  • 使用import /vendor/etc/init/*.rc在主init.rc中引入,保持主流程干净

5. 总结:从“能跑”到“稳跑”的关键跃迁

本文带你走完了Android开机启动shell脚本的完整落地链路。回顾核心要点:

  • 脚本本身不是难点,难点在于理解Android启动时序与SELinux约束的耦合关系
  • 验证必须前置:每一步都提供可执行的验证命令,杜绝“以为成功”的假象
  • SELinux不是黑箱avc denied日志就是说明书,结合sesearch可精准定位缺失权限
  • 生产环境必须隔离/vendor分区存放、persist.属性替代、oneshot服务设计,三者缺一不可

你现在拥有的不仅是一个init.test.sh,而是一套可复用的Android底层服务集成方法论。无论是添加硬件检测、预热AI模型,还是初始化加密模块,这套流程都能平滑迁移。

下一步,你可以尝试:

  • 将脚本升级为守护进程(fork &+waitpid
  • initctl动态控制服务启停
  • 结合ueventd监听硬件事件触发脚本

真正的Android系统能力,始于对启动流程的掌控。


获取更多AI镜像

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

http://www.jsqmd.com/news/328669/

相关文章:

  • 信号处理仿真:语音信号处理_(18).语音信号处理的Python实现
  • 免费办公批处理:含图片压缩重命名格式转换
  • 互联网大厂Java面试实战:核心技术与业务场景深度解析
  • 推荐PDF转Excel工具,转换效果鸡佳
  • 图片转Excel工具:OCR识别批量处理
  • 如何实现的就是Deep Agent 任务规划(Planner)
  • 半桥LLC仿真模型:MATLAB/Simulink实战之旅
  • 2026年北京商用清洁机器人品牌排名,哪家性价比高值得选购
  • 别再瞎找了!AI论文工具 千笔写作工具 VS 学术猹,本科生专属首选!
  • 导师严选10个降AIGC网站 千笔·降AIGC助手解决AI率过高痛点
  • 2026年安徽江苏等地充电桩制造商资质全排名,推荐靠谱品牌
  • AI简历项目(概括)
  • 真的太省时间了!AI论文写作软件 千笔 VS 云笔AI,研究生必备神器!
  • 2000-2024年上市公司客户、供应商集中度
  • 免费抽奖软件支持内定名单+防重复中奖
  • 2026晶抗生物评测:品质卓越,助力科研新突破,人试剂盒/晶抗生物/鱼试剂盒/小鼠试剂盒,晶抗生物公司口碑推荐
  • Java计算机毕设之基于Java Web的毕业设计选题管理系统的设计与实现基于java+springboot的Web的毕业设计选题系统(完整前后端代码+说明文档+LW,调试定制等)
  • 实测对比后 9个AI论文网站测评:专科生毕业论文写作必备工具推荐
  • 26-01
  • 【课程设计/毕业设计】基于Java Web的毕业设计选题管理系统的设计与实现基于Java的毕业设计管理系统的设计与实现【附源码、数据库、万字文档】
  • AI短剧生成初探
  • 深入解析:CTFHub XSS通关1:反射型
  • 【课程设计/毕业设计】基于springboot+bs架构的浙江艾艺塑业设计公司网站设计与实现【附源码、数据库、万字文档】
  • 2026年东莞口碑好的服务不错的吊装搬迁公司有哪些
  • 2026年商用清洁机器人品牌排名出炉,性价比高的Top10
  • 2026年东莞搬家公司推荐,大众搬家拆装家具要收费吗
  • 计算机Java毕设实战-基于Java Web的毕业设计选题管理系统的设计与实现基于SpringBoot+Vue的毕业设计选题管理系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 讲讲充电桩安装专业组织哪家靠谱,用户评价来参考
  • 2026热点风暴:如何将黄金暴跌、NBA交易变测试实战指南?
  • 手机 App 跨平台框架统一目录构建