KWin
Loading...
Searching...
No Matches
xwaylandserver_crash_test.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "kwin_wayland_test.h"
8
9#include "compositor.h"
10#include "core/output.h"
11#include "main.h"
13#include "wayland_server.h"
14#include "workspace.h"
15#include "x11window.h"
16#include "xwayland/xwayland.h"
18
19#include <xcb/xcb_icccm.h>
20
21namespace KWin
22{
23
24static const QString s_socketName = QStringLiteral("wayland_test_kwin_xwayland_server_crash-0");
25
26class XwaylandServerCrashTest : public QObject
27{
28 Q_OBJECT
29
30private Q_SLOTS:
31 void initTestCase();
32 void testCrash();
33};
34
35void XwaylandServerCrashTest::initTestCase()
36{
37 qRegisterMetaType<X11Window *>();
38 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
39 QVERIFY(waylandServer()->init(s_socketName));
41 QRect(0, 0, 1280, 1024),
42 QRect(1280, 0, 1280, 1024),
43 });
44
45 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
46 KConfigGroup xwaylandGroup = config->group(QStringLiteral("Xwayland"));
47 xwaylandGroup.writeEntry(QStringLiteral("XwaylandCrashPolicy"), QStringLiteral("Stop"));
48 xwaylandGroup.sync();
49 kwinApp()->setConfig(config);
50
51 kwinApp()->start();
52 QVERIFY(applicationStartedSpy.wait());
53 const auto outputs = workspace()->outputs();
54 QCOMPARE(outputs.count(), 2);
55 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
56 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
57}
58
59void XwaylandServerCrashTest::testCrash()
60{
61 // This test verifies that all connected X11 clients get destroyed when Xwayland crashes.
62
63 // Create a normal window.
65 QVERIFY(!xcb_connection_has_error(c.get()));
66 const QRect windowGeometry(0, 0, 100, 200);
67 xcb_window_t windowId1 = xcb_generate_id(c.get());
68 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId1, rootWindow(),
69 windowGeometry.x(),
70 windowGeometry.y(),
71 windowGeometry.width(),
72 windowGeometry.height(),
73 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
74 xcb_size_hints_t hints;
75 memset(&hints, 0, sizeof(hints));
76 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
77 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
78 xcb_icccm_size_hints_set_min_size(&hints, windowGeometry.width(), windowGeometry.height());
79 xcb_icccm_set_wm_normal_hints(c.get(), windowId1, &hints);
80 xcb_map_window(c.get(), windowId1);
81 xcb_flush(c.get());
82
83 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
84 QVERIFY(windowCreatedSpy.wait());
85 QPointer<X11Window> window = windowCreatedSpy.last().first().value<X11Window *>();
86 QVERIFY(window);
87 QVERIFY(window->isDecorated());
88
89 // Create an override-redirect window.
90 xcb_window_t windowId2 = xcb_generate_id(c.get());
91 const uint32_t values[] = {true};
92 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId2, rootWindow(),
93 windowGeometry.x(), windowGeometry.y(),
94 windowGeometry.width(), windowGeometry.height(), 0,
95 XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT,
96 XCB_CW_OVERRIDE_REDIRECT, values);
97 xcb_map_window(c.get(), windowId2);
98 xcb_flush(c.get());
99
100 QSignalSpy unmanagedAddedSpy(workspace(), &Workspace::windowAdded);
101 QVERIFY(unmanagedAddedSpy.wait());
102 QPointer<X11Window> unmanaged = unmanagedAddedSpy.last().first().value<X11Window *>();
103 QVERIFY(unmanaged);
104
105 // Let's pretend that the Xwayland process has crashed.
106 QSignalSpy x11ConnectionChangedSpy(kwinApp(), &Application::x11ConnectionChanged);
107 Xwl::Xwayland *xwayland = static_cast<Xwl::Xwayland *>(kwinApp()->xwayland());
108 xwayland->xwaylandLauncher()->process()->terminate();
109 QVERIFY(x11ConnectionChangedSpy.wait());
110
111 // When Xwayland crashes, the compositor should tear down the XCB connection and destroy
112 // all connected X11 clients.
113 QTRY_VERIFY(!window);
114 QTRY_VERIFY(!unmanaged);
115 QCOMPARE(kwinApp()->x11Connection(), nullptr);
116 QCOMPARE(kwinApp()->x11RootWindow(), XCB_WINDOW_NONE);
117
118 // Render a frame to ensure that the compositor doesn't crash.
120 QSignalSpy frameRenderedSpy(Compositor::self()->scene(), &WorkspaceScene::frameRendered);
121 QVERIFY(frameRenderedSpy.wait());
122}
123
124} // namespace KWin
125
127#include "xwaylandserver_crash_test.moc"
void x11ConnectionChanged()
WorkspaceScene * scene() const
Definition compositor.h:60
static Compositor * self()
void addRepaintFull()
Definition scene.cpp:81
void windowAdded(KWin::Window *)
QList< Output * > outputs() const
Definition workspace.h:762
#define WAYLANDTEST_MAIN(TestObject)
void setOutputConfig(const QList< QRect > &geometries)
XcbConnectionPtr createX11Connection()
std::unique_ptr< xcb_connection_t, XcbConnectionDeleter > XcbConnectionPtr
KWIN_EXPORT xcb_window_t rootWindow()
Definition xcb.h:24
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830