2026/2/10 7:30:05
网站建设
项目流程
绿色调网站,秦皇岛建设管理中心网站,怎么创建一个软件平台,龙岩做网站多少钱Android系统级脚本入门#xff1a;测试开机启动脚本详细教程
在Android开发和系统定制过程中#xff0c;经常需要让某些服务或逻辑在设备启动完成时自动运行。比如预装应用的初始化、硬件状态检测、日志收集、网络配置等。这类需求最直接可靠的实现方式#xff0c;就是编写…Android系统级脚本入门测试开机启动脚本详细教程在Android开发和系统定制过程中经常需要让某些服务或逻辑在设备启动完成时自动运行。比如预装应用的初始化、硬件状态检测、日志收集、网络配置等。这类需求最直接可靠的实现方式就是编写一个开机启动脚本并将其集成进系统初始化流程中。但很多刚接触Android底层的同学会发现写个shell脚本不难可一放到init.rc里就报错、卡住、甚至无法开机——问题往往不出在脚本本身而在于Android 8.0引入的严格Selinux策略、init语法变更、执行上下文限制等系统级约束。本文不是泛泛而谈“怎么写shell”而是聚焦一个真实可用的最小闭环从零开始手把手带你完成一个经过实测验证的开机启动脚本覆盖环境准备、脚本编写、Selinux适配、init集成、调试验证全流程。所有步骤均基于Android 8.0及以上版本含主流MTK/高通平台无需root、不依赖ADB shell持久化真正“烧录即生效”。你不需要熟悉Selinux规则细节也不用翻遍AOSP源码只需要按顺序操作就能看到getprop test.prop返回你设定的值——这是开机脚本成功执行的最直观证据。1. 明确目标与前置条件1.1 你要学会什么编写一个能在Android系统启动早期阶段稳定执行的shell脚本理解Android init机制中service声明的关键字段含义oneshot、user、seclabel等掌握Selinux权限适配的最小必要操作te文件 file_contexts学会用getprop和logcat快速验证脚本是否真正触发避开常见坑点路径错误、shell解释器不匹配、Selinux拒绝、init语法不兼容1.2 你需要准备什么一台已解锁Bootloader的Android设备推荐使用开发板或工程机避免量产机锁区AOSP或芯片厂商提供的完整Android源码至少包含system/core/init、external/sepolicy、device/xxx/sepolicy目录编译环境Linux主机安装repo、JDK、Python等基础工具基础Linux命令能力adb、push、reboot、getprop、logcat注意本文不涉及ADB临时启动或su提权方案。我们做的是真正的系统级开机脚本它随系统镜像固化重启后自动生效是OEM/ODM厂商的标准做法。2. 编写可执行的开机脚本2.1 脚本内容与关键细节新建一个文件命名为init.test.sh内容如下#!/system/bin/sh # 开机脚本必须以正确的shebang开头 # Android系统默认shell路径为 /system/bin/sh非 /bin/sh # 错误路径会导致init直接跳过执行且无明显报错 # 设置一个系统属性作为执行标记最轻量、最安全的验证方式 setprop test.prop init_test_ran_at_$(date %s) # 可选记录日志到kernel log便于logcat抓取 log -t INIT_TEST Script executed successfully. Prop set to $(getprop test.prop) # 可选创建一个临时标记文件仅用于调试生产环境建议避免写文件 # touch /data/local/tmp/init_test_done2.2 为什么这样写小白也能懂的原理#!/system/bin/sh是硬性要求Android的init进程只认这个路径下的解释器。写成/bin/sh或/system/xbin/sh在部分设备上会失败。setprop是首选验证手段它不依赖文件系统权限、不产生磁盘IO、不会因/data未挂载而失败且可通过adb shell getprop test.prop秒级确认。log -t比echo更可靠echo输出到stdout在init上下文中不可见而log命令会写入kernel log bufferlogcat -b events -t INIT_TEST即可捕获。注释掉touch行是经验之谈早期Android中/data可能尚未挂载写文件极易导致init卡死或崩溃。2.3 手动验证脚本是否可运行在push进设备前请先本地测试语法# 在Linux主机上模拟执行需有android-tools或busybox sh -n init.test.sh # 检查语法错误然后推送到设备手动运行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 adb shell getprop test.prop # 应输出类似 init_test_ran_at_1715678901只有这一步成功才能进入下一步。如果失败请回头检查shebang路径、换行符必须是LF、是否有多余空格。3. 为脚本配置Selinux权限3.1 为什么必须加Selinux一句话说清Android 8.0起默认启用enforcing模式的Selinux。init进程以u:r:init:s0身份运行它不能随意执行任意文件。你的脚本若没有对应file_type和domain定义init会静默拒绝执行——连log都不会打。这不是bug是设计。所以必须显式声明“这个脚本允许被init调用”。3.2 创建te策略文件test_service.te在源码目录下新建文件device/your_company/your_platform/sepolicy/non_plat/test_service.te内容如下# 定义一个新的域domain代表这个服务的执行上下文 type test_service, domain; # 定义该服务可执行的文件类型 type test_service_exec, exec_type, vendor_file_type, file_type; # 允许init域init_daemon_domain切换到test_service域 init_daemon_domain(test_service); # 允许test_service域读取/执行自己的文件 allow test_service test_service_exec:file { read open getattr execute }; # 允许test_service向property_service写属性关键否则setprop失败 allow test_service property_service:property_service { set };说明init_daemon_domain(test_service)是核心宏它自动赋予test_service域访问/dev/*、/proc/*、property_service等init必需资源的权限比手动写几十行allow更安全简洁。3.3 关联文件路径与类型file_contexts编辑device/your_company/your_platform/sepolicy/non_plat/file_contexts在末尾添加一行/system/bin/init\.test\.sh u:object_r:test_service_exec:s0注意路径必须用正则转义\.否则匹配失败路径要与你实际存放位置完全一致本文用/system/bin/若放/vendor/bin/则需改路径s0是MLS级别保持默认即可3.4 验证Selinux配置是否生效编译后刷机执行adb shell ls -Z /system/bin/init.test.sh # 正确输出应包含u:object_r:test_service_exec:s0如果显示u:object_r:shell_exec:s0或报错说明file_contexts未生效或路径不匹配。4. 将脚本集成进init启动流程4.1 不要直接修改init.rc正确做法是新建init.XXX.rc主流芯片平台MTK/高通/展锐都预留了客户自定义rc文件入口。例如MTK平台device/mediatek/common/init/init.mtk.rc或device/mediatek/sepolicy/basic/non_plat/init.mtk.rc高通平台device/qcom/common/rootdir/etc/init.qcom.rc找到对应位置在其中添加# service name pathname [argument] ... # class name # user username # group groupname [groupname] ... # oneshot # seclabel u:object_r:test_service_exec:s0 service test_service /system/bin/init.test.sh class main user root group root oneshot seclabel u:object_r:test_service_exec:s04.2 各字段作用通俗解读字段作用为什么这么设class main归入main类确保在on early-init之后、on init期间启动main类是绝大多数服务的默认归属时机稳妥user rootgroup root以root身份运行开机脚本常需访问硬件节点、设置系统属性非root不可oneshot执行完即退出不常驻我们的脚本是单次任务设prop无需后台守护seclabel强制指定执行域与te文件中的test_service_exec对应Selinux强制要求缺一不可提示不要加start test_service。init.rc中service声明本身不触发执行需由on触发器如on boot启动。oneshot服务通常由on property:或on boot隐式触发。4.3 确保触发时机可选增强如果你希望脚本在某个明确事件后执行比如sys.boot_completed1可在同一rc文件中添加on property:sys.boot_completed1 start test_service但对简单设prop场景class main已足够——init会在on init阶段自动启动所有main类oneshot服务。5. 编译、刷机与最终验证5.1 编译命令以全编译为例# 进入源码根目录 source build/envsetup.sh lunch your_target-userdebug m -j16 # 编译整个系统含sepolicy、init、system分区Sepolicy编译会自动合并non_plat目录下所有.te和.fc文件无需额外操作。5.2 刷机与验证步骤将生成的system.img刷入设备使用fastboot或烧录工具重启设备adb reboot等待开机完成约1~2分钟执行验证# 检查属性是否已设置最直接证据 adb shell getprop test.prop # 正常应输出init_test_ran_at_1715678901 # 查看init日志确认服务是否启动 adb logcat -b events | grep -i test_service # 查看kernel log中的自定义日志 adb logcat -b kernel | grep -i INIT_TEST5.3 常见问题速查表现象可能原因快速排查方法getprop test.prop无输出脚本根本没执行adb logcat -b eventslogcat中出现avc: deniedSelinux权限缺失adb logcat -b events设备卡在开机动画init语法错误或脚本崩溃串口连接看kernel panic或init segfault信息ls -Z显示类型错误file_contexts未生效或路径不匹配检查路径是否带转义、是否在正确non_plat目录、是否clean编译6. 进阶建议与安全提醒6.1 生产环境优化建议避免硬编码路径用/system/bin/sh而非/system/xbin/sh前者在所有Android版本中稳定存在。增加错误处理在脚本中加入if [ $? -ne 0 ]; then log -t INIT_TEST Failed; fi。日志分级用log -p iinfo、log -p eerror替代统一-t便于过滤。精简执行逻辑开机脚本应尽量短小10行耗时操作建议fork到后台或通过property触发后续服务。6.2 绝对不要做的三件事❌ 不要在脚本中调用reboot、poweroff等危险命令❌ 不要尝试挂载/格式化分区init上下文无此权限且极不安全❌ 不要写入/system分区只读挂载写入失败且可能触发verity校验失败6.3 为什么这个方案比“ADB开机启动”更可靠方案是否随系统固化是否依赖ADB连接是否受USB调试开关影响是否能早于UI启动本文方案init.rc Selinux是❌ 否❌ 否是early-init阶段ADB adb shell❌ 否是是❌ 否需ADB服务已启动pm enableBroadcastReceiver❌ 否❌ 否❌ 否❌ 否需Launcher进程启动真正的系统级自动化始于init止于内核。掌握它你就拿到了Android底层的第一把钥匙。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。