systemd 是一种用于 Linux 操作系统的初始化系统和服务管理器,负责启动和管理系统中的各种服务和进程,由 Lennart Poettering 主导开发并在 LGPL 2.1 及其后续版本许可证下开源发布。systemd 已经广泛被多数主流 Linux 发行版采用,如 Ubuntu、Fedora、Debian。展厅上的i.MX6/8/9系列采用Linux定制版,即Yocto系统,它也采用了systemd管理器。
systemctl命令是systemd系统和服务管理器的命令行工具,通过控制和监视系统的服务和单位文件,提供了对系统进程的强大管理功能。
在开发板上做调试时,有时我们会想把一些命令或脚本文件设置为开机自启动。尤其是在多次开机后运行同一命令观察其结果,设置为开机自启动能提高调试效率。我们可以利用systemd设置命令或脚本文件的开机自启动。
本文档涉及案例包括:
• 利用Systemd设置程序开机自启动
1. 预定开发板在动手实践本应用案例前先预定开发板:(以i.MX8MP为例,i.MX93等同样适用)
2. 如前面所述,systemctl命令是systemd系统和服务管理器的命令行工具。当 Linux 系统启动时,内核会加载并执行第一个用户空间程序,即 systemd。它作为 PID 1 运行,是所有其他进程的父进程。Systemd会读取配置文件,通常配置文件位于/etc/systemd/system下和/lib/systemd/system下,后缀为.service, 按照依赖顺序并行或顺序地启动服务。
systemctl命令的基本语法为:
systemctl [OPTIONS...] COMMAND [UNIT]
其中,OPTIONS是可选参数,用于指定systemctl的行为;COMMAND是必需参数,用于执行特定的systemd命令,如启动、停止或重新启动服务;UNIT是可选参数,用于指定要操作的服务或单元。
例如:
启动服务:
systemctl start 服务名称.service
停止服务:
systemctl stop 服务名称.service
重启服务:
systemctl restart 服务名称.service
查看服务状态:
systemctl satus 服务名称.service
设置服务开机自启动:
systemctl enable服务名称.service
取消服务开机自启动:
systemctl disable服务名称.service
查看所有已启用的服务:
systemctl list-unit-files --state=enabled
重新加载服务配置文件:
当修改了服务的配置文件后,需要执行此命令来重新加载配置文件。
systemctl daemon-reload
1. systemd 设计的单元(Units)是用于描述系统资源和服务的配置文件,它们代表了systemd可以管理的各种不同类型的对象。systemd支持的主要单元类型有:
(1) 服务单元 (.service):这是最常用的单元类型,用于定义系统服务,如守护进程(daemon)及其相关进程。服务单元控制着服务的启动、停止、重载等操作。
(2) 套接字单元 (.socket):用于管理系统中的本地IPC(进程间通信)或网络套接字,支持基于套接字激活服务,即当套接字上有连接请求时自动启动相应服务。
(3) 目标单元 (.target):作为一组单元的集合,用于定义系统状态或运行级别,如多用户目标(multi-user.target)或图形界面目标(graphical.target)。切换目标实际上就是启动或停止与该目标相关联的一组服务。
(4) 设备单元 (.device):代表系统中的硬件设备,可以用于基于设备的激活,即当设备接入或移除时执行特定操作。
除此之外,还有挂载单元 (.mount),路径单元 (.path),计时器单元 (.timer),交换单元 (.swap),自动挂载点单元 (.automount)等。
服务单元 (.service)是最常用的单元类型。以/lib/systemd/system下的psplash-start.service为例,该服务单元会让屏幕在Weston启动之前显示一张open-embedded 图片,
vi /lib/systemd/system/psplash-start.service
[Unit]
Description=Start Psplash Boot Screen
Wants=systemd-vconsole-setup.service
After=systemd-vconsole-setup.service systemd-udev-trigger.service systemd-udevd.service
DefaultDependencies=no
[Service]
ExecStartPre=/bin/sh -c "if [ -e /sys/class/graphics/fbcon/cursor_blink ]; then echo 0 > /sys/class/graphics/fbcon/cursor_blink; fi"
ExecStart=/bin/sh -c "s=$(/usr/sbin/fbset -i -fb /dev/fb0 | grep epdc); if [ -z "$s" ]; then i=0; else i=1; fi; if [ -e /dev/fb$i ]; then /usr/bin/psplash -n
[Install]
.service文件分为三个部分:
(1) [Unit] 部分,描述了单元的元数据和依赖关系。
1) Description:对当前服务的描述。
2) After 和 Before:定义服务的启动顺序,表示当前服务应该在哪些服务之后或之前启动。这两个字段只涉及启动顺序,不涉及依赖关系。
3) Wants:表示当前服务与另一个服务之间存在弱依赖关系。如果另一个服务启动失败或停止运行,不影响当前服务继续执行。
4) Requires:表示当前服务与另一个服务之间存在强依赖关系。如果另一个服务启动失败或异常退出,当前服务也必须退出。
5) Conflicts:定义与当前服务冲突的服务。如果冲突的服务已经启动,那么当前服务就不能启动。
(2) [Service]部分:定义了服务的具体行为。
1) ExecStart:定义服务启动时要执行的命令。可以是单个命令、脚本文件、或者多个命令组成的脚本。
2) ExecStop:定义服务停止时要执行的命令。
3) ExecStartPre 和 ExecStopPost:定义服务启动前和停止后要执行的命令。
4) WorkingDirectory:指定服务的工作目录。
5) User 和 Group:指定服务运行的用户和组。
6) Restart 和 RestartSec:定义服务的重启策略,如是否自动重启、重启间隔等。
(3) [Install]部分:定义了如何将服务安装到系统中。
1) WantedBy 和 RequiredBy:定义哪些服务或目标需要或要求当前服务。
2) Alias:为服务定义别名。
2. 以8MPLUSLPD4-PEVK-3开发板为例,CPU频率默认的策略是ondemand的(平时低速运行,当系统负载提高时按需自动提高频率),我们想设置开机自启动让CPU频率策略为powersave, 即以最低的频率运行。
先查看默认的CPU频率:
cat /sys/kernel/debug/clk/clk_summary|grep arm
能看到大部分时候CPU频率是1.8GHz(最高),偶尔也运行在1.6GHz。如果手动运行以下命令,CPU频率策略为powersave, 即以最低的频率运行:
cpufreq-set -g powersave
可以看到CPU的频率已经变为1.2GHz,为最低频率。
我们现在通过在systemd中新添加一个my service服务,设置CPU频率策略为powersave命令为开机自启动。
首先在/home/root下,创建一个名为cpufreq.sh的脚本文件,并将脚本权限设置为为最高777:
#!/bin/bash
cpufreq-set -g powersave
cpufreq-info
在/etc/systemd/system路径下,创建一个名为myservice.service的文件,内容如下:
[Unit]
Description=My service
After=weston.service
[Service]
ExecStart=/home/root/cpufreq.sh
User=root
[Install]
WantedBy=multi-user.target
ExecStart表示该服务启动时要执行脚本/home/root/cpufreq.sh。
依次运行以下命令:
systemctl daemon-reload
systemctl enable myservice.service
systemctl start myservice.service
之后点击PowerReset-EVK重启开发板,在临近文件系统login时,可以看到My service在Weston service启动后 自启动。查看CPU频率,看到CPU频率已经被设置为最低1.2GHz,证明通过systemd设置程序自启动已经生效。
需要注意的是,当运行
systemctl status myservice
时,会看到myservice的状态是inactive (dead)的,表示该服务已经停止。
这是因为ExecStart 调用的cpufreq.sh 里的命令只是一句命令,不是服务程序也没有设置循环,在开机运行完后就结束了。如果我们修改cpufreq.sh为:
#!/bin/bash
while true;do
cpufreq-set -g powersave
cpufreq-info
done
并依次运行以下命令:
systemctl daemon-reload
systemctl enable myservice.service
systemctl restart myservice.service
后,再运行
systemctl status myservice
去查看,会看到myservice的状态由inactive (dead)变为active。开发板重启,也依旧看看到此状态。
若想取消myservice的自启动,则运行
systemctl disable myservice.service
然后重启,可以看到启动log中“[ OK ] Started My service.”的log消失,查看其状态是disabled和inactive的。