power: Support power lock operation on headless profile 14/318214/1 accepted/tizen/9.0/unified/20250115.070545
authorYoungjae Cho <y0.cho@samsung.com>
Mon, 23 Dec 2024 08:25:39 +0000 (17:25 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Tue, 14 Jan 2025 07:25:47 +0000 (16:25 +0900)
Previously, the device API only supports power lock operation at headed
profile via display module. However, as the device API has changed to
support power lock opeartions not only on headed but also on headless
profile, it was required for the deviced to handle such requests on
headless profile accordingly.

To get to this goal, this patch is made up of three parts.
 1) Separate power lock code from power-dbus.c to power-lock.c.
 2) Power resource attributes for managing power lock have been newly
    added to make other modules utilize it via resource-manager.
    In this patch, specifically the display module makes use of it.
     • DEVICED_POWER_ATTR_UINT64_3_CPU_LOCK
       : A setter that controls cpulock. Takes 3 parameters.
          - int: acquire(1) or release(0) lock
          - pid_t: pid of requester
          - int: timeout of the lock, only effective when the
                 first parameter is acquire(1)
     • DEVICED_POWER_ATTR_INT_CPU_LOCK_COUNT
       : A getter for getting cpu lock count
    The resource-power.h, a wrapper accessing the above attributes,
    has newly been introduced. In the future, not only the deviced's
    modules but any plugins also could make use of it.
 3) Add condition branches at display-dbus.c to handle cpu lock request
    on headless profile. The reason why we go thorugh the display
    module, not directly to the power module, is that the current device
    API documentation has not specified privilege necessary for calling
    power method. As adding additional privilege to a public API is not a
    trivial work, we have implemented in this way for now.

Change-Id: If7523325fa00c8d80cc4d35cf86628700d234f8c
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
packaging/deviced.spec
src/display/display-lock.c
src/power/power-dbus.c
src/power/power-lock.c [new file with mode: 0644]
src/power/power-lock.h [new file with mode: 0644]
src/power/resource-power.c
src/power/resource-power.h [new file with mode: 0644]

index bdb1807193aac9c6cd43d822600bd4184b7ab7c7..86258fcba2f27225c7a8ec01ea88f63b068fa769 100644 (file)
@@ -5,7 +5,7 @@
 
 Name:       deviced
 Summary:    Deviced
-Version:    10.0.0
+Version:    10.0.1
 Release:    1
 Group:      System/Management
 License:    Apache-2.0
index 06fd15f28d1a8f740abd9d3382dc6799b96d5747..824376eeadffdae460961d7d0b7d2e632206a0fb 100644 (file)
@@ -22,6 +22,7 @@
  *
  */
 #include <libsyscommon/proc.h>
+#include <system_info.h>
 #include <system/syscommon-plugin-deviced-common-interface.h>
 
 #include "shared/common.h"
@@ -39,6 +40,7 @@
 #include "shared/log.h"
 #include "shared/log-macro.h"
 #include "shared/apps.h"
+#include "power/resource-power.h"
 
 #define METHOD_APP_STATUS      "CheckAppStatus"
 #define PID_MAX                        6
@@ -61,6 +63,29 @@ static GList *g_display_bglock_list[SYSCOMMON_DEVICED_DISPLAY_STATE_END]; /* loc
 
 static void broadcast_lock_changed(enum syscommon_deviced_display_state state);
 
+static int get_display_feature(bool *display_feature)
+{
+       static int initialized = false;
+       static bool feature = false;
+       int ret;
+
+       if (!display_feature)
+               return -EINVAL;
+
+       if (initialized) {
+               *display_feature = feature;
+               return 0;
+       }
+
+       ret = system_info_get_platform_bool("http://tizen.org/feature/display", &feature);
+       if (ret != SYSTEM_INFO_ERROR_NONE)
+               return -EINVAL;
+
+       initialized = true;
+
+       return 0;
+}
+
 static gboolean __find_lock(gconstpointer data, gconstpointer udata)
 {
        const struct display_lock *dl = (const struct display_lock *) data;
@@ -207,6 +232,26 @@ int display_lock_is_state_locked(enum syscommon_deviced_display_state state)
 int display_lock_get_lock_count(enum syscommon_deviced_display_state state)
 {
        int nlock = 0;
+       bool display_feature = false;
+       int ret;
+
+       ret = get_display_feature(&display_feature);
+       if (ret < 0) {
+               _E("Failed to get display feature.");
+               return 0;
+       }
+
+       if (!display_feature) {
+               if (state != SYSCOMMON_DEVICED_DISPLAY_STATE_OFF)
+                       return 0; /* Without display feature, lock count other than LCDOFF is 0 */
+
+               /* Delegate the LCDOFF lock count to power module when it has no display feature */
+               ret = power_resource_get_cpulock_count(&nlock);
+               if (ret < 0)
+                       return 0;
+
+               return nlock;
+       }
 
        nlock += g_list_length(g_display_fglock_list[state]);
        nlock += g_list_length(g_display_bglock_list[state]);
@@ -778,6 +823,23 @@ int display_lock_request_lock_with_option(pid_t pid, int s_bits, int flag, int t
 {
        int cond;
        PMMsg recv_data;
+       bool display_feature = false;
+       int ret;
+
+       ret = get_display_feature(&display_feature);
+       if (ret < 0) {
+               _E("Failed to get display feature.");
+               return -EINVAL;
+       }
+
+       if (!display_feature) {
+               /* Delegate the LCDOFF lock request to power module when it has no display feature */
+               if (s_bits == LCD_OFF)
+                       return power_resource_acquire_cpulock(pid, timeout);
+
+               _W("Locking on the state other than LCDOFF has no effect without display feature, but do it anyway, pid=%d, bits=%#x",
+                       pid, s_bits);
+       }
 
        cond = display_util_get_display_state(s_bits);
        if (cond < 0)
@@ -805,6 +867,23 @@ int display_lock_request_unlock_with_option(pid_t pid, int s_bits, int flag)
 {
        int cond;
        PMMsg recv_data;
+       bool display_feature = false;
+       int ret;
+
+       ret = get_display_feature(&display_feature);
+       if (ret < 0) {
+               _E("Failed to get display feature.");
+               return -EINVAL;
+       }
+
+       if (!display_feature) {
+               /* Delegate the LCDOFF lock request to power module when it has no display feature */
+               if (s_bits == LCD_OFF)
+                       return power_resource_release_cpulock(pid);
+
+               _W("Unlocking on the state other than LCDOFF has no effect without display feature, but do it anyway, pid=%d, bits=%#x",
+                       pid, s_bits);
+       }
 
        cond = display_util_get_display_state(s_bits);
        if (cond < 0)
index 6c87b0820cf82dccb5dab75962e53816407bd984..78199d6e8792dbb169cfa8aeae6d700e3780b85c 100644 (file)
 #include "shared/device-notifier.h"
 
 #include "power-suspend.h"
+#include "power-lock.h"
 #include "power.h"
 
-#ifndef PROCESS_CHECK_TIMEOUT
-#define PROCESS_CHECK_TIMEOUT    600000 /* milisecond, 10 minute */
-#endif
-
-static GList *lock_list;
-
-struct lock_node {
-       pid_t pid;
-       char comm[64];
-       int timer_id;
-       int timeout;
-       char locktime[64];
-};
-
 static uint64_t convert_device_state_to_deviced(device_power_state_e state)
 {
        if (state == DEVICE_POWER_STATE_START)
@@ -115,63 +102,6 @@ static uint64_t convert_device_transient_state_bitmap_to_deviced(device_power_tr
        return deviced_bitmap;
 }
 
-static void print_lock_node(void)
-{
-       GList *elem;
-       struct lock_node *node;
-
-       _D("List of remaining CPU locks");
-       SYS_G_LIST_FOREACH(lock_list, elem, node)
-               _D(" pid=%d(%s), locktime=%s, timeout=%dms",
-                       node->pid, node->comm, node->locktime, node->timeout);
-}
-
-static void remove_lock_node(struct lock_node *node)
-{
-       if (!node)
-               return;
-
-       if (node->timer_id) {
-               g_source_remove(node->timer_id);
-               node->timer_id = 0;
-       }
-
-       SYS_G_LIST_REMOVE(lock_list, node);
-       free(node);
-
-       /* Check the lock_list is empty after removing the node.
-        * If it is, then request wake unlock */
-       if (SYS_G_LIST_LENGTH(lock_list) == 0)
-               power_release_wakelock();
-       else
-               print_lock_node();
-}
-
-static gboolean lock_expired_cb(void *data)
-{
-       struct lock_node *this = (struct lock_node *) data;
-
-       _D("Powerlock of pid=%d(%s) for %dms is expired", this->pid, this->comm, this->timeout);
-       remove_lock_node(this);
-
-       return G_SOURCE_REMOVE;
-}
-
-/* check existance of process for every PROCESS_CHECK_TIMEOUT
- * if the process has requested infinite CPU lock */
-static gboolean process_check_cb(void *data)
-{
-       struct lock_node *this = (struct lock_node *) data;
-
-       if (kill(this->pid, 0) != 0) {
-               _D("pid=%d(%s) is not found, deviced release the CPU lock", this->pid, this->comm);
-               remove_lock_node(this);
-               return G_SOURCE_REMOVE;
-       }
-
-       return G_SOURCE_CONTINUE;
-}
-
 static GVariant *dbus_power_lock_cpu(GDBusConnection *conn,
        const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
        GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
@@ -179,12 +109,6 @@ static GVariant *dbus_power_lock_cpu(GDBusConnection *conn,
        int timeout;
        int ret = 0;
        pid_t pid;
-       GList *elem;
-       struct lock_node *node;
-
-       time_t current;
-       struct tm current_tm;
-       struct tm *rettm;
 
        /* lock timeout in milisecond */
        g_variant_get(param, "(i)", &timeout);
@@ -200,58 +124,7 @@ static GVariant *dbus_power_lock_cpu(GDBusConnection *conn,
                goto out;
        }
 
-       SYS_G_LIST_FOREACH(lock_list, elem, node) {
-               if (node->pid == pid)
-                       break;
-       }
-
-       if (!node) {
-               int retval;
-               char commpath[128];
-               char *sep;
-
-               node = calloc(1, sizeof(struct lock_node));
-               if (!node) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               node->pid = pid;
-               snprintf(commpath, sizeof(commpath), "/proc/%d/comm", pid);
-               retval = sys_get_str(commpath, node->comm, sizeof(node->comm));
-               if (retval != 0)
-                       snprintf(node->comm, sizeof(node->comm), "Unknown");
-
-               /* remove whitesapce */
-               sep = strpbrk(node->comm, " \n\t\r");
-               if (sep)
-                       *sep = '\0';
-
-               SYS_G_LIST_APPEND(lock_list, node);
-       }
-
-       /* set current time for logging */
-       current = time(NULL);
-       rettm = localtime_r(&current, &current_tm);
-       if (!rettm)
-               snprintf(node->locktime, sizeof(node->locktime), "Unknown");
-       else
-               strftime(node->locktime, sizeof(node->locktime), "%Y-%m-%d %H:%M:%S", &current_tm);
-
-       node->timeout = timeout;
-
-       if (node->timer_id) {
-               g_source_remove(node->timer_id);
-               node->timer_id = 0;
-       }
-
-       _D("pid=%d(%s) request CPU lock for %dms", pid, node->comm, timeout);
-       power_acquire_wakelock();
-
-       if (timeout > 0)
-               node->timer_id = g_timeout_add(timeout, lock_expired_cb, node);
-       else if (timeout == 0) /* endless CPU lock: add checker that monitors the process*/
-               node->timer_id = g_timeout_add(PROCESS_CHECK_TIMEOUT, process_check_cb, node);
+       ret = power_lock_acquire_lock(pid, timeout);
 
 out:
        return g_variant_new("(i)", ret);
@@ -263,8 +136,6 @@ static GVariant *dbus_power_unlock_cpu(GDBusConnection *conn,
 {
        int ret = 0;
        pid_t pid;
-       GList *elem;
-       struct lock_node *node;
 
        pid = gdbus_connection_get_sender_pid(conn, sender);
        if (pid == -1 || kill(pid, 0) == -1) {
@@ -273,15 +144,7 @@ static GVariant *dbus_power_unlock_cpu(GDBusConnection *conn,
                goto out;
        }
 
-       SYS_G_LIST_FOREACH(lock_list, elem, node) {
-               if (node->pid == pid)
-                       break;
-       }
-
-       if (node) {
-               _D("pid=%d(%s) release CPU lock", node->pid, node->comm);
-               remove_lock_node(node);
-       }
+       ret = power_lock_release_lock(pid);
 
 out:
        return g_variant_new("(i)", ret);
diff --git a/src/power/power-lock.c b/src/power/power-lock.c
new file mode 100644 (file)
index 0000000..40cbec4
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * deviced
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <glib.h>
+#include <system_info.h>
+#include <libsyscommon/libgdbus.h>
+#include <libsyscommon/list.h>
+#include <libsyscommon/file.h>
+#include <device/power.h>
+#include <hal/hal-device-power.h>
+
+#include "power.h"
+#include "power-suspend.h"
+#include "power-lock.h"
+#include "shared/log.h"
+
+#ifndef PROCESS_CHECK_TIMEOUT
+#define PROCESS_CHECK_TIMEOUT    600000 /* milisecond, 10 minute */
+#endif
+
+static GList *lock_list;
+
+struct lock_node {
+       pid_t pid;
+       char comm[64];
+       int timer_id;
+       int timeout;
+       char locktime[64];
+};
+
+static int get_display_feature(bool *display_feature)
+{
+       static int initialized = false;
+       static bool feature = false;
+       int ret;
+
+       if (!display_feature)
+               return -EINVAL;
+
+       if (initialized) {
+               *display_feature = feature;
+               return 0;
+       }
+
+       ret = system_info_get_platform_bool("http://tizen.org/feature/display", &feature);
+       if (ret != SYSTEM_INFO_ERROR_NONE)
+               return -EINVAL;
+
+       initialized = true;
+
+       return 0;
+}
+
+static void print_lock_node(void)
+{
+       GList *elem;
+       struct lock_node *node;
+
+       _D("List of remaining CPU locks");
+       SYS_G_LIST_FOREACH(lock_list, elem, node)
+               _D(" pid=%d(%s), locktime=%s, timeout=%dms",
+                       node->pid, node->comm, node->locktime, node->timeout);
+}
+
+static void remove_lock_node(struct lock_node *node)
+{
+       if (!node)
+               return;
+
+       if (node->timer_id) {
+               g_source_remove(node->timer_id);
+               node->timer_id = 0;
+       }
+
+       SYS_G_LIST_REMOVE(lock_list, node);
+       free(node);
+
+       /* Check the lock_list is empty after removing the node.
+        * If it is, then request wake unlock */
+       if (SYS_G_LIST_LENGTH(lock_list) == 0)
+               power_release_wakelock();
+       else
+               print_lock_node();
+
+       power_lock_broadcast_lock_count(POWER_LOCK_CPU, SYS_G_LIST_LENGTH(lock_list));
+}
+
+static gboolean lock_expired_cb(void *data)
+{
+       struct lock_node *this = (struct lock_node *) data;
+
+       _D("Powerlock of pid=%d(%s) for %dms is expired", this->pid, this->comm, this->timeout);
+       remove_lock_node(this);
+
+       return G_SOURCE_REMOVE;
+}
+
+/* check existance of process for every PROCESS_CHECK_TIMEOUT
+ * if the process has requested infinite CPU lock */
+static gboolean process_check_cb(void *data)
+{
+       struct lock_node *this = (struct lock_node *) data;
+
+       if (kill(this->pid, 0) != 0) {
+               _D("pid=%d(%s) is not found, deviced release the CPU lock", this->pid, this->comm);
+               remove_lock_node(this);
+               return G_SOURCE_REMOVE;
+       }
+
+       return G_SOURCE_CONTINUE;
+}
+
+int power_lock_broadcast_lock_count(int power_lock_type, int count)
+{
+       int ret;
+       bool display_feature = false;
+
+       if (power_lock_type < POWER_LOCK_CPU || power_lock_type > POWER_LOCK_DISPLAY_DIM)
+               return -EINVAL;
+
+       if (count < 0)
+               return -EINVAL;
+
+       ret = get_display_feature(&display_feature);
+       if (ret < 0) {
+               _E("Failed to get display feature. Suppress lock count signal broadcasting.");
+               return -EINVAL;
+       }
+
+       if (display_feature == false && power_lock_type != POWER_LOCK_CPU)
+               _W("Without display feature, locks other than POWER_LOCK_CPU have no effect.");
+
+       gdbus_signal_emit(NULL,
+               DEVICED_PATH_DISPLAY,
+               DEVICED_INTERFACE_DISPLAY,
+               DEVICED_SIGNAL_POWER_LOCK_COUNT_CHANGED,
+               g_variant_new("(ii)", power_lock_type, count));
+
+       return 0;
+}
+
+int power_lock_acquire_lock(pid_t pid, int timeout)
+{
+       GList *elem;
+       struct lock_node *node;
+       time_t current;
+       struct tm current_tm;
+       struct tm *rettm;
+
+       SYS_G_LIST_FOREACH(lock_list, elem, node) {
+               if (node->pid == pid)
+                       break;
+       }
+
+       if (!node) {
+               int retval;
+               char commpath[128];
+               char *sep;
+
+               node = calloc(1, sizeof(struct lock_node));
+               if (!node)
+                       return -ENOMEM;
+
+               node->pid = pid;
+               snprintf(commpath, sizeof(commpath), "/proc/%d/comm", pid);
+               retval = sys_get_str(commpath, node->comm, sizeof(node->comm));
+               if (retval != 0)
+                       snprintf(node->comm, sizeof(node->comm), "Unknown");
+
+               /* remove whitesapce */
+               sep = strpbrk(node->comm, " \n\t\r");
+               if (sep)
+                       *sep = '\0';
+
+               SYS_G_LIST_APPEND(lock_list, node);
+               power_lock_broadcast_lock_count(POWER_LOCK_CPU, SYS_G_LIST_LENGTH(lock_list));
+       }
+
+       /* set current time for logging */
+       current = time(NULL);
+       rettm = localtime_r(&current, &current_tm);
+       if (!rettm)
+               snprintf(node->locktime, sizeof(node->locktime), "Unknown");
+       else
+               strftime(node->locktime, sizeof(node->locktime), "%Y-%m-%d %H:%M:%S", &current_tm);
+
+       node->timeout = timeout;
+
+       if (node->timer_id) {
+               g_source_remove(node->timer_id);
+               node->timer_id = 0;
+       }
+
+       _D("pid=%d(%s) request CPU lock for %dms", pid, node->comm, timeout);
+       power_request_change_state(DEVICED_POWER_STATE_NORMAL, HAL_DEVICE_POWER_TRANSITION_REASON_POWER_LOCK);
+
+       if (timeout > 0)
+               node->timer_id = g_timeout_add(timeout, lock_expired_cb, node);
+       else if (timeout == 0) /* endless CPU lock: add checker that monitors the process*/
+               node->timer_id = g_timeout_add(PROCESS_CHECK_TIMEOUT, process_check_cb, node);
+
+       return 0;
+}
+
+int power_lock_release_lock(pid_t pid)
+{
+       GList *elem;
+       struct lock_node *node;
+
+       SYS_G_LIST_FOREACH(lock_list, elem, node) {
+               if (node->pid == pid)
+                       break;
+       }
+
+       if (node) {
+               _D("pid=%d(%s) release CPU lock", node->pid, node->comm);
+               remove_lock_node(node);
+       }
+
+       return 0;
+}
+
+int power_lock_get_lock_count(int *count)
+{
+       if (!count)
+               return -EINVAL;
+
+       *count = SYS_G_LIST_LENGTH(lock_list);
+
+       return 0;
+}
diff --git a/src/power/power-lock.h b/src/power/power-lock.h
new file mode 100644 (file)
index 0000000..2aafa9d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * deviced
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __POWER_LOCK_H__
+#define __POWER_LOCK_H__
+
+#include <unistd.h>
+#include <sys/types.h>
+
+int power_lock_broadcast_lock_count(int power_lock_type, int count);
+int power_lock_acquire_lock(pid_t pid, int timeout);
+int power_lock_release_lock(pid_t pid);
+int power_lock_get_lock_count(int *count);
+
+#endif /* __POWER_LOCK_H__ */
index 44f0fb9e58202f6964167ee3ab3603ca44ac5262..5d891b464c68578c21b860724601356b1fff5963 100644 (file)
@@ -31,6 +31,7 @@
 #include "power-doze.h"
 #include "power-suspend.h"
 #include "power-event-lock.h"
+#include "power-lock.h"
 
 typedef union {
        int32_t i32;
@@ -115,6 +116,18 @@ static int get_power_attr_data(int resource_id,
                        attr_data.i32 = vital_mode();
                }
                break;
+       case DEVICED_POWER_ATTR_INT_CPU_LOCK_COUNT:
+               {
+                       int lock_count = 0;
+                       int ret;
+
+                       ret = power_lock_get_lock_count(&lock_count);
+                       if (ret < 0)
+                               break;
+
+                       attr_data.i32 = lock_count;
+               }
+               break;
        default:
                ret = -EINVAL;
                break;
@@ -213,6 +226,30 @@ static int set_power_attr_data(int resource_id,
        return 0;
 }
 
+static int set_power_cpulock(int resource_id, const struct syscommon_resman_resource_attribute *attr,
+       const void *data1, const void *data2, const void *data3,
+       int count1, int count2, int count3)
+{
+       bool acquire_lock;
+       pid_t pid;
+       int timeout;
+
+       if (!data1 || !data2 || !data3)
+               return -EINVAL;
+
+       if (!attr || attr->id != DEVICED_POWER_ATTR_UINT64_3_CPU_LOCK)
+               return -EINVAL;
+
+       acquire_lock = *(const bool *) data1;
+       pid = *(const pid_t *) data2;
+       timeout = *(const int *) data3;
+
+       if (acquire_lock)
+               return power_lock_acquire_lock(pid, timeout);
+       else
+               return power_lock_release_lock(pid);
+}
+
 /**
  * FIXME: After developing the power abstraction layer, this attribute should
  * be fixed. Because the suspend-to-ram supports both echo-mem and wakelock
@@ -340,6 +377,24 @@ static const struct syscommon_resman_resource_attribute power_attrs[] = {
                        .set = set_power_attr_data,
                        .is_supported = syscommon_resman_resource_attr_supported_always,
                },
+       }, {
+               .name = "DEVICED_POWER_ATTR_UINT64_3_CPU_LOCK",
+               .id = DEVICED_POWER_ATTR_UINT64_3_CPU_LOCK,
+               .type = SYSCOMMON_RESMAN_DATA_TYPE_3_UINT64,
+               .flag = SYSCOMMON_RESMAN_RESOURCE_FLAG_PUBLIC,
+               .ops = {
+                       .set_3_tuple = set_power_cpulock,
+                       .is_supported = syscommon_resman_resource_attr_supported_always,
+               },
+       }, {
+               .name = "DEVICED_POWER_ATTR_INT_CPU_LOCK_COUNT",
+               .id = DEVICED_POWER_ATTR_INT_CPU_LOCK_COUNT,
+               .type = SYSCOMMON_RESMAN_DATA_TYPE_INT,
+               .flag = SYSCOMMON_RESMAN_RESOURCE_FLAG_PUBLIC,
+               .ops = {
+                       .get = get_power_attr_data,
+                       .is_supported = syscommon_resman_resource_attr_supported_always,
+               },
        }
 };
 
diff --git a/src/power/resource-power.h b/src/power/resource-power.h
new file mode 100644 (file)
index 0000000..8ea12aa
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * deviced
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RESOURCE_POWER_H__
+#define __RESOURCE_POWER_H__
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <libsyscommon/resource-manager.h>
+#include <system/syscommon-plugin-common-interface.h>
+#include <system/syscommon-plugin-deviced-power-interface.h>
+
+#define POWER_RESOURCE_ID      SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_POWER)
+
+/**
+ * FIXME: IT IS STRONGLY DISCOURAGED TO USE BELOW FUNCTIONS WHEN
+ *        THE DISPLAY FEATURE IS ENABLED.
+ *         • power_resource_acquire_cpulock()
+ *         • power_resource_release_cpulock()
+ *         • power_resource_get_cpulock_count()
+ *
+ *        It controls power lock directly, not via display lock, and it means
+ *        it doesn't care about the display lock mechanism. Therefore, if the display
+ *        feature is enabled, then use below functions instead to get an equivalent
+ *        effect.
+ *         • pm_lock_internal()
+ *         • pm_unlock_internal()
+ *         • pmlock_get_lock_count()
+ */
+
+static inline int power_resource_acquire_cpulock(pid_t pid, int timeout)
+{
+       return syscommon_resman_set_resource_attr_uint64_3(
+               POWER_RESOURCE_ID,
+               DEVICED_POWER_ATTR_UINT64_3_CPU_LOCK,
+               (u_int64_t) 1,
+               (u_int64_t) pid,
+               (u_int64_t) timeout);
+}
+
+static inline int power_resource_release_cpulock(pid_t pid)
+{
+       return syscommon_resman_set_resource_attr_uint64_3(
+               POWER_RESOURCE_ID,
+               DEVICED_POWER_ATTR_UINT64_3_CPU_LOCK,
+               (u_int64_t) 0,
+               (u_int64_t) pid,
+               (u_int64_t) 0);
+}
+
+static inline int power_resource_get_cpulock_count(int *count)
+{
+       return syscommon_resman_get_resource_attr_int(
+               POWER_RESOURCE_ID,
+               DEVICED_POWER_ATTR_INT_CPU_LOCK_COUNT,
+               count);
+}
+
+#endif /* __RESOURCE_POWER_H__ */