news 2026/1/23 5:17:53

创建简单可 start/stop 的 init 服务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
创建简单可 start/stop 的 init 服务

创建简单可 start/stop 的 init 服务

1. 项目结构

my_simple_service/ ├── Android.bp # 构建配置文件 ├── myservice.cpp # 服务实现 ├── myservice.rc # init 启动配置 └── myservice.h # 头文件(可选)

2. 服务实现代码

myservice.cpp

// 简单的 init 服务示例#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<signal.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<sys/socket.h>#include<sys/un.h>#include<cutils/log.h>#include<utils/Log.h>// 定义日志标签#defineTAG"MySimpleService"#defineLOGI(...)__android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)#defineLOGW(...)__android_log_print(ANDROID_LOG_WARN,TAG,__VA_ARGS__)#defineLOGE(...)__android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)// 全局变量staticvolatilesig_atomic_t g_running=1;// 信号处理函数voidsignal_handler(intsignum){switch(signum){caseSIGTERM:caseSIGINT:LOGI("Received termination signal");g_running=0;break;caseSIGUSR1:LOGI("Received SIGUSR1 for status query");break;}}// 设置信号处理器voidsetup_signals(){structsigactionsa;sa.sa_handler=signal_handler;sigemptyset(&sa.sa_mask);sa.sa_flags=0;sigaction(SIGTERM,&sa,NULL);sigaction(SIGINT,&sa,NULL);sigaction(SIGUSR1,&sa,NULL);// 忽略这些信号,防止意外终止signal(SIGPIPE,SIG_IGN);signal(SIGHUP,SIG_IGN);}// 简单的控制 socket 监听(可选)intsetup_control_socket(constchar*socket_path){intsock_fd=socket(AF_UNIX,SOCK_STREAM,0);if(sock_fd<0){LOGE("Failed to create socket: %s",strerror(errno));return-1;}// 删除可能存在的旧 socket 文件unlink(socket_path);structsockaddr_unaddr;memset(&addr,0,sizeof(addr));addr.sun_family=AF_UNIX;strncpy(addr.sun_path,socket_path,sizeof(addr.sun_path)-1);if(bind(sock_fd,(structsockaddr*)&addr,sizeof(addr))<0){LOGE("Failed to bind socket: %s",strerror(errno));close(sock_fd);return-1;}if(listen(sock_fd,5)<0){LOGE("Failed to listen on socket: %s",strerror(errno));close(sock_fd);return-1;}LOGI("Control socket created at %s",socket_path);returnsock_fd;}// 处理控制命令voidhandle_control_command(intclient_fd){charbuffer[256];ssize_t bytes=read(client_fd,buffer,sizeof(buffer)-1);if(bytes>0){buffer[bytes]='\0';LOGI("Received command: %s",buffer);// 简单的命令处理if(strncmp(buffer,"status",6)==0){constchar*response="Service is running\n";write(client_fd,response,strlen(response));}elseif(strncmp(buffer,"version",7)==0){constchar*response="MySimpleService v1.0\n";write(client_fd,response,strlen(response));}else{constchar*response="Unknown command\n";write(client_fd,response,strlen(response));}}close(client_fd);}// 主服务循环voidservice_loop(){LOGI("MySimpleService starting...");// 设置控制 socket(可选功能)constchar*socket_path="/dev/socket/my_simple_service";intcontrol_socket=setup_control_socket(socket_path);// 设置文件描述符集合用于 selectfd_set read_fds;structtimevaltimeout;while(g_running){// 清空描述符集合FD_ZERO(&read_fds);intmax_fd=0;if(control_socket>=0){FD_SET(control_socket,&read_fds);max_fd=control_socket;}// 设置超时时间(1秒)timeout.tv_sec=1;timeout.tv_usec=0;// 等待事件intresult=select(max_fd+1,&read_fds,NULL,NULL,&timeout);if(result<0){if(errno==EINTR){continue;// 被信号中断}LOGE("select error: %s",strerror(errno));break;}if(result==0){// 超时,可以在这里执行周期性任务staticintcounter=0;if(++counter%10==0){// 每10秒打印一次LOGI("Service is alive, uptime: %d seconds",counter);}continue;}// 检查控制 socket 是否有连接if(control_socket>=0&&FD_ISSET(control_socket,&read_fds)){intclient_fd=accept(control_socket,NULL,NULL);if(client_fd>=0){handle_control_command(client_fd);}}}// 清理资源if(control_socket>=0){close(control_socket);unlink(socket_path);}LOGI("MySimpleService stopping...");}intmain(intargc,char**argv){LOGI("MySimpleService starting with PID %d",getpid());// 设置信号处理器setup_signals();// 守护进程化(可选)if(argc>1&&strcmp(argv[1],"--daemon")==0){if(daemon(0,0)<0){LOGE("Failed to daemonize: %s",strerror(errno));return1;}}// 开始服务循环service_loop();LOGI("MySimpleService exited");return0;}

myservice.rc

# 简单服务的 init 配置文件 # 保存为 /system/etc/init/myservice.rc 或 /vendor/etc/init/myservice.rc # 服务定义 service myservice /system/bin/myservice class core # 在 core 类中启动 user system # 以 system 用户运行 group system # 主组 system group log # 附加组 log(用于写日志) oneshot # 只运行一次,不自动重启 disabled # 默认不自动启动,需要手动 start # SELinux 上下文(可选,需要相应的策略文件) seclabel u:r:myservice:s0 # 重启行为(如果崩溃) # onrestart restart zygote # 如果服务重启,也重启 zygote(示例) # 权限(示例) capabilities DAC_OVERRIDE, SETPCAP # 任务调度配置 task_profiles ServiceCapacityLow # 关键服务标记(如果崩溃,会触发重启到 recovery) # critical # 日志重定向(如果需要) # stderr /dev/kmsg # stdout /dev/kmsg # on 语句:定义触发条件(可选) on property:sys.myservice.enable=1 start myservice on property:sys.myservice.enable=0 stop myservice # 在 boot 完成后启动(如果需要自动启动) on property:sys.boot_completed=1 # 启动条件可以在这里设置 # start myservice

3. 构建配置文件

Android.bp

// Android.bp 构建配置文件 // 编译为可执行文件 cc_binary { name: "myservice", // 源文件 srcs: ["myservice.cpp"], // 编译标志 cflags: [ "-Wall", "-Wextra", "-Werror", "-Wno-unused-parameter", "-DLOG_TAG=\"MySimpleService\"", ], // 共享库依赖 shared_libs: [ "liblog", // Android 日志库 "libcutils", // Android C 工具库 "libutils", // Android 工具库 "libbase", // Android 基础库 "libc", // C 标准库 "libdl", // 动态链接库 ], // 静态库依赖(可选) static_libs: [ // 如果需要特殊功能,可以添加静态库 ], // init_rc 文件:自动安装到系统 init_rc: ["myservice.rc"], // 是否安装到 vendor 分区(可选) // vendor: true, // 模块所有者(用于跟踪) // owner: "myteam", // 测试依赖(可选) // test_suites: ["general-tests"], // data: ["testdata/*"], } // 可选的:创建一个文件组,用于其他地方引用 filegroup { name: "myservice_configs", srcs: [ "myservice.rc", // 可以包含其他配置文件 ], } // 可选的:添加 SELinux 策略文件 // 需要相应的 .te 文件 /* sepolicy_policy { name: "myservice_sepolicy", srcs: ["myservice.te"], } */

4. 使用方法

构建服务

# 在 Android 源码树中构建cd/path/to/android/sourcesourcebuild/envsetup.sh lunch<your_target>makemyservice# 编译后的文件位置# out/target/product/<device>/system/bin/myservice# out/target/product/<device>/system/etc/init/myservice.rc

安装到设备

# 方法1:重新刷写系统镜像makeflashall# 方法2:通过 adb 推送adb root adb remount adb push out/target/product/<device>/system/bin/myservice /system/bin/ adb push out/target/product/<device>/system/etc/init/myservice.rc /system/etc/init/ adb shellchmod755/system/bin/myservice adb shellchmod644/system/etc/init/myservice.rc# 重启 init 进程adb shell stop adb shell start# 或者adb shellpkill-HUP init

测试服务

# 启动服务adb shell start myservice# 检查服务状态adb shellps-A|grepmyservice# 或者adb shell pidof myservice# 查看日志adb logcat|grep-i myservice# 或者adb shell logcat -b all -s MySimpleService# 停止服务adb shell stop myservice# 验证服务已停止adb shellps-A|grepmyservice# 通过控制 socket 通信(如果实现了)adb shellecho"status"|nc-U /dev/socket/my_simple_service

调试技巧

# 1. 查看 init 日志adb shell logcat -b events|grepboot# 2. 查看服务启动失败原因adb shelldmesg|grepmyservice# 3. 检查 SELinux 拒绝adb shelldmesg|grepavc|grepmyservice# 4. 直接运行服务(不通过 init)adb shell /system/bin/myservice --daemon# 5. 发送信号给服务adb shellkill-SIGUSR1$(pidof myservice)

5. 扩展功能

添加系统属性控制

// 在 myservice.cpp 中添加#include<cutils/properties.h>voidcheck_properties(){charvalue[PROPERTY_VALUE_MAX];property_get("sys.myservice.enable",value,"0");if(strcmp(value,"1")==0){LOGI("Service enabled via property");}else{LOGI("Service disabled via property");g_running=0;}}

添加配置文件支持

// 读取配置文件voidload_config(constchar*config_path){FILE*fp=fopen(config_path,"r");if(fp){charline[256];while(fgets(line,sizeof(line),fp)){LOGI("Config line: %s",line);}fclose(fp);}}

创建测试脚本

#!/system/bin/sh# test_myservice.sh# 测试服务启动和停止echo"Testing myservice..."echo"1. Starting service..."start myservicesleep2pid=$(pidof myservice)if[-n"$pid"];thenecho"Service started with PID:$pid"elseecho"Failed to start service"exit1fiecho"2. Sending status query..."echo"status"|nc-U /dev/socket/my_simple_service2>/dev/null||echo"Socket not available"echo"3. Stopping service..."stop myservicesleep1echo"4. Verifying service stopped..."ifpidof myservice>/dev/null;thenecho"ERROR: Service still running"exit1elseecho"SUCCESS: Service stopped properly"fi

6. 完整示例打包

以下是更简洁的版本,适合快速测试:

简化版 myservice_simple.cpp

#include<stdio.h>#include<unistd.h>#include<cutils/log.h>intmain(){ALOGI("SimpleService started");// 简单的循环,每秒打印一次intcount=0;while(1){sleep(1);ALOGI("SimpleService running for %d seconds",++count);// 检查是否应该退出(通过文件系统标志)if(access("/data/myservice_stop",F_OK)==0){ALOGI("Stop flag detected, exiting");unlink("/data/myservice_stop");break;}}ALOGI("SimpleService exiting");return0;}

简化版 myservice_simple.rc

service myservice_simple /system/bin/myservice_simple class core user system oneshot disabled

测试命令

# 启动adb shell start myservice_simple# 查看日志adb logcat -s SimpleService# 停止(通过文件标志)adb shelltouch/data/myservice_stop# 或者强制停止adb shell stop myservice_simple

注意事项

  1. 权限问题:确保服务有足够的权限访问需要的资源
  2. SELinux:如果需要访问特殊资源,需要添加 SELinux 策略
  3. 资源清理:确保服务退出时清理所有资源
  4. 日志轮转:长时间运行的服务需要注意日志大小
  5. 错误处理:添加适当的错误处理和恢复机制
  6. 启动依赖:如果依赖其他服务,需要在 rc 文件中配置

这个简单的服务示例展示了 init 服务的基本结构和用法。你可以根据实际需求扩展功能,如添加配置读取、网络通信、数据库访问等。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/22 14:18:35

PyTorch-CUDA-v2.9镜像支持天文数据处理

PyTorch-CUDA-v2.9镜像支持天文数据处理 在FAST射电望远镜每秒产出数GB原始数据的今天&#xff0c;天文学家面临的早已不是“看得见”而是“算得动”的问题。传统基于CPU的数据分析流程&#xff0c;在面对LSST这类即将每晚生成PB级图像的项目时&#xff0c;几乎寸步难行。而与此…

作者头像 李华
网站建设 2026/1/22 6:19:59

PyTorch-CUDA-v2.9镜像是否支持DP(DataParallel)模式?

PyTorch-CUDA-v2.9镜像是否支持DataParallel模式&#xff1f; 在当前深度学习模型日益庞大的背景下&#xff0c;单块GPU的算力和显存往往难以支撑高效训练。越来越多的研究者与工程师开始依赖多GPU并行策略来加速实验迭代。对于使用容器化环境的团队而言&#xff0c;一个关键问…

作者头像 李华
网站建设 2026/1/22 17:00:04

大模型Token成本太高?用PyTorch-CUDA-v2.9本地推理降本增效

大模型Token成本太高&#xff1f;用PyTorch-CUDA-v2.9本地推理降本增效 在AI应用快速落地的今天&#xff0c;越来越多企业开始部署大语言模型&#xff08;LLM&#xff09;用于智能客服、内部知识库、代码辅助生成等场景。然而&#xff0c;当调用量从每天几百次飙升到数万甚至百…

作者头像 李华
网站建设 2026/1/22 14:41:07

PyTorch-CUDA-v2.9镜像如何集成Weaviate向量数据库?

PyTorch-CUDA-v2.9 镜像如何集成 Weaviate 向量数据库 在构建现代 AI 应用的今天&#xff0c;一个常见的挑战是&#xff1a;如何将深度学习模型输出的高维向量高效地存储起来&#xff0c;并支持毫秒级的相似性检索&#xff1f;尤其是在图像搜索、推荐系统或 RAG&#xff08;检索…

作者头像 李华
网站建设 2026/1/22 14:47:14

PyTorch-CUDA-v2.9镜像中使用TensorBoard可视化训练过程

PyTorch-CUDA-v2.9镜像中使用TensorBoard可视化训练过程 在深度学习项目开发中&#xff0c;一个常见的困境是&#xff1a;模型跑起来了&#xff0c;但你并不知道它“到底发生了什么”。损失曲线震荡&#xff1f;准确率停滞不前&#xff1f;还是梯度已经消失&#xff1f;如果只…

作者头像 李华
网站建设 2026/1/16 20:58:30

ESP32机器狗DIY实战:百元级智能伴侣从零打造

ESP32机器狗DIY实战&#xff1a;百元级智能伴侣从零打造 【免费下载链接】xiaozhi-esp32 Build your own AI friend 项目地址: https://gitcode.com/GitHub_Trending/xia/xiaozhi-esp32 还在为昂贵的机器人套件望而却步吗&#xff1f;今天我要分享一个令人兴奋的项目——…

作者头像 李华