Weston启动流程分析
- Weston是Wayland Compositor的实现。其Server端作为独立的进程运行在系统中。MakeFile中编译成果为,“weston”的可执行程序
- MakeFile.am(weston 2.0.0)
bin_PROGRAMS += weston
weston_LDFLAGS = -export-dynamic
weston_CPPFLAGS = $(AM_CPPFLAGS) -DIN_WESTON \
-DMODULEDIR='"$(moduledir)"' \
-DXSERVER_PATH='"@XSERVER_PATH@"'
weston_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS)
weston_LDADD = libshared.la libweston-@LIBWESTON_MAJOR@.la \
$(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \
$(DLOPEN_LIBS) $(LIBINPUT_BACKEND_LIBS) \
$(CLOCK_GETRES_LIBS) \
-lm
weston_SOURCES = \
compositor/main.c \
compositor/weston-screenshooter.c \
compositor/text-backend.c \
compositor/xwayland.c
启动流程分析
-
流程图:
-
main函数:入口函数。其实现在 weston-2.0.0/compositor/main.c
-
主要内容分析
int main(int argc, char *argv[])
{
// Log日志初始化
weston_log_set_handler(vlog, vlog_continue);
weston_log_file_open(log);
// 启动Log
weston_log("%s\n"
STAMP_SPACE "%s\n"
STAMP_SPACE "Bug reports to: %s\n"
STAMP_SPACE "Build: %s\n",
PACKAGE_STRING, PACKAGE_URL, PACKAGE_BUGREPORT,
BUILD_ID);
// 创建全局唯一的Display
display = wl_display_create();
// 读取weston.ini文件中的配置
if (load_configuration(&config, noconfig, config_file) < 0)
goto out_signals;
// 创建Compositor
ec = weston_compositor_create(display, &user_data);
if (ec == NULL) {
weston_log("fatal: failed to create compositor\n");
goto out;
}
// 加载backend(默认为drm-backend)
if (load_backend(ec, backend, &argc, argv, config) < 0) {
weston_log("fatal: failed to create compositor backend\n");
goto out;
}
// 捕获异常Signal
catch_signals();
if (fd != -1) {
// ...
// 默认走 else if,创建socket
} else if (weston_create_listening_socket(display, socket_name)) {
goto out;
}
// 加载shell
if (wet_load_shell(ec, shell, &argc, argv) < 0)
goto out;
// 唤醒compositor
weston_compositor_wake(ec);
// run:循环监听client端请求
wl_display_run(display);
}
- 可以看出其大致的过程为:
- 初始化Log系统
- 创建Display(全局唯一)
- 加载配置文件(ini文件)
- 创建Compositor
- 加载backend
- 创建socket
- 加载shell
- 开启循环
初始化Log系统
- weston-2.0.0/libweston/log.c
// 将vlog作为 log_handler
WL_EXPORT void
weston_log_set_handler(log_func_t log, log_func_t cont)
{
log_handler = log;
log_continue_handler = cont;
}
// 使用log_handler进行输出,实际上使用的是main.c中传递过来的
// vlog
WL_EXPORT int
weston_vlog(const char *fmt, va_list ap)
{
return log_handler(fmt, ap);
}
// 代码中使用到的log输出接口
WL_EXPORT int
weston_log(const char *fmt, ...)
{
int l;
va_list argp;
va_start(argp, fmt);
l = weston_vlog(fmt, argp);
va_end(argp);
return l;
}
- 实际上,log系统 使用vlog和vlog_continue这两个函数。两者的定义,在main.c中 。
static FILE *weston_logfile = NULL;
static void
weston_log_file_open(const char *filename)
{
wl_log_set_handler_server(custom_handler);
if (filename != NULL) {
weston_logfile = fopen(filename, "a");
if (weston_logfile)
os_fd_set_cloexec(fileno(weston_logfile));
}
if (weston_logfile == NULL)
weston_logfile = stderr;
else
setvbuf(weston_logfile, NULL, _IOLBF, 256);
}
static int
vlog(const char *fmt, va_list ap)
{
int l;
l = weston_log_timestamp();
l += vfprintf(weston_logfile, fmt, ap);
return l;
}
static int
vlog_continue(const char *fmt, va_list argp)
{
return vfprintf(weston_logfile, fmt, argp);
}
- 默认情况下weston_log_file_open函数,参数为NULL。所以log信息会输出到stderr中 。
创建Global Display
- wl_display_create:wayland1.13.0/src/wayland-server.c
WL_EXPORT struct wl_display *
wl_display_create(void)
{
struct wl_display *display;
const char *debug;
debug = getenv("WAYLAND_DEBUG");
if (debug && (strstr(debug, "server") || strstr(debug, "1")))
debug_server = 1;
display = malloc(sizeof *display);
if (display == NULL)
return NULL;
// 创建Loop
display->loop = wl_event_loop_create();
if (display->loop == NULL) {
free(display);
return NULL;
}
// list初始化
wl_list_init(&display->global_list);
wl_list_init(&display->socket_list);
wl_list_init(&display->client_list);
wl_list_init(&display->registry_resource_list);
wl_list_init(&display->protocol_loggers);
// signal初始化
wl_priv_signal_init(&display->destroy_signal);
wl_priv_signal_init(&display->create_client_signal);
display->id = 1;
display->serial = 0;
display->global_filter = NULL;
display->global_filter_data = NULL;
wl_array_init(&display->additional_shm_formats);
return display;
}
- wl_event_loop_create:wayland-1.13.0/src/event-loop.c
WL_EXPORT struct wl_event_loop *
wl_event_loop_create(void)
{
struct wl_event_loop *loop;
loop = malloc(sizeof *loop);
if (loop == NULL)
return NULL;
// 最终调用epoll_create
loop->epoll_fd = wl_os_epoll_create_cloexec();
if (loop->epoll_fd < 0) {
free(loop);
return NULL;
}
wl_list_init(&loop->check_list);
wl_list_init(&loop->idle_list);
wl_list_init(&loop->destroy_list);
wl_signal_init(&loop->destroy_signal);
return loop;
}
- 这部分主要就是初始化了Display结构体,使用epoll_create创建了loop。
加载配置文件
- 配置文件:weston提供了配置文件,可以动态的改变运行配置(需要重启Server端进程),比如使用哪种shell、动画的类型、backend的类型等等。
- compostior/main.c
static int
load_configuration(struct weston_config **config, int32_t noconfig,
const char *config_file)
{
// 默认的配置文件为 weston.ini
const char *file = "weston.ini";
const char *full_path;
*config = NULL;
if (config_file)
file = config_file;
// 解析配置文件
if (noconfig == 0)
*config = weston_config_parse(file);
if (*config) {
full_path = weston_config_get_full_path(*config);
weston_log("Using config file '%s'\n", full_path);
setenv(WESTON_CONFIG_FILE_ENV_VAR, full_path, 1);
return 0;
}
if (config_file && noconfig == 0) {
weston_log("fatal: error opening or reading config file"
" '%s'.\n", config_file);
return -1;
}
weston_log("Starting with no config file.\n");
setenv(WESTON_CONFIG_FILE_ENV_VAR, "", 1);
return 0;
}
- weston_config_parse函数负责具体解析配置文件。最终会解析成链表的数据结构。该函数代码行数较多,这里不再介绍。
- 官方提供的weston.ini
[core]
#modules=cms-colord.so
#xwayland=true
#shell=desktop-shell.so
#gbm-format=xrgb2101010
#require-input=true
[shell]
background-image=/usr/share/backgrounds/gnome/Aqua.jpg
background-color=0xff002244
background-type=tile
clock-format=minutes
panel-color=0x90ff0000
locking=true
animation=zoom
startup-animation=fade
#binding-modifier=ctrl
#num-workspaces=6
#cursor-theme=whiteglass
#cursor-size=24
#lockscreen-icon=/usr/share/icons/gnome/256x256/actions/lock.png
#lockscreen=/usr/share/backgrounds/gnome/Garden.jpg
#homescreen=/usr/share/backgrounds/gnome/Blinds.jpg
#animation=fade
[launcher]
icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
path=/usr/bin/gnome-terminal
[launcher]
icon=/usr/share/icons/gnome/24x24/apps/utilities-terminal.png
path=@bindir@/weston-terminal
[launcher]
icon=/usr/share/icons/hicolor/24x24/apps/google-chrome.png
path=/usr/bin/google-chrome
[launcher]
icon=/usr/share/icons/gnome/24x24/apps/arts.png
path=@abs_top_builddir@/weston-flower
[input-method]
path=@libexecdir@/weston-keyboard
#[output]
#name=LVDS1
#mode=1680x1050
#transform=90
#icc_profile=/usr/share/color/icc/colord/Bluish.icc
#[output]
#name=VGA1
#mode=173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
#transform=flipped
#[output]
#name=X1
#mode=1024x768@60
#transform=flipped-90
#[libinput]
#enable_tap=true
#[touchpad]
#constant_accel_factor = 50
#min_accel_factor = 0.16
#max_accel_factor = 1.0
[screen-share]
command=@bindir@/weston --backend=rdp-backend.so --shell=fullscreen-shell.so --no-clients-resize
#[xwayland]
#path=@bindir@/Xwayland
创建Compositor
- weston_compositor_create:libweston/compostior.c
WL_EXPORT struct weston_compositor *
weston_compositor_create(struct wl_display *display, void *user_data)
{
struct weston_compositor *ec;
struct wl_event_loop *loop;
ec = zalloc(sizeof *ec);
if (!ec)
return NULL;
// display为之前创建的全局display
ec->wl_display = display;
ec->user_data = user_data;
// 初始化一系列signal
wl_signal_init(&ec->destroy_signal);
wl_signal_init(&ec->create_surface_signal);
wl_signal_init(&ec->activate_signal);
wl_signal_init(&ec->transform_signal);
wl_signal_init(&ec->kill_signal);
wl_signal_init(&ec->idle_signal);
wl_signal_init(&ec->wake_signal);
wl_signal_init(&ec->show_input_panel_signal);
wl_signal_init(&ec->hide_input_panel_signal);
wl_signal_init(&ec->update_input_panel_signal);
wl_signal_init(&ec->seat_created_signal);
wl_signal_init(&ec->output_pending_signal);
wl_signal_init(&ec->output_created_signal);
wl_signal_init(&ec->output_destroyed_signal);
wl_signal_init(&ec->output_moved_signal);
wl_signal_init(&ec->output_resized_signal);
wl_signal_init(&ec->session_signal);
ec->session_active = 1;
ec->output_id_pool = 0;
ec->repaint_msec = DEFAULT_REPAINT_WINDOW;
ec->activate_serial = 1;
// 这几步比较关键。再weston代码中可以看多很多这种调用。
// wl_global_create有四个参数
// display、interface、version、bind_func
// 可以理解为:Display有一个全局对象List,这里为这个全局对象List中,加入一个新的全局对象。该对象的具体接口的实现,就是wl_compositor_interface。
if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4,
ec, compositor_bind))
goto fail;
// 同上wl_subcompositor_interface接口实现。
if (!wl_global_create(ec->wl_display, &wl_subcompositor_interface, 1,
ec, bind_subcompositor))
goto fail;
// 同上
if (!wl_global_create(ec->wl_display, &wp_viewporter_interface, 1,
ec, bind_viewporter))
goto fail;
// 同 上
if (!wl_global_create(ec->wl_display, &wp_presentation_interface, 1,
ec, bind_presentation))
goto fail;
// 创建了两个golbal对象,对应的interface为
// 1. zwp_relative_pointer_manager_v1_interface
// 2. zwp_pointer_constraints_v1_interface
if (weston_input_init(ec) != 0)
goto fail;
// 初始化,几个关键的list: view\plane\layer
wl_list_init(&ec->view_list);
wl_list_init(&ec->plane_list);
wl_list_init(&ec->layer_list);
wl_list_init(&ec->seat_list);
wl_list_init(&ec->pending_output_list);
wl_list_init(&ec->output_list);
wl_list_init(&ec->key_binding_list);
wl_list_init(&ec->modifier_binding_list);
wl_list_init(&ec->button_binding_list);
wl_list_init(&ec->touch_binding_list);
wl_list_init(&ec->axis_binding_list);
wl_list_init(&ec->debug_binding_list);
wl_list_init(&ec->plugin_api_list);
// 初始化 首先的plane
weston_plane_init(&ec->primary_plane, ec, 0, 0);
weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);
wl_data_device_manager_init(ec->wl_display);
wl_display_init_shm(ec->wl_display);
loop = wl_display_get_event_loop(ec->wl_display);
ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
// 初始化layer
weston_layer_init(&ec->fade_layer, ec);
weston_layer_init(&ec->cursor_layer, ec);
weston_layer_set_position(&ec->fade_layer, WESTON_LAYER_POSITION_FADE);
weston_layer_set_position(&ec->cursor_layer,
WESTON_LAYER_POSITION_CURSOR);
weston_compositor_add_debug_binding(ec, KEY_T,
timeline_key_binding_handler, ec);
return ec;
fail:
free(ec);
return NULL;
}
- 这里主要创建了几个全局对象,设置了这些全局对象对应的interface实现。并且初始化了view、layer、plane等一些关键的对象。
加载backend
- load_backend:compositor/main.c
static int
load_backend(struct weston_compositor *compositor, const char *backend,
int *argc, char **argv, struct weston_config *config)
{
if (strstr(backend, "headless-backend.so"))
return load_headless_backend(compositor, argc, argv, config);
else if (strstr(backend, "rdp-backend.so"))
return load_rdp_backend(compositor, argc, argv, config);
else if (strstr(backend, "fbdev-backend.so"))
return load_fbdev_backend(compositor, argc, argv, config);
// 默认走 drm-backend
else if (strstr(backend, "drm-backend.so"))
return load_drm_backend(compositor, argc, argv, config);
else if (strstr(backend, "x11-backend.so"))
return load_x11_backend(compositor, argc, argv, config);
else if (strstr(backend, "wayland-backend.so"))
return load_wayland_backend(compositor, argc, argv, config);
weston_log("Error: unknown backend \"%s\"\n", backend);
return -1;
}
- load_drm_backend
static int
load_drm_backend(struct weston_compositor *c,
int *argc, char **argv, struct weston_config *wc)
{
struct weston_drm_backend_config config = {{ 0, }};
struct weston_config_section *section;
struct wet_compositor *wet = to_wet_compositor(c);
// 走这里创建backend
ret = weston_compositor_load_backend(c, WESTON_BACKEND_DRM,
&config.base);
wet_set_pending_output_handler(c, drm_backend_output_configure);
free(config.gbm_format);
free(config.seat_id);
return ret;
}
- weston_compositor_load_backend:libweston/compositor.c
WL_EXPORT int
weston_compositor_load_backend(struct weston_compositor *compositor,
enum weston_compositor_backend backend,
struct weston_backend_config *config_base)
{
int (*backend_init)(struct weston_compositor *c,
struct weston_backend_config *config_base);
if (backend >= ARRAY_LENGTH(backend_map))
return -1;
// 通过dlopen,打开drm-backend.so,查找 weston_backend_init 函数
backend_init = weston_load_module(backend_map[backend], "weston_backend_init");
if (!backend_init)
return -1;
// 执行weston_backend_init函数
return backend_init(compositor, config_base);
}
- weston_backend_init:libweston/compositor-drm.c
WL_EXPORT int
weston_backend_init(struct weston_compositor *compositor,
struct weston_backend_config *config_base)
{
struct drm_backend *b;
struct weston_drm_backend_config config = {{ 0, }};
if (config_base == NULL ||
config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
weston_log("drm backend config structure is invalid\n");
return -1;
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
// 创建 drm backend
b = drm_backend_create(compositor, &config);
if (b == NULL)
return -1;
return 0;
}
- drm_backend_create:libweston/compositor-drm.c
static struct drm_backend *
drm_backend_create(struct weston_compositor *compositor,
struct weston_drm_backend_config *config)
{
// 使用libdrm接口,做一些初始化的动作
// 创建output对象 drmModeGetConnector
}
创建Socket
- Server进程创建监听socket
- weston_create_listening_socket:compositor/main.c
static int
weston_create_listening_socket(struct wl_display *display, const char *socket_name)
{
if (socket_name) {
if (wl_display_add_socket(display, socket_name)) {
weston_log("fatal: failed to add socket: %m\n");
return -1;
}
} else {
// 默认socketname为空。
// 创建一个名为wayland-0的socket
socket_name = wl_display_add_socket_auto(display);
if (!socket_name) {
weston_log("fatal: failed to add socket: %m\n");
return -1;
}
}
setenv("WAYLAND_DISPLAY", socket_name, 1);
return 0;
}
加载shell
- wet_load_shell:compositor/main.c
static int
wet_load_shell(struct weston_compositor *compositor,
const char *name, int *argc, char *argv[])
{
int (*shell_init)(struct weston_compositor *ec,
int *argc, char *argv[]);
// 默认:
// 使用dlopen,打开desktop-shell.so,查找wet_shell_init函数
shell_init = wet_load_module_entrypoint(name, "wet_shell_init");
if (!shell_init)
return -1;
// 调用wet_shell_init
if (shell_init(compositor, argc, argv) < 0)
return -1;
return 0;
}
- wet_shell_init:deskstop-shell/shell.c
WL_EXPORT int
wet_shell_init(struct weston_compositor *ec,
int *argc, char *argv[])
{
// 创建desktop
shell->desktop = weston_desktop_create(ec, &shell_desktop_api, shell);
if (!shell->desktop)
return -1;
// 创建全局对象
if (wl_global_create(ec->wl_display,
&weston_desktop_shell_interface, 1,
shell, bind_desktop_shell) == NULL)
return -1;
}
开启循环
- 这里的循环,指使用epoll机制,监听对socket(上面Server端创建的socket)产生的读写事件。
WL_EXPORT void
wl_display_run(struct wl_display *display)
{
display->run = 1;
while (display->run) {
wl_display_flush_clients(display);
wl_event_loop_dispatch(display->loop, -1);
}
}
- wl_event_loop_dispatch:event-loop.c
WL_EXPORT int
wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
{
struct epoll_event ep[32];
struct wl_event_source *source;
int i, count, n;
wl_event_loop_dispatch_idle(loop);
count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
if (count < 0)
return -1;
for (i = 0; i < count; i++) {
source = ep[i].data.ptr;
if (source->fd != -1)
source->interface->dispatch(source, &ep[i]);
}
wl_event_loop_process_destroy_list(loop);
wl_event_loop_dispatch_idle(loop);
do {
n = post_dispatch_check(loop);
} while (n > 0);
return 0;
}