编辑
2025-01-22
工作知识
0
请注意,本文编写于 106 天前,最后修改于 63 天前,其中某些信息可能已经过时。

目录

一、为什么要boot-completed信号
二、systemd的boot_completed信号
三、应用程序如何集成
四、linux的缺陷

对于安卓系统,开机起来之后会全局发送一个BOOT_COMPLETED广播。应用程序通过这个广播就知道系统正常启动完成了。通常情况下,是安卓启动完全完成之后,ams会发送一个FINISH_BOOTING_MSG消息后,开启了30s的timeout检查是否为boot-completed。这里30s是开机动画,如果开机动画正常退出或者超过30s退出,则认为boot-completed。但是,在linux中,我们的系统好像没有利用起来这个机制。

本文基于systemd的默认机制,说明一下linux如何实现boot-completed信号。

一、为什么要boot-completed信号

对于系统而言,应该主动发送boot-completed信号,让其他程序能够获取当前系统的启动状态,如何此信号接收到,则代表系统已经准备完成,ui类型的应用可以运行,可以检测系统是否破损,可以判断系统是否异常等等。

对于安卓,我们可以通过如下获取信号

getprop sys.boot_completed

二、systemd的boot_completed信号

对于systemd,默认提供了类似此机制的信号,如下:

systemctl is-system-running --wait

此方法会一直阻塞,知道systemd认为系统启动完成。引入此功能的patch如下:

https://github.com/systemd/systemd/pull/9796/commits/02d9350cda6b330669607ae88c74ac7256212741

我们可以知道,此命令一直等待的是StartupFinished的dbus信号。

当systemd的一系列jobs都正常处理完成,则发送此信号,我们可以通过list-jobs来查看jobs运行状态,如下:

systemctl list-jobs

三、应用程序如何集成

针对上面提到的,我们可以知道,我们直接监听dbus的StartupFinished信号,那么应用程序就能接收到systemd发送的boot_completed,所以我们借助yocto的工具源码dbus-wait如下:

/* * Copyright (C) 2008 Intel Corporation. * * Author: Ross Burton <ross@linux.intel.com> * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ #include <string.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <unistd.h> #include <dbus/dbus.h> static char *interface, *member, *path; static void alarm_handler (int signum) { fprintf(stderr, "Timeout waiting for %s.%s\n", interface, member); exit (EXIT_SUCCESS); } static DBusHandlerResult filter (DBusConnection *conn, DBusMessage *message, void *user_data) { /* If the interface matches */ if (strcmp (interface, dbus_message_get_interface (message)) == 0) /* And the member matches */ if (strcmp (member, dbus_message_get_member (message)) == 0) /* And the path is NULL or matches */ if (path == NULL || strcmp (path, dbus_message_get_path (message)) == 0) /* Then exit */ exit (EXIT_SUCCESS); return DBUS_HANDLER_RESULT_HANDLED; } int main (int argc, char **argv) { DBusError error = DBUS_ERROR_INIT; DBusConnection *conn; char *match = NULL; if (argc < 3 || argc > 4) { fprintf (stderr, "$ dbus-wait <INTERFACE> <MEMBER> [PATH]\n"); return EXIT_FAILURE; } signal (SIGALRM, alarm_handler); alarm (60); /* TODO: allow system or session */ conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error); if (!conn) { fprintf (stderr, "Cannot get system bus: %s\n", error.message); dbus_error_free (&error); return EXIT_FAILURE; } switch (argc) { case 3: interface = argv[1]; member = argv[2]; path = NULL; asprintf (&match, "type='signal',interface='%s',member='%s'", interface, member); break; case 4: interface = argv[1]; member = argv[2]; path = argv[3]; asprintf (&match, "type='signal',interface='%s',member='%s',path='%s'", interface, member, path); break; } dbus_bus_add_match (conn, match, &error); free (match); if (dbus_error_is_set (&error)) { fprintf (stderr, "Cannot add match: %s\n", error.message); dbus_error_free (&error); return EXIT_FAILURE; } dbus_connection_add_filter (conn, filter, NULL, NULL); while (dbus_connection_read_write_dispatch (conn, -1)) ; dbus_connection_unref (conn); return EXIT_SUCCESS; }

编译如下:

gcc dbus-wait.c $(pkg-config --libs --cflags dbus-1)-o dbus-wait

至此,我们可以直接监听此dbus信号如下:

dbus-wait org.freedesktop.systemd1.Manager StartupFinished

四、linux的缺陷

对于通常的boot_completed信号,它只能判断systemd的service是否启动完成。我们知道,对于一个桌面系统而言,systemd服务并不代表系统真实的启动完成,例如ukui-session带起来的一系列应用程序,如果peony未启动,systemd并不能察觉,StartupFinished信号的发送和peony等应用程序的是否正常运行没有产生关联。所以我们需要产生关联。

至此,我们需要在ukui-session中,一边接受此信号,一边等待系统核心应用完成。然后,构造一个完整的boot_completed信号,提供给用户,至此我们在linux中,也具备了boot_completed信号。