Skip to content

Commit d35ecc6

Browse files
reddevillgdengbo11
authored andcommitted
feat: add --disable-xdp flag to disable xdp integration
Add xdp document support Signed-off-by: reddevillg <reddevillg@gmail.com>
1 parent d305bbd commit d35ecc6

13 files changed

Lines changed: 171 additions & 6 deletions

File tree

api/schema/v1.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,9 @@
14541454
"items": {
14551455
"$ref": "#/$defs/DeviceOption"
14561456
}
1457+
},
1458+
"disable_xdp": {
1459+
"type": "boolean"
14571460
}
14581461
}
14591462
},

api/schema/v1.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,8 @@ $defs:
11011101
type: array
11021102
items:
11031103
$ref: '#/$defs/DeviceOption'
1104+
disable_xdp:
1105+
type: boolean
11041106
RunContextConfig:
11051107
title: RunContextConfig
11061108
type: object

apps/ll-cli/src/main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ ll-cli run org.deepin.demo -- bash -x /path/to/bash/script)"));
173173
->delimiter(',') // 支持以逗号分隔
174174
->allow_extra_args(false) // 避免吞掉后面的参数
175175
->check(validatorString);
176+
cliRun
177+
->add_flag("--enable-xdp{false},!--disable-xdp{true}",
178+
runOptions.disableXdp,
179+
_("Enable or disable xdg-desktop-portal related integration inside the sandbox"))
180+
->take_last();
176181
cliRun->add_option("--run-context", runOptions.runContext, _("Run context json string"))
177182
->group("");
178183
cliRun

libs/api/src/linglong/api/types/v1/Generators.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,7 @@ j["version"] = x.version;
12781278

12791279
inline void from_json(const json & j, RuntimeConfigure& x) {
12801280
x.deviceMode = get_stack_optional<std::vector<DeviceOption>>(j, "device_mode");
1281+
x.disableXdp = get_stack_optional<bool>(j, "disable_xdp");
12811282
x.env = get_stack_optional<std::map<std::string, std::string>>(j, "env");
12821283
x.extDefs = get_stack_optional<std::map<std::string, std::vector<ExtensionDefine>>>(j, "ext_defs");
12831284
}
@@ -1287,6 +1288,9 @@ j = json::object();
12871288
if (x.deviceMode) {
12881289
j["device_mode"] = x.deviceMode;
12891290
}
1291+
if (x.disableXdp) {
1292+
j["disable_xdp"] = x.disableXdp;
1293+
}
12901294
if (x.env) {
12911295
j["env"] = x.env;
12921296
}

libs/api/src/linglong/api/types/v1/RuntimeConfigure.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ using nlohmann::json;
3737

3838
struct RuntimeConfigure {
3939
std::optional<std::vector<DeviceOption>> deviceMode;
40+
std::optional<bool> disableXdp;
4041
std::optional<std::map<std::string, std::string>> env;
4142
/**
4243
* external extension definitions to extend the component

libs/linglong/src/linglong/cli/cli.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct RunOptions
5757
std::optional<std::string> runtime;
5858
std::optional<std::string> workdir;
5959
std::vector<std::string> extensions;
60+
std::optional<bool> disableXdp;
6061
bool privileged{ false };
6162
std::vector<std::string> capsAdd;
6263
std::vector<std::string> cdiSpecDir = { "/etc/cdi", "/var/run/cdi" };

libs/linglong/src/linglong/runtime/container_builder.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include <fmt/format.h>
1818
#include <fmt/ranges.h>
1919

20+
#include <QDBusConnection>
21+
#include <QDBusInterface>
22+
#include <QDBusReply>
23+
2024
#include <algorithm>
2125
#include <fstream>
2226

@@ -32,6 +36,47 @@ const std::vector<std::string> buildContainerCaps = {
3236
"CAP_SETPCAP", "CAP_SETUID", "CAP_SYS_CHROOT",
3337
};
3438

39+
auto getXDPDocumentsMountPoint() noexcept -> utils::error::Result<std::filesystem::path>
40+
{
41+
LINGLONG_TRACE("get XDP Documents mount point");
42+
43+
auto bus = QDBusConnection::sessionBus();
44+
if (!bus.isConnected()) {
45+
return LINGLONG_ERR("session bus is not connected");
46+
}
47+
48+
QDBusInterface documentsPortal("org.freedesktop.portal.Documents",
49+
"/org/freedesktop/portal/documents",
50+
"org.freedesktop.portal.Documents",
51+
bus);
52+
if (!documentsPortal.isValid()) {
53+
return LINGLONG_ERR("org.freedesktop.portal.Documents is not available");
54+
}
55+
56+
auto reply = documentsPortal.call(QDBus::Block, "GetMountPoint");
57+
if (reply.type() == QDBusMessage::ErrorMessage) {
58+
return LINGLONG_ERR(reply.errorMessage().toStdString());
59+
}
60+
61+
if (reply.arguments().isEmpty()) {
62+
return LINGLONG_ERR("Documents portal mount point reply is empty");
63+
}
64+
65+
const auto &value = reply.arguments().constFirst();
66+
if (!value.canConvert<QByteArray>()) {
67+
return LINGLONG_ERR(
68+
fmt::format("unexpected Documents portal mount point type: {}", value.typeName()));
69+
}
70+
auto mountPoint = value.toByteArray().toStdString();
71+
72+
if (mountPoint.empty()) {
73+
return LINGLONG_ERR("Documents portal mount point is empty");
74+
}
75+
76+
// c_str is crucial here, without it the path may include trailing null bytes
77+
return std::filesystem::path{ mountPoint.c_str() };
78+
}
79+
3580
} // namespace
3681

3782
utils::error::Result<std::filesystem::path> makeBundleDir(const std::string &containerID,
@@ -68,6 +113,10 @@ std::string genContainerID(const api::types::v1::RunContextConfig &config) noexc
68113
auto RunContainerOptions::applyRuntimeConfig(
69114
const api::types::v1::RuntimeConfigure &runtimeConfig) noexcept -> utils::error::Result<void>
70115
{
116+
if (runtimeConfig.disableXdp.has_value()) {
117+
this->disableXdp = *runtimeConfig.disableXdp;
118+
}
119+
71120
if (runtimeConfig.deviceMode) {
72121
for (const auto &option : *runtimeConfig.deviceMode) {
73122
if (option == api::types::v1::DeviceOption::Passthru) {
@@ -107,6 +156,9 @@ auto RunContainerOptions::applyCliRunOptions(const cli::RunOptions &options) noe
107156
this->env.insert_or_assign(item.substr(0, split), item.substr(split + 1));
108157
}
109158

159+
if (options.disableXdp.has_value()) {
160+
this->disableXdp = *options.disableXdp;
161+
}
110162
this->privileged = options.privileged;
111163
this->capabilities.insert(this->capabilities.end(),
112164
options.capsAdd.begin(),
@@ -146,6 +198,11 @@ auto RunContainerOptions::isDevicePassthruEnabled() const noexcept -> bool
146198
return this->devicePassthru;
147199
}
148200

201+
auto RunContainerOptions::isXdpDisabled() const noexcept -> bool
202+
{
203+
return this->disableXdp;
204+
}
205+
149206
auto RunContainerOptions::isPrivileged() const noexcept -> bool
150207
{
151208
return this->privileged;
@@ -473,6 +530,18 @@ auto ContainerBuilder::configureRunContainer(PreparedContainer &prepared,
473530
.bindIPC()
474531
.forwardDefaultEnv();
475532

533+
if (!options.isXdpDisabled()) {
534+
auto docMountPoint = getXDPDocumentsMountPoint();
535+
if (docMountPoint) {
536+
prepared.cfgBuilder.enableXDP(generator::XdpOption{
537+
.docMountPoint = std::move(*docMountPoint),
538+
});
539+
} else {
540+
LogW("failed to get XDP Documents mount point: {}, skip XDP integration",
541+
docMountPoint.error());
542+
}
543+
}
544+
476545
if (options.isDevicePassthruEnabled()) {
477546
prepared.cfgBuilder.bindDev(true);
478547
} else {

libs/linglong/src/linglong/runtime/container_builder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ struct RunContainerOptions
5353
[[nodiscard]] auto getSecurityContexts() const noexcept
5454
-> const std::vector<SecurityContextType> &;
5555
[[nodiscard]] auto isDevicePassthruEnabled() const noexcept -> bool;
56+
[[nodiscard]] auto isXdpDisabled() const noexcept -> bool;
5657
[[nodiscard]] auto isPrivileged() const noexcept -> bool;
5758

5859
CommonContainerOptions common;
5960

61+
bool disableXdp{ false };
6062
bool privileged{ false };
6163
bool devicePassthru{ false };
6264
std::map<std::string, std::string> env;

libs/linglong/tests/ll-tests/src/linglong/runtime/container_builder_test.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ TEST(RunContainerOptionsTest, ApplyRuntimeConfigEnablesDevicePassthru)
2222
EXPECT_TRUE(options.isDevicePassthruEnabled());
2323
}
2424

25+
TEST(RunContainerOptionsTest, ApplyRuntimeConfigDisablesXdp)
26+
{
27+
runtime::RunContainerOptions options;
28+
29+
api::types::v1::RuntimeConfigure runtimeConfig;
30+
runtimeConfig.disableXdp = true;
31+
32+
auto result = options.applyRuntimeConfig(runtimeConfig);
33+
ASSERT_TRUE(result);
34+
EXPECT_TRUE(options.isXdpDisabled());
35+
}
36+
2537
TEST(RunContainerOptionsTest, ApplyCliRunOptionsEnablesDevicePassthru)
2638
{
2739
runtime::RunContainerOptions options;
@@ -32,3 +44,39 @@ TEST(RunContainerOptionsTest, ApplyCliRunOptionsEnablesDevicePassthru)
3244
ASSERT_TRUE(result);
3345
EXPECT_TRUE(options.isDevicePassthruEnabled());
3446
}
47+
48+
TEST(RunContainerOptionsTest, ApplyCliRunOptionsPreservesRuntimeConfigXdpSettingByDefault)
49+
{
50+
runtime::RunContainerOptions options;
51+
52+
api::types::v1::RuntimeConfigure runtimeConfig;
53+
runtimeConfig.disableXdp = true;
54+
55+
auto runtimeResult = options.applyRuntimeConfig(runtimeConfig);
56+
ASSERT_TRUE(runtimeResult);
57+
ASSERT_TRUE(options.isXdpDisabled());
58+
59+
cli::RunOptions runOptions;
60+
auto cliResult = options.applyCliRunOptions(runOptions);
61+
ASSERT_TRUE(cliResult);
62+
EXPECT_TRUE(options.isXdpDisabled());
63+
}
64+
65+
TEST(RunContainerOptionsTest, ApplyCliRunOptionsOverridesRuntimeConfigXdpSettingWhenSpecified)
66+
{
67+
runtime::RunContainerOptions options;
68+
69+
api::types::v1::RuntimeConfigure runtimeConfig;
70+
runtimeConfig.disableXdp = false;
71+
72+
auto runtimeResult = options.applyRuntimeConfig(runtimeConfig);
73+
ASSERT_TRUE(runtimeResult);
74+
ASSERT_FALSE(options.isXdpDisabled());
75+
76+
cli::RunOptions runOptions;
77+
runOptions.disableXdp = true;
78+
79+
auto cliResult = options.applyCliRunOptions(runOptions);
80+
ASSERT_TRUE(cliResult);
81+
EXPECT_TRUE(options.isXdpDisabled());
82+
}

libs/linglong/tests/ll-tests/src/linglong/utils/runtime_config_test.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ TEST(RuntimeConfigTest, LoadFromPath)
2424
fs::path config_file = tempDir.path() / "test_config.json";
2525

2626
RuntimeConfigure config;
27+
config.disableXdp = true;
2728
config.deviceMode = std::vector<DeviceOption>{ DeviceOption::Passthru };
2829
config.env =
2930
std::map<std::string, std::string>{ { "PATH", "/usr/bin" }, { "HOME", "/home/user" } };
@@ -48,6 +49,9 @@ TEST(RuntimeConfigTest, LoadFromPath)
4849
auto loaded_config = linglong::utils::loadRuntimeConfig(config_file);
4950
ASSERT_TRUE(loaded_config.has_value());
5051

52+
ASSERT_TRUE(loaded_config->disableXdp.has_value());
53+
EXPECT_TRUE(*loaded_config->disableXdp);
54+
5155
ASSERT_TRUE(loaded_config->deviceMode);
5256
EXPECT_EQ(loaded_config->deviceMode->size(), 1);
5357
EXPECT_EQ(loaded_config->deviceMode->at(0), DeviceOption::Passthru);
@@ -75,6 +79,7 @@ TEST(RuntimeConfigTest, MergeConfigs)
7579
{
7680
// Create first config
7781
RuntimeConfigure config1;
82+
config1.disableXdp = false;
7883
config1.deviceMode = std::vector<DeviceOption>{ DeviceOption::Passthru };
7984
config1.env =
8085
std::map<std::string, std::string>{ { "PATH", "/usr/bin" }, { "HOME", "/home/user1" } };
@@ -87,6 +92,7 @@ TEST(RuntimeConfigTest, MergeConfigs)
8792

8893
// Create second config
8994
RuntimeConfigure config2;
95+
config2.disableXdp = true;
9096
config2.deviceMode = std::vector<DeviceOption>{ DeviceOption::Passthru };
9197
config2.env =
9298
std::map<std::string, std::string>{ { "PATH", "/usr/local/bin" }, { "USER", "testuser" } };
@@ -104,6 +110,9 @@ TEST(RuntimeConfigTest, MergeConfigs)
104110
std::vector<RuntimeConfigure> configs = { config1, config2 };
105111
auto merged = linglong::utils::MergeRuntimeConfig(configs);
106112

113+
ASSERT_TRUE(merged.disableXdp.has_value());
114+
EXPECT_TRUE(*merged.disableXdp);
115+
107116
ASSERT_TRUE(merged.deviceMode);
108117
EXPECT_EQ(merged.deviceMode->size(), 2);
109118
EXPECT_EQ(merged.deviceMode->at(0), DeviceOption::Passthru);
@@ -135,6 +144,7 @@ TEST(RuntimeConfigTest, MergeEmptyConfigs)
135144
std::vector<RuntimeConfigure> empty_configs;
136145
auto merged = linglong::utils::MergeRuntimeConfig(empty_configs);
137146

147+
EXPECT_FALSE(merged.disableXdp);
138148
EXPECT_FALSE(merged.deviceMode);
139149
EXPECT_FALSE(merged.env);
140150
EXPECT_FALSE(merged.extDefs);
@@ -144,6 +154,7 @@ TEST(RuntimeConfigTest, MergePartialConfigs)
144154
{
145155
// Config with only env
146156
RuntimeConfigure config1;
157+
config1.disableXdp = false;
147158
config1.deviceMode = std::vector<DeviceOption>{ DeviceOption::Passthru };
148159
config1.env = std::map<std::string, std::string>{ { "PATH", "/usr/bin" } };
149160

@@ -165,6 +176,9 @@ TEST(RuntimeConfigTest, MergePartialConfigs)
165176
linglong::api::types::v1::to_json(j, merged);
166177
LogD("{}", j.dump());
167178

179+
ASSERT_TRUE(merged.disableXdp.has_value());
180+
EXPECT_FALSE(*merged.disableXdp);
181+
168182
ASSERT_TRUE(merged.env);
169183
EXPECT_EQ(merged.env->size(), 1);
170184
EXPECT_EQ(merged.env->at("PATH"), "/usr/bin");

0 commit comments

Comments
 (0)