乌兰察布市网站建设_网站建设公司_UI设计_seo优化
2026/1/22 5:06:23 网站建设 项目流程

手把手教你写Android开机启动shell脚本(附完整流程)

在Android系统开发中,有时我们需要让某些操作在设备开机时自动执行,比如设置系统属性、启动守护进程、初始化配置文件等。实现这一目标最常见的方式就是编写一个开机启动的Shell脚本,并通过系统init机制触发。

本文将带你从零开始,完整走一遍如何在Android 8.0系统上编写并部署一个开机自启的Shell脚本,涵盖脚本编写、SELinux权限配置、init.rc注册和调试技巧,确保你能在真实项目中顺利落地。


1. 明确目标与适用场景

我们这次要实现的目标是:

编写一个简单的Shell脚本,在Android设备开机时自动运行,并通过setprop设置一个系统属性,用于后续服务或应用识别启动状态。

这种方案适用于以下场景:

  • 需要在系统启动早期执行初始化命令
  • 要为Native服务准备环境变量或标记位
  • 替代复杂C++ native service的轻量级替代方案

整个流程分为四个核心步骤:

  1. 编写可执行的Shell脚本
  2. 将脚本纳入系统镜像
  3. 在init进程中注册服务
  4. 配置SELinux策略允许执行

下面一步步来操作。


2. 编写开机启动Shell脚本

2.1 创建脚本文件

在你的Android源码目录下创建脚本文件,例如:

device/yourcompany/yourproduct/init.test.sh

内容如下:

#!/system/bin/sh # # 开机启动测试脚本 # # 设置一个测试属性,表示脚本已执行 setprop test.boot.script.ready 1 # 可选:输出日志便于调试 log -t "InitScript" -p i "Test boot script executed successfully" # 如果需要做更多事情,可以继续添加命令 # mount /data/vendor/settings /mnt/shared # cp /vendor/etc/config.default /data/vendor/config

2.2 注意事项

  • Shebang必须正确:Android系统使用的是/system/bin/sh,不是Linux常见的/bin/sh
  • 不要随意创建文件:建议先用setprop验证流程,避免因目录权限问题导致失败
  • 脚本需可执行:确保最终打包进系统后有执行权限(x权限)

3. 将脚本打包进系统镜像

为了让脚本在开机时可用,必须将其编译进vendor分区或system分区。推荐放在vendor/bin下。

3.1 添加脚本到Android.mk或Android.bp

如果你使用的是Android.mk,在对应产品目录添加:

# Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := init.test.sh LOCAL_SRC_FILES := init.test.sh LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_EXECUTABLES) LOCAL_MODULE_TAGS := optional LOCAL_LICENSE_KINDS := notice LOCAL_LICENSE_CONDITIONS := by_exception_only LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE include $(BUILD_PREBUILT)

如果是Android.bp

# Android.bp cc_prebuilt_binary { name: "init.test.sh", srcs: ["init.test.sh"], owner: "your_company", relative_install_path: "bin", vendor: true, executable: true, group_defaults: ["hide_from_make"], }

这样脚本会被打包进/vendor/bin/init.test.sh,并在系统启动时可用。


4. 在init.rc中注册启动服务

Android系统的启动由init进程控制,它会解析.rc文件来启动服务。我们需要在这里注册我们的脚本服务。

4.1 不要直接修改init.rc

官方不建议直接修改根目录下的init.rc,而是应该使用厂商提供的扩展文件,如:

init.yourproduct.rc

创建该文件(如果不存在):

device/yourcompany/yourproduct/init.yourproduct.rc

添加以下内容:

service test_boot_script /vendor/bin/init.test.sh class main user root group root oneshot disabled seclabel u:r:test_service:s0
参数说明:
属性说明
class main归属main类,随系统主流程启动
user/group root以root身份运行(根据需求调整)
oneshot只运行一次,适合初始化脚本
disabled初始不启用,需通过trigger启动或显式enable
seclabel指定SELinux上下文,需与te文件匹配

注意:有些平台会在on property sys.boot_completed=1之后才触发,若需更早执行,请检查property依赖。

你可以选择在某个阶段自动启动,例如:

on property:sys.init_boot_completed=1 start test_boot_script

或者手动调试时通过adb启动:

adb shell start test_boot_script

5. 配置SELinux权限(关键步骤)

这是最容易出错的部分。即使关闭了SELinux enforcing模式,Android仍可能阻止脚本执行,尤其是从init启动的服务。

5.1 创建SELinux策略文件

在MTK或其他平台常用路径:

device/mediatek/sepolicy/basic/non_plat/

新建两个文件:

(1)test_service.te
# 定义类型 type test_service, coredomain; # 可执行文件类型 type test_service_exec, exec_type, file_type, vendor_file_type; # 允许init域启动这个服务 init_daemon_domain(test_service) # 可选:放开调试限制 # permissive test_service;
(2)file_contexts

在同一目录的file_contexts文件中添加:

/(system\/vendor|vendor)/bin/init\.test\.sh u:object_r:test_service_exec:s0

这行的作用是:告诉SELinux,这个脚本文件属于test_service_exec类型。

5.2 SELinux调试技巧

如果脚本没执行,先看有没有SELinux拒绝日志:

adb logcat | grep avc # 或 dmesg | grep avc

常见错误示例:

avc: denied { execute } for name="init.test.sh" dev="mmcblk0pXX" ...

说明缺少执行权限,需要补充allow规则,例如:

allow init test_service_exec:file execute; allow init test_service:process transition;

但更推荐使用init_daemon_domain()宏,它已经包含了大部分必要权限。


6. 编译与烧录验证

完成以上步骤后,进行完整编译:

m init.test.sh # 或全编 m -j32

烧录镜像后重启设备:

adb reboot

等待开机完成后,检查属性是否设置成功:

adb shell getprop test.boot.script.ready

预期输出:

1

同时查看日志:

adb logcat -s InitScript

应能看到:

InitScript: Test boot script executed successfully

7. 常见问题与解决方案

7.1 脚本没有执行,无任何反应

  • 检查init.yourproduct.rc是否被正确包含(grep service_name init.log)
  • 查看dmesg | grep avc是否有SELinux拦截
  • 确认脚本路径是否正确(/vendor/bin/init.test.sh是否存在?)
  • 使用ls -Z /vendor/bin/init.test.sh查看SELinux标签是否匹配

7.2 提示“Permission denied”但SELinux未报错

  • 检查脚本是否具有可执行权限:chmod 755 init.test.sh
  • 确保Android.mk/BP中设置了正确的executable: trueEXECUTABLE类型

7.3 脚本能手动执行,但开机无法运行

  • 手动执行可能是shell用户权限,而init是以特定context运行
  • 必须配置SELinux策略,否则会被静默阻止
  • 推荐开启permissive test_service临时调试,确认逻辑没问题后再收紧策略

8. 进阶建议与最佳实践

8.1 更安全的做法:非root用户运行

除非必要,不要以root身份运行脚本。可以改为:

user system group system

并确保操作的文件路径对该用户可访问。

8.2 使用property触发后续动作

利用setprop作为信号,通知其他服务启动:

setprop service.mydaemon.start 1

然后在init.rc中监听:

on property:service.mydaemon.start=1 start my_daemon_service

实现解耦。

8.3 日志输出建议

使用log命令写入kernel log buffer:

log -t "MyScript" -p i "Starting initialization..."

可通过logcat -b events查看。


9. 总结

9.1 核心流程回顾

我们完成了Android开机启动Shell脚本的完整部署流程:

  1. 编写脚本:使用正确的shebang和简单逻辑
  2. 打包进系统:通过Android.mk/BP编译到/vendor/bin
  3. 注册init服务:在.rc文件中声明service条目
  4. 配置SELinux:定义type、file_context、权限策略
  5. 编译验证:烧录后检查属性和日志确认执行

9.2 关键点提醒

  • SELinux是最大拦路虎,务必提前配置
  • 不要直接改init.rc,使用厂商扩展文件
  • 先用setprop测试,再做复杂操作
  • 多用avc:日志定位权限问题

9.3 实际应用场景拓展

此方法可用于:

  • 初始化硬件配置
  • 挂载特殊分区
  • 启动自定义守护进程
  • 设置系统行为标志位

掌握这套流程后,你就可以灵活地在系统启动早期插入自己的逻辑,为后续功能打下基础。


获取更多AI镜像

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询