Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/schema/v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -1454,6 +1454,9 @@
"items": {
"$ref": "#/$defs/DeviceOption"
}
},
"disable_xdp": {
"type": "boolean"
}
}
},
Expand Down
2 changes: 2 additions & 0 deletions api/schema/v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,8 @@ $defs:
type: array
items:
$ref: '#/$defs/DeviceOption'
disable_xdp:
type: boolean
RunContextConfig:
title: RunContextConfig
type: object
Expand Down
5 changes: 5 additions & 0 deletions apps/ll-cli/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ ll-cli run org.deepin.demo -- bash -x /path/to/bash/script)"));
->delimiter(',') // 支持以逗号分隔
->allow_extra_args(false) // 避免吞掉后面的参数
->check(validatorString);
cliRun
->add_flag("--enable-xdp{false},!--disable-xdp{true}",
runOptions.disableXdp,
_("Enable or disable xdg-desktop-portal related integration inside the sandbox"))
->take_last();
cliRun->add_option("--run-context", runOptions.runContext, _("Run context json string"))
->group("");
cliRun
Expand Down
4 changes: 4 additions & 0 deletions libs/api/src/linglong/api/types/v1/Generators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,7 @@ j["version"] = x.version;

inline void from_json(const json & j, RuntimeConfigure& x) {
x.deviceMode = get_stack_optional<std::vector<DeviceOption>>(j, "device_mode");
x.disableXdp = get_stack_optional<bool>(j, "disable_xdp");
x.env = get_stack_optional<std::map<std::string, std::string>>(j, "env");
x.extDefs = get_stack_optional<std::map<std::string, std::vector<ExtensionDefine>>>(j, "ext_defs");
}
Expand All @@ -1287,6 +1288,9 @@ j = json::object();
if (x.deviceMode) {
j["device_mode"] = x.deviceMode;
}
if (x.disableXdp) {
j["disable_xdp"] = x.disableXdp;
}
if (x.env) {
j["env"] = x.env;
}
Expand Down
1 change: 1 addition & 0 deletions libs/api/src/linglong/api/types/v1/RuntimeConfigure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ using nlohmann::json;

struct RuntimeConfigure {
std::optional<std::vector<DeviceOption>> deviceMode;
std::optional<bool> disableXdp;
std::optional<std::map<std::string, std::string>> env;
/**
* external extension definitions to extend the component
Expand Down
1 change: 1 addition & 0 deletions libs/linglong/src/linglong/cli/cli.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct RunOptions
std::optional<std::string> runtime;
std::optional<std::string> workdir;
std::vector<std::string> extensions;
std::optional<bool> disableXdp;
bool privileged{ false };
std::vector<std::string> capsAdd;
std::vector<std::string> cdiSpecDir = { "/etc/cdi", "/var/run/cdi" };
Expand Down
69 changes: 69 additions & 0 deletions libs/linglong/src/linglong/runtime/container_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
#include "linglong/runtime/run_context.h"
#include "linglong/utils/log/log.h"

#include <fmt/format.h>

Check warning on line 17 in libs/linglong/src/linglong/runtime/container_builder.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <fmt/format.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <fmt/ranges.h>

Check warning on line 18 in libs/linglong/src/linglong/runtime/container_builder.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <fmt/ranges.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <QDBusConnection>

Check warning on line 20 in libs/linglong/src/linglong/runtime/container_builder.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <algorithm> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDBusInterface>

Check warning on line 21 in libs/linglong/src/linglong/runtime/container_builder.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <fstream> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDBusReply>

Check warning on line 23 in libs/linglong/src/linglong/runtime/container_builder.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <unistd.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <algorithm>
#include <fstream>

Expand All @@ -32,6 +36,47 @@
"CAP_SETPCAP", "CAP_SETUID", "CAP_SYS_CHROOT",
};

auto getXDPDocumentsMountPoint() noexcept -> utils::error::Result<std::filesystem::path>
{
LINGLONG_TRACE("get XDP Documents mount point");

auto bus = QDBusConnection::sessionBus();
if (!bus.isConnected()) {
return LINGLONG_ERR("session bus is not connected");
}

QDBusInterface documentsPortal("org.freedesktop.portal.Documents",
"/org/freedesktop/portal/documents",
"org.freedesktop.portal.Documents",
bus);
if (!documentsPortal.isValid()) {
return LINGLONG_ERR("org.freedesktop.portal.Documents is not available");
}

auto reply = documentsPortal.call(QDBus::Block, "GetMountPoint");
if (reply.type() == QDBusMessage::ErrorMessage) {
return LINGLONG_ERR(reply.errorMessage().toStdString());
}

if (reply.arguments().isEmpty()) {
return LINGLONG_ERR("Documents portal mount point reply is empty");
}

const auto &value = reply.arguments().constFirst();
if (!value.canConvert<QByteArray>()) {
return LINGLONG_ERR(
fmt::format("unexpected Documents portal mount point type: {}", value.typeName()));
}
auto mountPoint = value.toByteArray().toStdString();

if (mountPoint.empty()) {
return LINGLONG_ERR("Documents portal mount point is empty");

Check warning on line 73 in libs/linglong/src/linglong/runtime/container_builder.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Consider using std::any_of algorithm instead of a raw loop.
}

// c_str is crucial here, without it the path may include trailing null bytes
return std::filesystem::path{ mountPoint.c_str() };
}

} // namespace

utils::error::Result<std::filesystem::path> makeBundleDir(const std::string &containerID,
Expand Down Expand Up @@ -68,6 +113,10 @@
auto RunContainerOptions::applyRuntimeConfig(
const api::types::v1::RuntimeConfigure &runtimeConfig) noexcept -> utils::error::Result<void>
{
if (runtimeConfig.disableXdp.has_value()) {
this->disableXdp = *runtimeConfig.disableXdp;
}

if (runtimeConfig.deviceMode) {
for (const auto &option : *runtimeConfig.deviceMode) {
if (option == api::types::v1::DeviceOption::Passthru) {
Expand Down Expand Up @@ -107,6 +156,9 @@
this->env.insert_or_assign(item.substr(0, split), item.substr(split + 1));
}

if (options.disableXdp.has_value()) {
this->disableXdp = *options.disableXdp;
}
this->privileged = options.privileged;
this->capabilities.insert(this->capabilities.end(),
options.capsAdd.begin(),
Expand Down Expand Up @@ -146,6 +198,11 @@
return this->devicePassthru;
}

auto RunContainerOptions::isXdpDisabled() const noexcept -> bool
{
return this->disableXdp;
}

auto RunContainerOptions::isPrivileged() const noexcept -> bool
{
return this->privileged;
Expand Down Expand Up @@ -473,6 +530,18 @@
.bindIPC()
.forwardDefaultEnv();

if (!options.isXdpDisabled()) {
auto docMountPoint = getXDPDocumentsMountPoint();
if (docMountPoint) {
prepared.cfgBuilder.enableXDP(generator::XdpOption{
.docMountPoint = std::move(*docMountPoint),
});
} else {
LogW("failed to get XDP Documents mount point: {}, skip XDP integration",
docMountPoint.error());
}
}

if (options.isDevicePassthruEnabled()) {
prepared.cfgBuilder.bindDev(true);
} else {
Expand Down
2 changes: 2 additions & 0 deletions libs/linglong/src/linglong/runtime/container_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ struct RunContainerOptions
[[nodiscard]] auto getSecurityContexts() const noexcept
-> const std::vector<SecurityContextType> &;
[[nodiscard]] auto isDevicePassthruEnabled() const noexcept -> bool;
[[nodiscard]] auto isXdpDisabled() const noexcept -> bool;
[[nodiscard]] auto isPrivileged() const noexcept -> bool;

CommonContainerOptions common;

bool disableXdp{ false };
bool privileged{ false };
bool devicePassthru{ false };
std::map<std::string, std::string> env;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ TEST(RunContainerOptionsTest, ApplyRuntimeConfigEnablesDevicePassthru)
EXPECT_TRUE(options.isDevicePassthruEnabled());
}

TEST(RunContainerOptionsTest, ApplyRuntimeConfigDisablesXdp)
{
runtime::RunContainerOptions options;

api::types::v1::RuntimeConfigure runtimeConfig;
runtimeConfig.disableXdp = true;

auto result = options.applyRuntimeConfig(runtimeConfig);
ASSERT_TRUE(result);
EXPECT_TRUE(options.isXdpDisabled());
}

TEST(RunContainerOptionsTest, ApplyCliRunOptionsEnablesDevicePassthru)
{
runtime::RunContainerOptions options;
Expand All @@ -32,3 +44,39 @@ TEST(RunContainerOptionsTest, ApplyCliRunOptionsEnablesDevicePassthru)
ASSERT_TRUE(result);
EXPECT_TRUE(options.isDevicePassthruEnabled());
}

TEST(RunContainerOptionsTest, ApplyCliRunOptionsPreservesRuntimeConfigXdpSettingByDefault)
{
runtime::RunContainerOptions options;

api::types::v1::RuntimeConfigure runtimeConfig;
runtimeConfig.disableXdp = true;

auto runtimeResult = options.applyRuntimeConfig(runtimeConfig);
ASSERT_TRUE(runtimeResult);
ASSERT_TRUE(options.isXdpDisabled());

cli::RunOptions runOptions;
auto cliResult = options.applyCliRunOptions(runOptions);
ASSERT_TRUE(cliResult);
EXPECT_TRUE(options.isXdpDisabled());
}

TEST(RunContainerOptionsTest, ApplyCliRunOptionsOverridesRuntimeConfigXdpSettingWhenSpecified)
{
runtime::RunContainerOptions options;

api::types::v1::RuntimeConfigure runtimeConfig;
runtimeConfig.disableXdp = false;

auto runtimeResult = options.applyRuntimeConfig(runtimeConfig);
ASSERT_TRUE(runtimeResult);
ASSERT_FALSE(options.isXdpDisabled());

cli::RunOptions runOptions;
runOptions.disableXdp = true;

auto cliResult = options.applyCliRunOptions(runOptions);
ASSERT_TRUE(cliResult);
EXPECT_TRUE(options.isXdpDisabled());
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ TEST(RuntimeConfigTest, LoadFromPath)
fs::path config_file = tempDir.path() / "test_config.json";

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

ASSERT_TRUE(loaded_config->disableXdp.has_value());
EXPECT_TRUE(*loaded_config->disableXdp);

ASSERT_TRUE(loaded_config->deviceMode);
EXPECT_EQ(loaded_config->deviceMode->size(), 1);
EXPECT_EQ(loaded_config->deviceMode->at(0), DeviceOption::Passthru);
Expand Down Expand Up @@ -75,6 +79,7 @@ TEST(RuntimeConfigTest, MergeConfigs)
{
// Create first config
RuntimeConfigure config1;
config1.disableXdp = false;
config1.deviceMode = std::vector<DeviceOption>{ DeviceOption::Passthru };
config1.env =
std::map<std::string, std::string>{ { "PATH", "/usr/bin" }, { "HOME", "/home/user1" } };
Expand All @@ -87,6 +92,7 @@ TEST(RuntimeConfigTest, MergeConfigs)

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

ASSERT_TRUE(merged.disableXdp.has_value());
EXPECT_TRUE(*merged.disableXdp);

ASSERT_TRUE(merged.deviceMode);
EXPECT_EQ(merged.deviceMode->size(), 2);
EXPECT_EQ(merged.deviceMode->at(0), DeviceOption::Passthru);
Expand Down Expand Up @@ -135,6 +144,7 @@ TEST(RuntimeConfigTest, MergeEmptyConfigs)
std::vector<RuntimeConfigure> empty_configs;
auto merged = linglong::utils::MergeRuntimeConfig(empty_configs);

EXPECT_FALSE(merged.disableXdp);
EXPECT_FALSE(merged.deviceMode);
EXPECT_FALSE(merged.env);
EXPECT_FALSE(merged.extDefs);
Expand All @@ -144,6 +154,7 @@ TEST(RuntimeConfigTest, MergePartialConfigs)
{
// Config with only env
RuntimeConfigure config1;
config1.disableXdp = false;
config1.deviceMode = std::vector<DeviceOption>{ DeviceOption::Passthru };
config1.env = std::map<std::string, std::string>{ { "PATH", "/usr/bin" } };

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

ASSERT_TRUE(merged.disableXdp.has_value());
EXPECT_FALSE(*merged.disableXdp);

ASSERT_TRUE(merged.env);
EXPECT_EQ(merged.env->size(), 1);
EXPECT_EQ(merged.env->at("PATH"), "/usr/bin");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ utils::error::Result<void> ContainerCfgBuilder::buildXDGRuntime() noexcept
.type = "bind" });
environment["XDG_RUNTIME_DIR"] = *containerXDGRuntimeDir;

if (xdpOption) {
runMount->emplace_back(Mount{ .destination = *containerXDGRuntimeDir / "doc",
.options = string_list{ "bind" },
.source = xdpOption->docMountPoint / "by-app" / appId,
.type = "bind" });
}

return LINGLONG_OK;
}

Expand Down Expand Up @@ -1450,7 +1457,7 @@ utils::error::Result<void> ContainerCfgBuilder::buildEnv() noexcept
environment["LINGLONG_APPID"] = appId;
}

if (!disableGenerateContainerInfo) {
if (xdpOption) {
environment.try_emplace("GTK_USE_PORTAL", "1");
environment.try_emplace("QT_QPA_PLATFORMTHEME", "xdgdesktopportal");
}
Expand Down Expand Up @@ -1489,17 +1496,17 @@ utils::error::Result<void> ContainerCfgBuilder::buildEnv() noexcept
return LINGLONG_OK;
}

ContainerCfgBuilder &ContainerCfgBuilder::disableContainerInfo() noexcept
ContainerCfgBuilder &ContainerCfgBuilder::enableXDP(XdpOption option) noexcept
{
disableGenerateContainerInfo = true;
xdpOption = std::move(option);
return *this;
}

utils::error::Result<void> ContainerCfgBuilder::buildContainerInfo() noexcept
{
LINGLONG_TRACE("build container info");

if (disableGenerateContainerInfo) {
if (!xdpOption) {
return LINGLONG_OK;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@

namespace linglong::generator {

struct XdpOption
{
std::filesystem::path docMountPoint;
};

enum class ANNOTATION {
APPID,
BASEDIR,
Expand Down Expand Up @@ -133,7 +138,7 @@ class ContainerCfgBuilder

ContainerCfgBuilder &enableQuirkVolatile() noexcept;

ContainerCfgBuilder &disableContainerInfo() noexcept;
ContainerCfgBuilder &enableXDP(XdpOption option) noexcept;

ContainerCfgBuilder &
setExtensionMounts(std::vector<ocppi::runtime::config::types::Mount>) noexcept;
Expand Down Expand Up @@ -325,7 +330,7 @@ class ContainerCfgBuilder

bool isolateNetWorkEnabled = false;
bool disableUserNamespaceEnabled = false;
bool disableGenerateContainerInfo{ false };
std::optional<XdpOption> xdpOption;
bool applyPatchEnabled = true;
bool isolateTmp{ false };
bool devPassthru{ false };
Expand Down
Loading
Loading