From 50a0ad53ecc827705df3d165b6bee7259198775a Mon Sep 17 00:00:00 2001 From: ck Date: Wed, 22 May 2024 11:32:11 +0800 Subject: [PATCH] feat: add app extra/unset env config to fix #8667 you can - subpath:"/FoxitReader" appExtraEnvironments : "QT_QPA_PLATFORM=xcb" - subpath:"/FoxitReader" appEnvironmentsBlacklist : "QT_QPA_PLATFORM" ``` dde-dconfig set -a org.deepin.dde.application-manager -r org.deepin.dde.application-manager -k appExtraEnvironments -s "/FoxitReader" -v "[\"QT_QPA_PLATFORM=xcb\"]" dde-dconfig set -a org.deepin.dde.application-manager -r org.deepin.dde.application-manager -k appEnvironmentsBlacklist -s "/FoxitReader" -v "[\"QT_QPA_PLATFORM\"]" ``` Issue: https://github.com/linuxdeepin/developer-center/issues/8667 --- ...opspec.ApplicationManager1.Application.xml | 9 ++-- apps/app-launch-helper/src/main.cpp | 28 +++++++----- apps/app-launch-helper/src/variantvalue.cpp | 25 ++++------- misc/CMakeLists.txt | 4 +- .../org.deepin.dde.application-manager.json | 26 +++++++++++ src/constant.h | 4 ++ src/dbus/CMakeLists.txt | 1 + src/dbus/applicationservice.cpp | 35 +++++++++++++-- src/launchoptions.cpp | 23 +++++----- src/launchoptions.h | 45 ++++++++++++++++--- 10 files changed, 146 insertions(+), 54 deletions(-) create mode 100644 misc/dsg/configs/dde-application-manager/org.deepin.dde.application-manager.json diff --git a/api/dbus/org.desktopspec.ApplicationManager1.Application.xml b/api/dbus/org.desktopspec.ApplicationManager1.Application.xml index f15d40c..2d33b39 100644 --- a/api/dbus/org.desktopspec.ApplicationManager1.Application.xml +++ b/api/dbus/org.desktopspec.ApplicationManager1.Application.xml @@ -138,10 +138,13 @@ 1. `uid` (type u): The user id as who is that application will be run. This option might request a polikit authentication. - 2. `env` (type s): + 2. `env` (type as): passing some specific environment variables to Launch - this application, eg. 'LANG=en_US;PATH=xxx:yyy;' - 3. `path` (type s): + this application without them, eg. '[LANG=en_US, PATH=xxx:yyy]' + 3. `unsetEnv` (type as): + passed environment variables will be ignored when + launching this application, eg. '[LANG, PATH]' + 4. `path` (type s): set this application's working directory, please pass absolute directory path. NOTE: diff --git a/apps/app-launch-helper/src/main.cpp b/apps/app-launch-helper/src/main.cpp index 6365778..dd1b6c1 100644 --- a/apps/app-launch-helper/src/main.cpp +++ b/apps/app-launch-helper/src/main.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "constant.h" #include "types.h" @@ -140,6 +141,7 @@ int processExecStart(msg_ptr &msg, const std::deque &execArgs) DBusValueType getPropType(std::string_view key) { static std::unordered_map map{{"Environment", DBusValueType::ArrayOfString}, + {"UnsetEnvironment", DBusValueType::ArrayOfString}, {"WorkingDirectory", DBusValueType::String}, {"ExecSearchPath", DBusValueType::ArrayOfString}}; @@ -150,7 +152,7 @@ DBusValueType getPropType(std::string_view key) return DBusValueType::String; // fallback to string } -int appendPropValue(msg_ptr &msg, DBusValueType type, std::string_view value) +int appendPropValue(msg_ptr &msg, DBusValueType type, const std::list &value) { int ret; @@ -165,9 +167,11 @@ int appendPropValue(msg_ptr &msg, DBusValueType type, std::string_view value) return ret; } - if (ret = handler->appendValue(std::string{value}); ret < 0) { - sd_journal_perror("append property's variant value failed."); - return ret; + for (const auto &v : value) { + if (ret = handler->appendValue(std::string{v}); ret < 0) { + sd_journal_perror("append property's variant value failed."); + return ret; + } } if (ret = handler->closeVariant(); ret < 0) { @@ -178,13 +182,12 @@ int appendPropValue(msg_ptr &msg, DBusValueType type, std::string_view value) return 0; } -int processKVPair(msg_ptr &msg, const std::map &props) +int processKVPair(msg_ptr &msg, const std::map> &props) { int ret; if (!props.empty()) { for (auto [key, value] : props) { std::string keyStr{key}; - std::string valueStr{value}; if (ret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv"); ret < 0) { sd_journal_perror("open struct of properties failed."); return ret; @@ -195,7 +198,7 @@ int processKVPair(msg_ptr &msg, const std::map cmdLines) { std::string serviceName{"internalError"}; - std::map props; + std::map> props; while (!cmdLines.empty()) { // NOTE: avoid stl exception auto str = cmdLines.front(); if (str.size() < 2) { @@ -249,7 +252,7 @@ std::string cmdParse(msg_ptr &msg, std::deque cmdLines) cmdLines.pop_front(); continue; } - props[key] = kvStr.substr(splitIndex + 1); + props[key].push_back(kvStr.substr(splitIndex + 1)); cmdLines.pop_front(); continue; } @@ -265,18 +268,19 @@ std::string cmdParse(msg_ptr &msg, std::deque cmdLines) serviceName = "invalidInput"; return serviceName; } - int ret; if (props.find("unitName") == props.cend()) { sd_journal_perror("unitName doesn't exists."); serviceName = "invalidInput"; return serviceName; } - if (ret = sd_bus_message_append(msg, "s", props["unitName"].data()); ret < 0) { // unitName + + int ret; + if (ret = sd_bus_message_append(msg, "s", props["unitName"].front().data()); ret < 0) { // unitName sd_journal_perror("append unitName failed."); return serviceName; } - serviceName = props["unitName"]; + serviceName = props["unitName"].front(); props.erase("unitName"); if (ret = sd_bus_message_append(msg, "s", "replace"); ret < 0) { // start mode diff --git a/apps/app-launch-helper/src/variantvalue.cpp b/apps/app-launch-helper/src/variantvalue.cpp index c11cd88..73c4d9b 100644 --- a/apps/app-launch-helper/src/variantvalue.cpp +++ b/apps/app-launch-helper/src/variantvalue.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "variantValue.h" +#include "constant.h" #include std::unique_ptr creatValueHandler(msg_ptr &msg, DBusValueType type) @@ -34,29 +35,21 @@ int StringValue::appendValue(std::string &&value) noexcept int ASValue::openVariant() noexcept { - return sd_bus_message_open_container(msgRef(), SD_BUS_TYPE_VARIANT, "as"); + if (int ret = sd_bus_message_open_container(msgRef(), SD_BUS_TYPE_VARIANT, "as"); ret < 0) + return ret; + + return sd_bus_message_open_container(msgRef(), SD_BUS_TYPE_ARRAY, "s"); } int ASValue::closeVariant() noexcept { + if (int ret = sd_bus_message_close_container(msgRef()); ret < 0) + return ret; + return sd_bus_message_close_container(msgRef()); } int ASValue::appendValue(std::string &&value) noexcept { - std::string envs{std::move(value)}; - std::istringstream stream{envs}; - int ret{0}; - - if (ret = sd_bus_message_open_container(msgRef(), SD_BUS_TYPE_ARRAY, "s"); ret < 0) { - return ret; - } - - for (std::string line; std::getline(stream, line, ';');) { - if (ret = sd_bus_message_append(msgRef(), "s", line.data()); ret < 0) { - return ret; - } - } - - return sd_bus_message_close_container(msgRef()); + return sd_bus_message_append(msgRef(), "s", value.data()); } diff --git a/misc/CMakeLists.txt b/misc/CMakeLists.txt index 69c4d5d..15df56d 100644 --- a/misc/CMakeLists.txt +++ b/misc/CMakeLists.txt @@ -70,5 +70,7 @@ install(FILES ${CMAKE_CURRENT_LIST_DIR}/hooks.d/debFix.sh ) dtk_add_config_meta_files(APPID ${APPLICATION_SERVICEID} - FILES ${CMAKE_CURRENT_LIST_DIR}/dsg/configs/dde-application-manager/org.deepin.dde.am.json + FILES + ${CMAKE_CURRENT_LIST_DIR}/dsg/configs/dde-application-manager/org.deepin.dde.am.json + ${CMAKE_CURRENT_LIST_DIR}/dsg/configs/dde-application-manager/org.deepin.dde.application-manager.json ) diff --git a/misc/dsg/configs/dde-application-manager/org.deepin.dde.application-manager.json b/misc/dsg/configs/dde-application-manager/org.deepin.dde.application-manager.json new file mode 100644 index 0000000..5c85a0d --- /dev/null +++ b/misc/dsg/configs/dde-application-manager/org.deepin.dde.application-manager.json @@ -0,0 +1,26 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "appExtraEnvironments": { + "value": [], + "serial": 0, + "flags": [], + "name": "Launching app with extra environments", + "name[zh_CN]": "启动应用时附加额外环境变量", + "description": "Launching app with extra environments", + "permissions": "readwrite", + "visibility": "public" + }, + "appEnvironmentsBlacklist": { + "value": [], + "serial": 0, + "flags": [], + "name": "Ignore blacklisted environment variables before launching app", + "name[zh_CN]": "启动应用时取消某些环境变量", + "description": "Ignore blacklisted environment variables before launching app", + "permissions": "readwrite", + "visibility": "public" + } + } +} diff --git a/src/constant.h b/src/constant.h index 5aeb666..643bf15 100644 --- a/src/constant.h +++ b/src/constant.h @@ -65,4 +65,8 @@ constexpr auto ApplicationManagerHookDir = u8"/deepin/dde-application-manager/ho constexpr auto ApplicationManagerToolsConfig = u8"org.deepin.dde.am"; +constexpr auto ApplicationManagerConfig = u8"org.deepin.dde.application-manager"; +constexpr auto AppExtraEnvironments = u8"appExtraEnvironments"; +constexpr auto AppEnvironmentsBlacklist = u8"appEnvironmentsBlacklist"; + #endif diff --git a/src/dbus/CMakeLists.txt b/src/dbus/CMakeLists.txt index 92ffdd6..9a50b92 100644 --- a/src/dbus/CMakeLists.txt +++ b/src/dbus/CMakeLists.txt @@ -24,6 +24,7 @@ target_link_libraries( Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Concurrent + Dtk6::Core ) target_include_directories( diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index 0f2af33..bfe3ae2 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -14,6 +14,7 @@ #include "launchoptions.h" #include "desktopentry.h" #include "desktopfileparser.h" +#include "config.h" #include #include #include @@ -31,22 +32,50 @@ #include #include #include +#include + +static inline void appendEnvs(const QVariant &var, QStringList &envs) +{ + if (var.canConvert(QMetaType::QStringList)) { + envs.append(var.value()); + } else if (var.canConvert(QMetaType::QString)) { + envs.append(var.value().split(";", Qt::SkipEmptyParts)); + } +} void ApplicationService::appendExtraEnvironments(QVariantMap &runtimeOptions) const noexcept { - QStringList envs; + DCORE_USE_NAMESPACE + QStringList envs, unsetEnvs; const QString &env = environ(); if (!env.isEmpty()) envs.append(env); if (auto it = runtimeOptions.find("env"); it != runtimeOptions.cend()) { - envs.append(it->value()); + appendEnvs(*it, envs); + } + + if (auto it = runtimeOptions.find("unsetEnv"); it != runtimeOptions.cend()) { + appendEnvs(*it, unsetEnvs); + } + + std::unique_ptr config(DConfig::create(ApplicationServiceID, ApplicationManagerConfig, + QString("/%1").arg((id())))); // $appid as subpath + if (config->isValid()){ + const QStringList &extraEnvs = config->value(AppExtraEnvironments).toStringList(); + if (!extraEnvs.isEmpty()) + envs.append(extraEnvs); + + const QStringList &envsBlacklist = config->value(AppEnvironmentsBlacklist).toStringList(); + if (!envsBlacklist.isEmpty()) + unsetEnvs.append(envsBlacklist); } // it's useful for App to get itself AppId. envs.append(QString{"DSG_APP_ID=%1"}.arg(id())); - runtimeOptions.insert("env", envs.join(';')); + runtimeOptions.insert("env", envs); + runtimeOptions.insert("unsetEnv", unsetEnvs); } ApplicationService::ApplicationService(DesktopFile source, diff --git a/src/launchoptions.cpp b/src/launchoptions.cpp index 661cc22..52b85ca 100644 --- a/src/launchoptions.cpp +++ b/src/launchoptions.cpp @@ -17,6 +17,8 @@ QStringList generateCommand(const QVariantMap &props) noexcept options.emplace_back(std::make_unique(value)); } else if (key == setEnvLaunchOption::key()) { options.emplace_back(std::make_unique(value)); + } else if (key == unsetEnvLaunchOption::key()) { + options.emplace_back(std::make_unique(value)); } else if (key == hookLaunchOption::key()) { options.emplace_back(std::make_unique(value)); } else if (key == setWorkingPathLaunchOption::key()) { @@ -100,16 +102,6 @@ QStringList splitLaunchOption::generateCommandLine() const noexcept return QStringList{m_val.toString()}; } -QStringList setEnvLaunchOption::generateCommandLine() const noexcept -{ - auto str = m_val.toString(); - if (str.isEmpty()) { - return {}; - } - - return QStringList{QString{"--Environment=%1"}.arg(str)}; -} - QStringList setWorkingPathLaunchOption::generateCommandLine() const noexcept { auto str = m_val.toString(); @@ -120,13 +112,18 @@ QStringList setWorkingPathLaunchOption::generateCommandLine() const noexcept return QStringList{QString{"--WorkingDirectory=%1"}.arg(str)}; } -QStringList builtInSearchExecOption::generateCommandLine() const noexcept +QStringList StringListLaunchOption::generateCommandLine() const noexcept { auto list = m_val.toStringList(); if (list.isEmpty()) { return {}; } - auto content = list.join(';'); - return QStringList{QString{"--ExecSearchPath=%1"}.arg(content)}; + QStringList ret; + const QString ok = optionKey(); + for (const auto &ov : list) { + ret << QString{"%1=%2"}.arg(ok).arg(ov); + } + + return ret; } diff --git a/src/launchoptions.h b/src/launchoptions.h index 46af141..82c351f 100644 --- a/src/launchoptions.h +++ b/src/launchoptions.h @@ -27,6 +27,14 @@ protected: LaunchOption() = default; }; +struct StringListLaunchOption : public LaunchOption +{ + using LaunchOption::LaunchOption; + [[nodiscard]] QStringList generateCommandLine() const noexcept override; +protected: + [[nodiscard]] virtual const QString optionKey() const noexcept = 0; +}; + struct setUserLaunchOption : public LaunchOption { using LaunchOption::LaunchOption; @@ -43,9 +51,9 @@ struct setUserLaunchOption : public LaunchOption [[nodiscard]] QStringList generateCommandLine() const noexcept override; }; -struct setEnvLaunchOption : public LaunchOption +struct setEnvLaunchOption : public StringListLaunchOption { - using LaunchOption::LaunchOption; + using StringListLaunchOption::StringListLaunchOption; [[nodiscard]] const QString &type() const noexcept override { static QString tp{systemdOption}; @@ -56,7 +64,10 @@ struct setEnvLaunchOption : public LaunchOption static QString env{"env"}; return env; } - [[nodiscard]] QStringList generateCommandLine() const noexcept override; +protected: + [[nodiscard]] virtual const QString optionKey() const noexcept { + return QString("--Environment"); + } }; struct splitLaunchOption : public LaunchOption @@ -110,9 +121,9 @@ struct setWorkingPathLaunchOption : public LaunchOption [[nodiscard]] QStringList generateCommandLine() const noexcept override; }; -struct builtInSearchExecOption : public LaunchOption +struct builtInSearchExecOption : public StringListLaunchOption { - using LaunchOption::LaunchOption; + using StringListLaunchOption::StringListLaunchOption; [[nodiscard]] const QString &type() const noexcept override { static QString tp{systemdOption}; @@ -123,7 +134,29 @@ struct builtInSearchExecOption : public LaunchOption static QString key{"_builtIn_searchExec"}; return key; } - [[nodiscard]] QStringList generateCommandLine() const noexcept override; +protected: + [[nodiscard]] virtual const QString optionKey() const noexcept { + return QString("--ExecSearchPath"); + } +}; + +struct unsetEnvLaunchOption : public StringListLaunchOption +{ + using StringListLaunchOption::StringListLaunchOption; + [[nodiscard]] const QString &type() const noexcept override + { + static QString tp{systemdOption}; + return tp; + } + [[nodiscard]] static const QString &key() noexcept + { + static QString env{"unsetEnv"}; + return env; + } +protected: + [[nodiscard]] virtual const QString optionKey() const noexcept { + return QString("--UnsetEnvironment"); + } }; QStringList generateCommand(const QVariantMap &props) noexcept;