From 1121e867aea9f283b8e596c06a6889d252d8d31f Mon Sep 17 00:00:00 2001
From: tangjie02 <tangjie02@kylinsec.com.cn>
Date: Fri, 7 Jul 2023 18:04:51 +0800
Subject: [PATCH] feature(power): Compatiable two power profile daemon which
 contains hadess and tuned.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- 电源节能模式兼容hadess和tuned两个后端。

Signed-off-by: tangjie02 <tangjie02@kylinsec.com.cn>
---
 .../com.kylinsec.kiran.power.gschema.xml.in   |  10 +
 include/power-i.h                             |  23 ++
 ...com.kylinsec.Kiran.SessionDaemon.Power.xml |  16 ++
 plugins/power/power-manager.cpp               |  24 ++
 plugins/power/power-manager.h                 |   6 +
 plugins/power/save/power-save.cpp             |   4 +-
 plugins/power/save/power-save.h               |   2 +-
 .../power/wrapper/power-profiles-hadess.cpp   | 217 ++++++++++++++++++
 plugins/power/wrapper/power-profiles-hadess.h |  42 ++++
 .../power/wrapper/power-profiles-tuned.cpp    | 194 ++++++++++++++++
 plugins/power/wrapper/power-profiles-tuned.h  |  45 ++++
 plugins/power/wrapper/power-profiles.cpp      | 137 ++---------
 plugins/power/wrapper/power-profiles.h        |  41 ++--
 .../power/wrapper/power-wrapper-manager.cpp   |   2 +-
 14 files changed, 611 insertions(+), 152 deletions(-)
 create mode 100644 plugins/power/wrapper/power-profiles-hadess.cpp
 create mode 100644 plugins/power/wrapper/power-profiles-hadess.h
 create mode 100644 plugins/power/wrapper/power-profiles-tuned.cpp
 create mode 100644 plugins/power/wrapper/power-profiles-tuned.h

diff --git a/data/schemas/com.kylinsec.kiran.power.gschema.xml.in b/data/schemas/com.kylinsec.kiran.power.gschema.xml.in
index 094ea2f..2c4eef9 100644
--- a/data/schemas/com.kylinsec.kiran.power.gschema.xml.in
+++ b/data/schemas/com.kylinsec.kiran.power.gschema.xml.in
@@ -34,6 +34,11 @@
         <value nick="x11" value="2"/>
     </enum>
 
+    <enum id="com.kylinsec.kiran.power.profile-policy">
+        <value nick="hadess" value="1"/>
+        <value nick="tuned" value="2"/>
+    </enum>
+
     <schema id="com.kylinsec.kiran.power" path="/com/kylinsec/kiran/power/">
 
         <key name="computer-battery-idle-time" type="i">
@@ -136,5 +141,10 @@
             <default>'auto'</default>
             <description>Set the policy for obtaining brightness values.</description>
         </key>
+
+        <key name="profile-policy" enum="com.kylinsec.kiran.power.profile-policy">
+            <default>'hadess'</default>
+            <description>The profiles daemon used by current power plugin.</description>
+        </key>
     </schema>
 </schemalist>
diff --git a/include/power-i.h b/include/power-i.h
index 8d33a91..895c93e 100644
--- a/include/power-i.h
+++ b/include/power-i.h
@@ -116,6 +116,27 @@ extern "C"
         POWER_MONITOR_BACKLIGHT_POLICY_X11 = 2,
     };
 
+    /* 这里兼容两个后端的原因是power-profiles-daemon更好用，支持holdprofile接口，但支持的架构比较少。
+       如果要支持D2000等系统，要使用tuned作为后端。由于tuned不支持holdprofile，如果电源电量过低时自动切换到saver
+       模式后，如果电量充足了，就没法再切回原来的模式了，因此两者各有优缺点。*/
+    enum PowerProfilePolicy
+    {
+        // 使用power-profiles-daemon作为后端
+        POWER_PROFILE_POLICY_HADESS = 1,
+        // 使用tuned作为后端
+        POWER_PROFILE_POLICY_TUNED = 2,
+    };
+
+    enum PowerProfileMode
+    {
+        // 节能
+        POWER_PROFILE_MODE_SAVER = 0,
+        // 平衡
+        POWER_PROFILE_MODE_BALANCED = 1,
+        // 高性能
+        POWER_PROFILE_MODE_PERFORMANCE = 2,
+    };
+
 #define POWER_DBUS_NAME "com.kylinsec.Kiran.SessionDaemon.Power"
 #define POWER_OBJECT_PATH "/com/kylinsec/Kiran/SessionDaemon/Power"
 
@@ -157,6 +178,8 @@ extern "C"
 #define POWER_SCHEMA_TRAY_ICON_POLICY "tray-icon-policy"
 // 设置获取显示器亮度值的策略，'tool'是直接操作背光设备文件，'x11'是通过xrandr接口调节亮度
 #define POWER_SCHEMA_MONITOR_BACKLIGHT_POLICY "monitor-backlight-policy"
+// 选用的profiles后端
+#define POWER_SCHEMA_PROFILE_POLICY "profile-policy"
 
 #ifdef __cplusplus
 }
diff --git a/plugins/power/com.kylinsec.Kiran.SessionDaemon.Power.xml b/plugins/power/com.kylinsec.Kiran.SessionDaemon.Power.xml
index fe2f35e..afa5ebc 100644
--- a/plugins/power/com.kylinsec.Kiran.SessionDaemon.Power.xml
+++ b/plugins/power/com.kylinsec.Kiran.SessionDaemon.Power.xml
@@ -81,6 +81,13 @@
             <description>Enable cpu save energy when the ups or battery power is low.</description>
         </method>
 
+        <method name="SwitchProfile">
+            <arg type="i" name="mode" direction="in">
+                <description>The profile mode. Refer to PowerProfileMode in power-i.h</description>
+            </arg>
+            <description>Switch profile mode.</description>
+        </method>
+
         <property name="OnBattery" type="b" access="read">
             <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
             <description>Indicates whether the system is running on battery power.</description>
@@ -106,6 +113,11 @@
             <description>Whether does the cpu save energy when the ups or battery power is low.</description>
         </property>
 
+        <property name="ActiveProfile" type="i" access="read">
+            <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
+            <description>The active profile mode.</description>
+        </property>
+
         <signal name="IdleActionChanged">
             <arg name="device" type="i" />
             <arg name="supply" type="i" />
@@ -119,5 +131,9 @@
             <arg name="device" type="i" />
         </signal>
 
+        <signal name="ActiveProfileChanged">
+            <arg name="active_profile" type="i" />
+        </signal>
+
     </interface>
 </node>
diff --git a/plugins/power/power-manager.cpp b/plugins/power/power-manager.cpp
index 9282b85..cf5d8d5 100644
--- a/plugins/power/power-manager.cpp
+++ b/plugins/power/power-manager.cpp
@@ -27,6 +27,7 @@ PowerManager::PowerManager(PowerWrapperManager* wrapper_manager, PowerBacklight*
 {
     this->power_settings_ = Gio::Settings::create(POWER_SCHEMA_ID);
     this->upower_client_ = this->wrapper_manager_->get_default_upower();
+    this->profiles_ = this->wrapper_manager_->get_default_profiles();
 }
 
 PowerManager::~PowerManager()
@@ -56,6 +57,8 @@ void PowerManager::init()
                                                  sigc::mem_fun(this, &PowerManager::on_bus_acquired),
                                                  sigc::mem_fun(this, &PowerManager::on_name_acquired),
                                                  sigc::mem_fun(this, &PowerManager::on_name_lost));
+
+    this->profiles_->signal_active_profile_changed().connect(sigc::mem_fun(this, &PowerManager::on_active_profile_changed));
 }
 
 void PowerManager::SetIdleAction(gint32 device,
@@ -329,6 +332,12 @@ void PowerManager::EnableChargeLowSaver(bool enabled, MethodInvocation& invocati
     invocation.ret();
 }
 
+void PowerManager::SwitchProfile(gint32 mode, MethodInvocation& invocation)
+{
+    this->ActiveProfile_set(mode);
+    invocation.ret();
+}
+
 bool PowerManager::DisplayIdleDimmedEnabled_setHandler(bool value)
 {
     this->power_settings_->set_boolean(POWER_SCHEMA_ENABLE_DISPLAY_IDLE_DIMMED, value);
@@ -347,6 +356,11 @@ bool PowerManager::ChargeLowSaverEnabled_setHandler(bool value)
     return true;
 }
 
+bool PowerManager::ActiveProfile_setHandler(gint32 value)
+{
+    return this->profiles_->switch_profile(value);
+}
+
 bool PowerManager::OnBattery_get()
 {
     return this->upower_client_->get_on_battery();
@@ -372,6 +386,11 @@ bool PowerManager::ChargeLowSaverEnabled_get()
     return this->power_settings_->get_boolean(POWER_SCHEMA_ENABLE_CHARGE_LOW_SAVER);
 }
 
+gint32 PowerManager::ActiveProfile_get()
+{
+    return this->profiles_->get_active_profile();
+}
+
 void PowerManager::on_battery_changed(bool on_battery)
 {
     this->OnBattery_set(on_battery);
@@ -426,6 +445,11 @@ void PowerManager::on_brightness_changed(std::shared_ptr<PowerBacklightPercentag
     this->BrightnessChanged_signal.emit(backlight_device->get_type());
 }
 
+void PowerManager::on_active_profile_changed(int32_t profile_mode)
+{
+    this->ActiveProfileChanged_signal.emit(profile_mode);
+}
+
 void PowerManager::on_bus_acquired(const Glib::RefPtr<Gio::DBus::Connection>& connect, Glib::ustring name)
 {
     KLOG_PROFILE("name: %s", name.c_str());
diff --git a/plugins/power/power-manager.h b/plugins/power/power-manager.h
index 674de4d..97c8c7d 100644
--- a/plugins/power/power-manager.h
+++ b/plugins/power/power-manager.h
@@ -88,12 +88,15 @@ protected:
     virtual void EnableChargeLowDimmed(bool enabled, MethodInvocation &invocation);
     // 电量过低时是否进入节能模式
     virtual void EnableChargeLowSaver(bool enabled, MethodInvocation &invocation);
+    // 切换电源模式
+    virtual void SwitchProfile(gint32 mode, MethodInvocation &invocation);
 
     virtual bool OnBattery_setHandler(bool value) { return true; }
     virtual bool LidIsPresent_setHandler(bool value) { return true; }
     virtual bool DisplayIdleDimmedEnabled_setHandler(bool value);
     virtual bool ChargeLowDimmedEnabled_setHandler(bool value);
     virtual bool ChargeLowSaverEnabled_setHandler(bool value);
+    virtual bool ActiveProfile_setHandler(gint32 value);
 
     // 系统是否在使用电池供电
     virtual bool OnBattery_get();
@@ -102,6 +105,7 @@ protected:
     virtual bool DisplayIdleDimmedEnabled_get();
     virtual bool ChargeLowDimmedEnabled_get();
     virtual bool ChargeLowSaverEnabled_get();
+    virtual gint32 ActiveProfile_get();
 
 private:
     void init();
@@ -111,6 +115,7 @@ private:
 
     void on_settings_changed(const Glib::ustring &key);
     void on_brightness_changed(std::shared_ptr<PowerBacklightPercentage> backlight_device, int32_t brightness_value);
+    void on_active_profile_changed(int32_t profile_mode);
 
     void on_bus_acquired(const Glib::RefPtr<Gio::DBus::Connection> &connect, Glib::ustring name);
     void on_name_acquired(const Glib::RefPtr<Gio::DBus::Connection> &connect, Glib::ustring name);
@@ -122,6 +127,7 @@ private:
     PowerWrapperManager *wrapper_manager_;
     PowerBacklight *backlight_;
     std::shared_ptr<PowerUPower> upower_client_;
+    std::shared_ptr<PowerProfiles> profiles_;
 
     Glib::RefPtr<Gio::Settings> power_settings_;
 
diff --git a/plugins/power/save/power-save.cpp b/plugins/power/save/power-save.cpp
index 3dfcfce..c5b6bf8 100644
--- a/plugins/power/save/power-save.cpp
+++ b/plugins/power/save/power-save.cpp
@@ -162,7 +162,7 @@ void PowerSave::do_cpu_saver()
         return;
     }
 
-    this->cpu_saver_cookie_ = this->profiles_->hold_profile(POWER_PROFILE_SAVER, "battery or ups power low.", "kiran-session-daemon");
+    this->cpu_saver_cookie_ = this->profiles_->hold_profile(PowerProfileMode::POWER_PROFILE_MODE_SAVER, "battery or ups power low.");
     this->cpu_saver_timestamp_ = time(NULL);
 }
 
@@ -207,7 +207,7 @@ void PowerSave::on_monitor_brightness_changed(int32_t brightness_percentage)
     }
 }
 
-void PowerSave::on_active_profile_changed(const Glib::ustring& active_profile)
+void PowerSave::on_active_profile_changed(int32_t profile_mode)
 {
     if (this->cpu_saver_timestamp_ > 0 &&
         this->cpu_saver_timestamp_ + CPU_SAVER_INTERVAL < time(NULL))
diff --git a/plugins/power/save/power-save.h b/plugins/power/save/power-save.h
index ca0f6fd..6f994f5 100644
--- a/plugins/power/save/power-save.h
+++ b/plugins/power/save/power-save.h
@@ -54,7 +54,7 @@ private:
 
     void on_kbd_brightness_changed(int32_t brightness_percentage);
     void on_monitor_brightness_changed(int32_t brightness_percentage);
-    void on_active_profile_changed(const Glib::ustring& active_profile);
+    void on_active_profile_changed(int32_t profile_mode);
 
 private:
     static PowerSave* instance_;
diff --git a/plugins/power/wrapper/power-profiles-hadess.cpp b/plugins/power/wrapper/power-profiles-hadess.cpp
new file mode 100644
index 0000000..d6e4247
--- /dev/null
+++ b/plugins/power/wrapper/power-profiles-hadess.cpp
@@ -0,0 +1,217 @@
+/**
+ * Copyright (c) 2023 ~ 2024 KylinSec Co., Ltd. 
+ * kiran-cc-daemon is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2. 
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2 
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
+ * See the Mulan PSL v2 for more details.  
+ * 
+ * Author:     tangjie02 <tangjie02@kylinos.com.cn>
+ */
+
+#include "plugins/power/wrapper/power-profiles-hadess.h"
+#include "power-i.h"
+
+namespace Kiran
+{
+#define PROFILES_HADESS_MODE_SAVER "power-saver"
+#define PROFILES_HADESS_MODE_BALANCED "balanced"
+#define PROFILES_HADESS_MODE_PERFORMANCE "performance"
+
+#define PROFILES_HADESS_DBUS_NAME "net.hadess.PowerProfiles"
+#define PROFILES_HADESS_DBUS_OBJECT_PATH "/net/hadess/PowerProfiles"
+#define PROFILES_HADESS_DBUS_INTERFACE "net.hadess.PowerProfiles"
+#define PROFILES_HADESS_DBUS_PROP_ACTIVE_PROFILE "ActiveProfile"
+
+PowerProfilesHadess::PowerProfilesHadess()
+{
+    try
+    {
+        this->profiles_proxy_ = Gio::DBus::Proxy::create_for_bus_sync(Gio::DBus::BUS_TYPE_SYSTEM,
+                                                                      PROFILES_HADESS_DBUS_NAME,
+                                                                      PROFILES_HADESS_DBUS_OBJECT_PATH,
+                                                                      PROFILES_HADESS_DBUS_INTERFACE);
+    }
+    catch (const Glib::Error &e)
+    {
+        KLOG_WARNING("Failed to create bus sync: %s", e.what().c_str());
+        return;
+    }
+}
+
+void PowerProfilesHadess::init()
+{
+    this->profiles_proxy_->signal_properties_changed().connect(sigc::mem_fun(this, &PowerProfilesHadess::on_properties_changed));
+}
+
+bool PowerProfilesHadess::switch_profile(int32_t profile_mode)
+{
+    RETURN_VAL_IF_FALSE(this->profiles_proxy_, false);
+
+    auto profile_mode_str = this->porfile_mode_enum2str(profile_mode);
+    KLOG_DEBUG("Switch power active profile to %s.", profile_mode_str.c_str());
+
+    try
+    {
+        std::vector<Glib::VariantBase> params_base;
+        params_base.push_back(Glib::Variant<Glib::ustring>::create(PROFILES_HADESS_DBUS_INTERFACE));
+        params_base.push_back(Glib::Variant<Glib::ustring>::create(PROFILES_HADESS_DBUS_PROP_ACTIVE_PROFILE));
+        params_base.push_back(Glib::Variant<Glib::VariantBase>::create(Glib::Variant<Glib::ustring>::create((profile_mode_str))));
+        Glib::VariantContainerBase params = Glib::VariantContainerBase::create_tuple(params_base);
+        this->profiles_proxy_->call_sync("org.freedesktop.DBus.Properties.Set", params);
+    }
+    catch (const Glib::Error &e)
+    {
+        KLOG_WARNING("Failed to set property %s to %s: %s",
+                     PROFILES_HADESS_DBUS_PROP_ACTIVE_PROFILE,
+                     profile_mode_str.c_str(),
+                     e.what().c_str());
+        return false;
+    }
+    catch (const std::exception &e)
+    {
+        KLOG_WARNING("Failed to set property %s to %s: %s",
+                     PROFILES_HADESS_DBUS_PROP_ACTIVE_PROFILE,
+                     profile_mode_str.c_str(),
+                     e.what());
+        return false;
+    }
+    return true;
+}
+
+uint32_t PowerProfilesHadess::hold_profile(int32_t profile_mode, const std::string &reason)
+{
+    RETURN_VAL_IF_FALSE(this->profiles_proxy_, -1);
+
+    auto profile_mode_str = this->porfile_mode_enum2str(profile_mode);
+    KLOG_DEBUG("Hold power active profile to %s.", profile_mode_str.c_str());
+
+    try
+    {
+        auto parameters = g_variant_new("(sss)", profile_mode_str.c_str(), reason.c_str(), "kiran-session-daemon");
+        Glib::VariantContainerBase base(parameters, false);
+        auto retval = this->profiles_proxy_->call_sync("HoldProfile", base);
+        auto v1 = retval.get_child(0);
+        return Glib::VariantBase::cast_dynamic<Glib::Variant<uint32_t>>(v1).get();
+    }
+    catch (const Glib::Error &e)
+    {
+        KLOG_WARNING("Failed to call HoldProfile: %s", e.what().c_str());
+        return -1;
+    }
+    catch (const std::exception &e)
+    {
+        KLOG_WARNING("Failed to call HoldProfile: %s", e.what());
+        return -1;
+    }
+    return 0;
+}
+
+void PowerProfilesHadess::release_profile(uint32_t cookie)
+{
+    Glib::VariantContainerBase retval;
+
+    RETURN_IF_FALSE(this->profiles_proxy_);
+
+    auto parameters = g_variant_new("(u)", cookie);
+    Glib::VariantContainerBase base(parameters, false);
+
+    try
+    {
+        this->profiles_proxy_->call_sync("ReleaseProfile", base);
+    }
+    catch (const Glib::Error &e)
+    {
+        KLOG_WARNING("Failed to call ReleaseProfile: %s", e.what().c_str());
+    }
+}
+
+int32_t PowerProfilesHadess::get_active_profile()
+{
+    RETURN_VAL_IF_FALSE(this->profiles_proxy_, POWER_PROFILE_MODE_PERFORMANCE);
+
+    try
+    {
+        Glib::VariantBase value;
+        this->profiles_proxy_->get_cached_property(value, PROFILES_HADESS_DBUS_PROP_ACTIVE_PROFILE);
+        auto profile_mode_str = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(value).get();
+        return this->porfile_mode_str2enum(profile_mode_str);
+    }
+    catch (const std::exception &e)
+    {
+        KLOG_WARNING("Failed to get property %s: %s", PROFILES_HADESS_DBUS_PROP_ACTIVE_PROFILE, e.what());
+    }
+    // 默认返回高性能模式
+    return POWER_PROFILE_MODE_PERFORMANCE;
+}
+
+std::string PowerProfilesHadess::porfile_mode_enum2str(int32_t profile_mode)
+{
+    switch (profile_mode)
+    {
+    case PowerProfileMode::POWER_PROFILE_MODE_SAVER:
+        return PROFILES_HADESS_MODE_SAVER;
+    case PowerProfileMode::POWER_PROFILE_MODE_BALANCED:
+        return PROFILES_HADESS_MODE_BALANCED;
+    case PowerProfileMode::POWER_PROFILE_MODE_PERFORMANCE:
+        return PROFILES_HADESS_MODE_PERFORMANCE;
+    default:
+    {
+        KLOG_WARNING("Unknown profile mode %d, so return performance as current profile mode.", profile_mode);
+        return PROFILES_HADESS_MODE_PERFORMANCE;
+    }
+    }
+}
+
+int32_t PowerProfilesHadess::porfile_mode_str2enum(const std::string &profile_mode_str)
+{
+    switch (shash(profile_mode_str.c_str()))
+    {
+    case CONNECT(PROFILES_HADESS_MODE_SAVER, _hash):
+        return PowerProfileMode::POWER_PROFILE_MODE_SAVER;
+    case CONNECT(PROFILES_HADESS_MODE_BALANCED, _hash):
+        return PowerProfileMode::POWER_PROFILE_MODE_BALANCED;
+    case CONNECT(PROFILES_HADESS_MODE_PERFORMANCE, _hash):
+        return PowerProfileMode::POWER_PROFILE_MODE_PERFORMANCE;
+
+    default:
+    {
+        KLOG_WARNING("Unknown profile mode %s, so return performance as current profile mode.", profile_mode_str.c_str());
+        return PowerProfileMode::POWER_PROFILE_MODE_PERFORMANCE;
+    }
+    }
+}
+
+void PowerProfilesHadess::on_properties_changed(const Gio::DBus::Proxy::MapChangedProperties &changed_properties,
+                                                const std::vector<Glib::ustring> &invalidated_properties)
+{
+    try
+    {
+        for (auto &iter : changed_properties)
+        {
+            switch (shash(iter.first.c_str()))
+            {
+            case CONNECT(PROFILES_HADESS_DBUS_PROP_ACTIVE_PROFILE, _hash):
+            {
+                auto profile_mode_str = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(iter.second).get();
+                auto profile_mode = this->porfile_mode_str2enum(profile_mode_str);
+                this->active_profile_changed_.emit(profile_mode);
+                break;
+            }
+            default:
+                break;
+            }
+        }
+    }
+    catch (const std::exception &e)
+    {
+        KLOG_WARNING("%s", e.what());
+    }
+
+    return;
+}
+
+}  // namespace Kiran
diff --git a/plugins/power/wrapper/power-profiles-hadess.h b/plugins/power/wrapper/power-profiles-hadess.h
new file mode 100644
index 0000000..40bb4f5
--- /dev/null
+++ b/plugins/power/wrapper/power-profiles-hadess.h
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2023 ~ 2024 KylinSec Co., Ltd. 
+ * kiran-cc-daemon is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2. 
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2 
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
+ * See the Mulan PSL v2 for more details.  
+ * 
+ * Author:     tangjie02 <tangjie02@kylinos.com.cn>
+ */
+
+#pragma once
+
+#include "plugins/power/wrapper/power-profiles.h"
+
+namespace Kiran
+{
+class PowerProfilesHadess : public PowerProfiles
+{
+public:
+    PowerProfilesHadess();
+    virtual ~PowerProfilesHadess(){};
+
+    virtual void init();
+    virtual bool switch_profile(int32_t profile_mode);
+    virtual uint32_t hold_profile(int32_t profile_mode, const std::string &reason);
+    virtual void release_profile(uint32_t cookie);
+    virtual int32_t get_active_profile();
+
+private:
+    std::string porfile_mode_enum2str(int32_t profile_mode);
+    int32_t porfile_mode_str2enum(const std::string &profile_mode_str);
+    void on_properties_changed(const Gio::DBus::Proxy::MapChangedProperties &changed_properties,
+                               const std::vector<Glib::ustring> &invalidated_properties);
+
+private:
+    Glib::RefPtr<Gio::DBus::Proxy> profiles_proxy_;
+};
+}  // namespace Kiran
diff --git a/plugins/power/wrapper/power-profiles-tuned.cpp b/plugins/power/wrapper/power-profiles-tuned.cpp
new file mode 100644
index 0000000..ee1fa7b
--- /dev/null
+++ b/plugins/power/wrapper/power-profiles-tuned.cpp
@@ -0,0 +1,194 @@
+/**
+ * Copyright (c) 2023 ~ 2024 KylinSec Co., Ltd. 
+ * kiran-cc-daemon is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2. 
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2 
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
+ * See the Mulan PSL v2 for more details.  
+ * 
+ * Author:     tangjie02 <tangjie02@kylinos.com.cn>
+ */
+
+#include "plugins/power/wrapper/power-profiles-tuned.h"
+#include "power-i.h"
+
+namespace Kiran
+{
+#define PROFILES_TUNED_MODE_SAVER "powersave"
+#define PROFILES_TUNED_MODE_BALANCED "balanced"
+#define PROFILES_TUNED_MODE_PERFORMANCE "throughput-performance"
+
+#define PROFILES_TUNED_DBUS_NAME "com.redhat.tuned"
+#define PROFILES_TUNED_DBUS_OBJECT_PATH "/Tuned"
+#define PROFILES_TUNED_DBUS_INTERFACE "com.redhat.tuned.control"
+
+PowerProfilesTuned::PowerProfilesTuned()
+{
+    try
+    {
+        this->profiles_proxy_ = Gio::DBus::Proxy::create_for_bus_sync(Gio::DBus::BUS_TYPE_SYSTEM,
+                                                                      PROFILES_TUNED_DBUS_NAME,
+                                                                      PROFILES_TUNED_DBUS_OBJECT_PATH,
+                                                                      PROFILES_TUNED_DBUS_INTERFACE);
+    }
+    catch (const Glib::Error &e)
+    {
+        KLOG_WARNING("Failed to create bus sync: %s", e.what().c_str());
+        return;
+    }
+}
+
+void PowerProfilesTuned::init()
+{
+    this->profiles_proxy_->signal_signal().connect(sigc::mem_fun(this, &PowerProfilesTuned::on_profile_signal));
+}
+
+bool PowerProfilesTuned::switch_profile(int32_t profile_mode)
+{
+    auto retval = this->hold_profile(profile_mode, std::string());
+    return (retval >= 0);
+}
+
+uint32_t PowerProfilesTuned::hold_profile(int32_t profile_mode, const std::string &)
+{
+    RETURN_VAL_IF_FALSE(this->profiles_proxy_, 0);
+
+    auto profile_mode_str = this->porfile_mode_enum2str(profile_mode);
+    KLOG_DEBUG("Hold power active profile to %s.", profile_mode_str.c_str());
+
+    try
+    {
+        auto parameters = g_variant_new("(s)", profile_mode_str.c_str());
+        Glib::VariantContainerBase base(parameters, false);
+        auto retval = this->profiles_proxy_->call_sync("switch_profile", base);
+
+        auto ret_parameters = retval.get_child(0);
+        auto ret_parameters_tuple = Glib::VariantBase::cast_dynamic<Glib::Variant<std::tuple<bool, Glib::ustring>>>(ret_parameters);
+        auto successed = ret_parameters_tuple.get_child<bool>(0);
+        auto reason = ret_parameters_tuple.get_child<Glib::ustring>(1);
+
+        if (!successed)
+        {
+            KLOG_WARNING("Failed to call switch_profile: %s.", reason.c_str());
+            return -1;
+        }
+    }
+    catch (const Glib::Error &e)
+    {
+        KLOG_WARNING("Failed to call switch_profile: %s", e.what().c_str());
+        return -1;
+    }
+    catch (const std::exception &e)
+    {
+        KLOG_WARNING("Failed to call switch_profile: %s", e.what());
+        return -1;
+    }
+
+    return 0;
+}
+
+int32_t PowerProfilesTuned::get_active_profile()
+{
+    RETURN_VAL_IF_FALSE(this->profiles_proxy_, POWER_PROFILE_MODE_PERFORMANCE);
+
+    std::string profile_mode_str;
+    try
+    {
+        auto retval = this->profiles_proxy_->call_sync("active_profile", Glib::VariantContainerBase());
+        auto v1 = retval.get_child(0);
+        profile_mode_str = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(v1).get();
+    }
+    catch (const Glib::Error &e)
+    {
+        KLOG_WARNING("Failed to call active_profile: %s", e.what().c_str());
+    }
+    catch (const std::exception &e)
+    {
+        KLOG_WARNING("Failed to call active_profile: %s", e.what());
+    }
+
+    return this->porfile_mode_str2enum(profile_mode_str);
+}
+
+std::string PowerProfilesTuned::porfile_mode_enum2str(int32_t profile_mode)
+{
+    switch (profile_mode)
+    {
+    case PowerProfileMode::POWER_PROFILE_MODE_SAVER:
+        return PROFILES_TUNED_MODE_SAVER;
+    case PowerProfileMode::POWER_PROFILE_MODE_BALANCED:
+        return PROFILES_TUNED_MODE_BALANCED;
+    case PowerProfileMode::POWER_PROFILE_MODE_PERFORMANCE:
+        return PROFILES_TUNED_MODE_PERFORMANCE;
+    default:
+    {
+        KLOG_WARNING("Unknown profile mode %d, so return performance as current profile mode.", profile_mode);
+        return PROFILES_TUNED_MODE_PERFORMANCE;
+    }
+    }
+}
+
+int32_t PowerProfilesTuned::porfile_mode_str2enum(const std::string &profile_mode_str)
+{
+    switch (shash(profile_mode_str.c_str()))
+    {
+    case CONNECT(PROFILES_TUNED_MODE_SAVER, _hash):
+        return PowerProfileMode::POWER_PROFILE_MODE_SAVER;
+    case CONNECT(PROFILES_TUNED_MODE_BALANCED, _hash):
+        return PowerProfileMode::POWER_PROFILE_MODE_BALANCED;
+    case CONNECT(PROFILES_TUNED_MODE_PERFORMANCE, _hash):
+        return PowerProfileMode::POWER_PROFILE_MODE_PERFORMANCE;
+
+    default:
+    {
+        KLOG_WARNING("Unknown profile mode %s, so return performance as current profile mode.", profile_mode_str.c_str());
+        return PowerProfileMode::POWER_PROFILE_MODE_PERFORMANCE;
+    }
+    }
+}
+
+void PowerProfilesTuned::on_profile_signal(const Glib::ustring &sender_name,
+                                           const Glib::ustring &signal_name,
+                                           const Glib::VariantContainerBase &parameters)
+{
+    switch (shash(signal_name.c_str()))
+    {
+    case "profile_changed"_hash:
+    {
+        try
+        {
+            Glib::VariantContainerBase v1;
+            Glib::VariantContainerBase v2;
+            Glib::VariantContainerBase v3;
+            parameters.get_child(v1, 0);
+            parameters.get_child(v2, 1);
+            parameters.get_child(v3, 2);
+
+            auto profiled_mode_str = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(v1).get();
+            auto successed = Glib::VariantBase::cast_dynamic<Glib::Variant<bool>>(v2).get();
+            auto reason = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(v3).get();
+
+            if (!successed)
+            {
+                KLOG_WARNING("Failed to call switch_profile: %s.", reason.c_str());
+            }
+            else
+            {
+                this->active_profile_changed_.emit(this->porfile_mode_str2enum(profiled_mode_str));
+            }
+        }
+        catch (const std::exception &e)
+        {
+            KLOG_WARNING("%s.", e.what());
+        }
+        break;
+    }
+    default:
+        break;
+    }
+}
+
+}  // namespace Kiran
diff --git a/plugins/power/wrapper/power-profiles-tuned.h b/plugins/power/wrapper/power-profiles-tuned.h
new file mode 100644
index 0000000..af1fcf5
--- /dev/null
+++ b/plugins/power/wrapper/power-profiles-tuned.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2023 ~ 2024 KylinSec Co., Ltd. 
+ * kiran-cc-daemon is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2. 
+ * You may obtain a copy of Mulan PSL v2 at:
+ *          http://license.coscl.org.cn/MulanPSL2 
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
+ * See the Mulan PSL v2 for more details.  
+ * 
+ * Author:     tangjie02 <tangjie02@kylinos.com.cn>
+ */
+
+#pragma once
+
+#include "plugins/power/wrapper/power-profiles.h"
+
+namespace Kiran
+{
+class PowerProfilesTuned : public PowerProfiles
+{
+public:
+    PowerProfilesTuned();
+    virtual ~PowerProfilesTuned(){};
+
+    virtual void init();
+    virtual bool switch_profile(int32_t profile_mode);
+    // 这里永远返回0，因为不支持hold操作
+    virtual uint32_t hold_profile(int32_t profile_mode, const std::string& reason);
+    // 不支持该操作，什么都不执行
+    virtual void release_profile(uint32_t cookie){};
+    virtual int32_t get_active_profile();
+
+private:
+    std::string porfile_mode_enum2str(int32_t profile_mode);
+    int32_t porfile_mode_str2enum(const std::string& profile_mode_str);
+    void on_profile_signal(const Glib::ustring& sender_name,
+                           const Glib::ustring& signal_name,
+                           const Glib::VariantContainerBase& parameters);
+
+private:
+    Glib::RefPtr<Gio::DBus::Proxy> profiles_proxy_;
+};
+}  // namespace Kiran
diff --git a/plugins/power/wrapper/power-profiles.cpp b/plugins/power/wrapper/power-profiles.cpp
index d7ba1b3..ac5f15c 100644
--- a/plugins/power/wrapper/power-profiles.cpp
+++ b/plugins/power/wrapper/power-profiles.cpp
@@ -13,135 +13,24 @@
  */
 
 #include "plugins/power/wrapper/power-profiles.h"
+#include "plugins/power/wrapper/power-profiles-hadess.h"
+#include "plugins/power/wrapper/power-profiles-tuned.h"
+#include "power-i.h"
 
 namespace Kiran
 {
-#define PROFILES_DBUS_NAME "net.hadess.PowerProfiles"
-#define PROFILES_DBUS_OBJECT_PATH "/net/hadess/PowerProfiles"
-#define PROFILES_DBUS_INTERFACE "net.hadess.PowerProfiles"
-#define PROFILES_DBUS_PROP_ACTIVE_PROFILE "ActiveProfile"
-
-PowerProfiles::PowerProfiles()
-{
-    try
-    {
-        this->profiles_proxy_ = Gio::DBus::Proxy::create_for_bus_sync(Gio::DBus::BUS_TYPE_SYSTEM,
-                                                                      PROFILES_DBUS_NAME,
-                                                                      PROFILES_DBUS_OBJECT_PATH,
-                                                                      PROFILES_DBUS_INTERFACE);
-    }
-    catch (const Glib::Error &e)
-    {
-        KLOG_WARNING("Failed to create bus sync: %s", e.what().c_str());
-        return;
-    }
-}
-
-void PowerProfiles::init()
-{
-    this->profiles_proxy_->signal_properties_changed().connect(sigc::mem_fun(this, &PowerProfiles::on_properties_changed));
-}
-
-uint32_t PowerProfiles::hold_profile(const std::string &profile,
-                                     const std::string &reason,
-                                     const std::string &application_id)
-{
-    Glib::VariantContainerBase retval;
-
-    RETURN_VAL_IF_FALSE(this->profiles_proxy_, false);
-
-    auto parameters = g_variant_new("(sss)", profile.c_str(), reason.c_str(), application_id.c_str());
-    Glib::VariantContainerBase base(parameters, false);
-
-    KLOG_DEBUG("Set power active profile to %s.", profile.c_str());
-
-    try
-    {
-        retval = this->profiles_proxy_->call_sync("HoldProfile", base);
-    }
-    catch (const Glib::Error &e)
-    {
-        KLOG_WARNING("%s", e.what().c_str());
-        return 0;
-    }
-
-    try
-    {
-        auto v1 = retval.get_child(0);
-        auto cookie = Glib::VariantBase::cast_dynamic<Glib::Variant<uint32_t>>(v1).get();
-        return cookie;
-    }
-    catch (const std::exception &e)
-    {
-        KLOG_WARNING("%s", e.what());
-    }
-
-    return 0;
-}
-
-void PowerProfiles::release_profile(uint32_t cookie)
+std::shared_ptr<PowerProfiles> PowerProfiles::create()
 {
-    Glib::VariantContainerBase retval;
-
-    RETURN_IF_FALSE(this->profiles_proxy_);
-
-    auto parameters = g_variant_new("(u)", cookie);
-    Glib::VariantContainerBase base(parameters, false);
-
-    try
+    auto power_settings = Gio::Settings::create(POWER_SCHEMA_ID);
+    auto profiles_policy = power_settings->get_enum(POWER_SCHEMA_PROFILE_POLICY);
+    switch (profiles_policy)
     {
-        this->profiles_proxy_->call_sync("ReleaseProfile", base);
-    }
-    catch (const Glib::Error &e)
-    {
-        KLOG_WARNING("%s", e.what().c_str());
+    case PowerProfilePolicy::POWER_PROFILE_POLICY_HADESS:
+        return std::make_shared<PowerProfilesHadess>();
+    case PowerProfilePolicy::POWER_PROFILE_POLICY_TUNED:
+        return std::make_shared<PowerProfilesTuned>();
+    default:
+        return std::make_shared<PowerProfilesTuned>();
     }
 }
-
-std::string PowerProfiles::get_active_profile()
-{
-    RETURN_VAL_IF_FALSE(this->profiles_proxy_, POWER_PROFILE_BALANCED);
-
-    try
-    {
-        Glib::VariantBase value;
-        this->profiles_proxy_->get_cached_property(value, PROFILES_DBUS_PROP_ACTIVE_PROFILE);
-        return Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(value).get();
-    }
-    catch (const std::exception &e)
-    {
-        KLOG_WARNING("%s", e.what());
-    }
-    // 默认返回平衡模式
-    return POWER_PROFILE_BALANCED;
-}
-
-void PowerProfiles::on_properties_changed(const Gio::DBus::Proxy::MapChangedProperties &changed_properties,
-                                          const std::vector<Glib::ustring> &invalidated_properties)
-{
-    try
-    {
-        for (auto &iter : changed_properties)
-        {
-            switch (shash(iter.first.c_str()))
-            {
-            case CONNECT(PROFILES_DBUS_PROP_ACTIVE_PROFILE, _hash):
-            {
-                auto active_profile = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(iter.second).get();
-                this->active_profile_changed_.emit(active_profile);
-                break;
-            }
-            default:
-                break;
-            }
-        }
-    }
-    catch (const std::exception &e)
-    {
-        KLOG_WARNING("%s", e.what());
-    }
-
-    return;
-}
-
 }  // namespace Kiran
diff --git a/plugins/power/wrapper/power-profiles.h b/plugins/power/wrapper/power-profiles.h
index cf5b943..8f9f6f7 100644
--- a/plugins/power/wrapper/power-profiles.h
+++ b/plugins/power/wrapper/power-profiles.h
@@ -12,41 +12,34 @@
  * Author:     tangjie02 <tangjie02@kylinos.com.cn>
  */
 
+#pragma once
+
 #include "lib/base/base.h"
 
 namespace Kiran
 {
-#define POWER_PROFILE_SAVER "power-saver"
-#define POWER_PROFILE_BALANCED "balanced"
-#define POWER_PROFILE_PERFORMANCE "performance"
-
 class PowerProfiles
 {
 public:
-    PowerProfiles();
-    virtual ~PowerProfiles(){};
-
-    void init();
+    // 根据gsettings的设置创建不同的子类
+    static std::shared_ptr<PowerProfiles> create();
 
-    // 设置模式，如果调用了ReleaseProfile，则进行恢复。如果有其他用户进行了手动设置（直接修改ActiveProfile属性），则不再hold当前模式
-    uint32_t hold_profile(const std::string &profile,
-                          const std::string &reason,
-                          const std::string &application_id);
+    virtual void init() = 0;
 
+    // 设置模式
+    virtual bool switch_profile(int32_t profile_mode) = 0;
+    /* 临时设置模式，如果调用了ReleaseProfile，则进行恢复。如果调用了switch_profile，则不再hold当前模式
+       如果返回值大于0，则表示一个cookie；如果返回值等于0；则表示无法hold，只能永久生效，功能同switch_profile；
+       如果小于0则表示调用失败。*/
+    virtual uint32_t hold_profile(int32_t profile_mode, const std::string &reason) = 0;
     // 释放hold_profile操作。恢复到之前的模式
-    void release_profile(uint32_t cookie);
-
-    std::string get_active_profile();
-
-    sigc::signal<void, const Glib::ustring &> &signal_active_profile_changed() { return this->active_profile_changed_; };
-
-private:
-    void on_properties_changed(const Gio::DBus::Proxy::MapChangedProperties &changed_properties,
-                               const std::vector<Glib::ustring> &invalidated_properties);
+    virtual void release_profile(uint32_t cookie) = 0;
+    // 获取当前模式
+    virtual int32_t get_active_profile() = 0;
 
-private:
-    Glib::RefPtr<Gio::DBus::Proxy> profiles_proxy_;
+    sigc::signal<void, int32_t> &signal_active_profile_changed() { return this->active_profile_changed_; };
 
-    sigc::signal<void, const Glib::ustring &> active_profile_changed_;
+protected:
+    sigc::signal<void, int32_t> active_profile_changed_;
 };
 }  // namespace Kiran
diff --git a/plugins/power/wrapper/power-wrapper-manager.cpp b/plugins/power/wrapper/power-wrapper-manager.cpp
index 685000d..c60f46b 100644
--- a/plugins/power/wrapper/power-wrapper-manager.cpp
+++ b/plugins/power/wrapper/power-wrapper-manager.cpp
@@ -22,7 +22,7 @@ PowerWrapperManager::PowerWrapperManager()
     this->screensaver_ = std::make_shared<PowerScreenSaver>();
     this->session_ = std::make_shared<PowerSession>();
     this->upower_ = std::make_shared<PowerUPower>();
-    this->profiles_ = std::make_shared<PowerProfiles>();
+    this->profiles_ = PowerProfiles::create();
 }
 
 PowerWrapperManager::~PowerWrapperManager()
-- 
2.36.1

