记录 | 个人开发库推送至PyPi流程梳理(ChatGPT to Markdown 工具发布完整流程)

核心内容摘要

5个专业配置技巧让你彻底掌握Cemu模拟器性能优化
QGIS符号化实战:从shp文件到GeoServer样式导入全流程

Gemma-3-270m与SolidWorks集成:智能工程设计应用

Android平台开机启动shell脚本快速落地实践在Android系统开发中让自定义脚本在设备启动时自动运行是一项常见但容易踩坑的需求。

无论是调试验证、环境初始化还是硬件检测、服务预加载一个稳定可靠的开机启动机制都至关重要。

但很多开发者反馈脚本写好了却没执行、SELinux报错卡住、init.rc修改后不生效、push进去能跑但开机就失效……这些问题往往不是逻辑错误而是Android特有的启动流程和安全机制没对齐。

本文不讲抽象原理不堆砌术语只聚焦“怎么让一个shell脚本真正在Android

0设备上稳稳跑起来”。

所有步骤均基于真实MTK平台实测Android 9/10/11适配主流AOSP及厂商定制系统覆盖从脚本编写、权限配置、init集成到问题排查的完整闭环。

你不需要是SELinux专家也不用翻遍整个sepolicy目录——只要按顺序操作15分钟内就能看到getprop test.prop返回预期值。

明确目标与前提条件

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

2 你需要准备什么一台已解锁Bootloader的Android设备推荐使用用户调试版或工程机ADB调试环境正常用于推送、验证、日志抓取编译环境可选若需修改init.rc或file_contexts需有对应平台的源码或可编辑镜像若仅测试可用adb root adb remount临时挂载修改基础Linux shell知识会写#!/system/bin/sh、setprop、log即可关键提醒Android

0默认启用强制SELinux模式关闭SELinuxsetenforce 0仅用于快速验证不能作为最终方案。

本文所有步骤均在enforcing模式下通过测试。

四步极简落地流程我们把整个过程压缩为四个清晰、可验证、可回退的步骤。

每一步完成后都有明确的验证方式避免“以为成功实则失败”。

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 21 # 可选触发后续动作如启动服务 # 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→ 解释器路径错误或脚本编码含BOMPermission denied→chmod未执行或目标目录不可执行/data/local/tmp安全setprop: permission denied→ SELinux未放行或属性未在property_contexts中声明本例无需声明属系统属性

2 第二步配置SELinux策略te文件 file_contextsAndroid

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_socket和system_file避免因属性写入失败导致静默退出。

在file_contexts中声明脚本文件类型找到设备对应平台的file_contexts文件常见路径device/mediatek/sepolicy/basic/non_plat/file_contexts或vendor/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输出含execute和property_socket相关规则。

3 第三步集成到init启动流程不要直接修改/system/etc/init.rc易被OTA覆盖优先使用厂商提供的扩展入口。

MTK平台通常提供init.mtXXX.rc或init.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可见服务启动记录。

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.

常见问题速查与修复指南以下问题均来自真实项目踩坑记录按发生频率排序附带一键修复命令。

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.shinit: 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

2 SELinux拒绝执行avc denied典型日志avc: denied { execute } for path/system/bin/init.test.sh devdm-0 ino12345 scontextu:r:init:s0 tcontextu:object_r:unlabeled:s0 tclassfile permissive0问题类型修复命令说明文件上下文未生效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 属性设置失败setprop permission denied即使脚本执行setprop仍失败日志显示avc: denied { set } for propertytest.boot.status根本原因Android

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并刷入。

工程化建议与安全边界落地只是开始生产环境需考虑可维护性与安全性。

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区分级别便于过滤

2 SELinux策略最小化原则永远遵循“最小权限”不要轻易取消注释permissive test_service;这等于关闭防护用sesearch -A -s test_service定期审计已授权权限移除未使用的规则生产环境禁用allow test_service self:capability { dac_override };绕过文件权限

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星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

大象传媒隐藏入口2025版-大象传媒隐藏入口2025版应用

百度百家号客服电话人工服务

123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123