power: Support power operation on headless profile 92/315392/9 accepted/tizen/7.0/unified/20241204.185040
authorYoungjae Cho <y0.cho@samsung.com>
Thu, 28 Nov 2024 08:29:06 +0000 (17:29 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Wed, 4 Dec 2024 03:12:10 +0000 (12:12 +0900)
The dummy display module of headless profile has now changed to
initialize dbus object with DEVICED_PATH_DISPLAY path.

Note that, the current device API for power operation is working
under privilege 'http://tizen.org/privilege/display'. Therefore,
the API cannot directly call power module as the power module
requires privilege 'http://tizen.org/privilege/power'. This is why
the request for power on headless cannot go directly to the power
module but must pass through the display module first.

 - device power API ---(X)--> deviced power module (lack of privilege)
      |  |                        (headless)
      |  |
      |  |
      |  |-----> deviced display module
      |              (headed)
      |
      |--------> deviced display module --------> deviced power module
                    (headless)                       (headless)

The headless profile now supports 3 display dbus methods and those
behavior are similar to the headed profile. It only differs in that the
headed profile manages locks at the display module, on the other hand,
the headless profile manages only cpulock, which is equivalent to lcdoff
lock on the headed profile, at the power module.
 - lockstate
     • headed display module   -> display/poll.c: __pm_lock_internal()
     • headless display module -> power/power-lock.c: power_lock_acquire_lock()
 - unlockstate
     • headed display module   -> display/poll.c: __pm_unlock_internal()
     • headless display module -> power/power-lock.c: power_lock_release_lock()
 - PmlockGetLockCount
     • headed display module   -> display/display-lock.c: pmlock_get_lock_count()
     • headless display module -> power/power-lock.c: power_lock_get_lock_count()

Change-Id: Ib875e3e2c8edf57a6fa8bb533bf1fb40f34826f0
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
packaging/deviced.spec
plugins/iot-headless/display/CMakeLists.txt
plugins/iot-headless/display/core.c
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]

index 720190771323d061f98d2190093be57ffec99fb0..8e23fee19f28798cfff0828e479a8226f545a085 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 3d0a1869c80dbce57783daa07bff5a8dbfdcbbae..e1b4d4044a5c070c62a5b5b1209b071e29cbd5fa 100644 (file)
@@ -7,6 +7,8 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src)
 
 INCLUDE(FindPkgConfig)
 pkg_check_modules(libpkgs REQUIRED
+       glib-2.0
+       capi-system-device
        libsyscommon)
 
 FOREACH(flag ${libpkgs_CFLAGS})
index ac7bd1116716d47878d71ff7891eece2e861698f..2e2a687fdb72702eef2084ee5a40ce7321029f23 100644 (file)
  * limitations under the License.
  */
 
+#include <string.h>
+#include <glib.h>
 #include <shared/common.h>
 #include <shared/devices.h>
 #include <libsyscommon/libgdbus.h>
+#include <device/power.h>
 
-#include "core/log.h"
+#include "shared/log-macro.h"
+#include "power/power-lock.h"
 
 static GVariant *dbus_lockstate(GDBusConnection *conn,
        const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
        GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
 {
-       return g_variant_new("(i)", 0);
+       char *state_str;
+       char *option1_str;
+       char *option2_str;
+       int timeout;
+       pid_t pid;
+       int ret = 0;
+
+       g_variant_get(param, "(sssi)", &state_str, &option1_str, &option2_str, &timeout);
+
+       if (!state_str || timeout < 0) {
+               _E("message is invalid!");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!strncmp(state_str, "privilege check", sizeof("privilege check")))
+               goto out;
+
+       pid = gdbus_connection_get_sender_pid(conn, sender);
+       if (pid == -1 || kill(pid, 0) == -1) {
+               _E("%d process does not exist, dbus ignored!", pid);
+               ret = -ESRCH;
+               goto out;
+       }
+
+       if (strncmp(state_str, "lcdoff", sizeof("lcdoff"))) {
+               _E("Headless doesn't support lock other than lcdoff");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /**
+        * Delegate the lock request to power module instead of display module
+        * when it comes to a headless profile.
+        */
+       ret = power_lock_acquire_lock(pid, timeout);
+
+out:
+       g_free(state_str);
+       g_free(option1_str);
+       g_free(option2_str);
+       return g_variant_new("(i)", ret);
 }
 
 static GVariant *dbus_unlockstate(GDBusConnection *conn,
        const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
        GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
 {
-       return g_variant_new("(i)", 0);
+       char *state_str;
+       char *option_str;
+       pid_t pid;
+       int ret = 0;
+
+       g_variant_get(param, "(ss)", &state_str, &option_str);
+
+       if (!state_str) {
+               _E("message is invalid!");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!strncmp(state_str, "privilege check", sizeof("privilege check")))
+               goto out;
+
+       pid = gdbus_connection_get_sender_pid(conn, sender);
+       if (pid == -1 || kill(pid, 0) == -1) {
+               _E("%d process does not exist, dbus ignored!", pid);
+               ret = -ESRCH;
+               goto out;
+       }
+
+       if (strncmp(state_str, "lcdoff", sizeof("lcdoff"))) {
+               _E("Headless doesn't support lock other than lcdoff");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /**
+        * Delegate the unlock request to power module instead of display module
+        * when it comes to a headless profile.
+        */
+       ret = power_lock_release_lock(pid);
+out:
+       g_free(state_str);
+       g_free(option_str);
+       return g_variant_new("(i)", ret);
+}
+
+static GVariant *dbus_pmlockgetlockcount(GDBusConnection *conn,
+       const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
+       GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+       power_lock_e power_lock_type;
+       int ret;
+
+       g_variant_get(param, "(i)", &power_lock_type);
+
+       if (power_lock_type != POWER_LOCK_CPU) {
+               _W("Invalid parameter power lock type=(%d)", power_lock_type);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       power_lock_get_lock_count(&ret);
+
+out:
+       return g_variant_new("(i)", ret);
 }
 
 static const dbus_method_s dbus_methods[] = {
-       { "lockstate",        "sssi", "i", dbus_lockstate },
-       { "unlockstate",      "ss",   "i", dbus_unlockstate }
+       { "lockstate",          "sssi", "i", dbus_lockstate },
+       { "unlockstate",        "ss",   "i", dbus_unlockstate },
+       { "PmlockGetLockCount", "i",    "i", dbus_pmlockgetlockcount},
 };
 
 static const dbus_interface_u dbus_interface = {
index ba937f8fa3488dd9f19c6a818bc96b93b56005b8..e1d8580ec4431354567beb9bdefcdbcba0a8e166 100644 (file)
@@ -30,6 +30,7 @@
 #include "display-lock.h"
 #include "shared/log-macro.h"
 #include "shared/apps.h"
+#include "power/power-lock.h"
 
 #define METHOD_APP_STATUS      "CheckAppStatus"
 #define PID_MAX                        6
@@ -119,11 +120,7 @@ static void broadcast_pmlock_state_changed(enum state_t state)
        num_of_pmlock = g_list_length(cond_head[state]);
 
        /* broadcast on every change of lock count */
-       gdbus_signal_emit(NULL,
-               DEVICED_PATH_DISPLAY,
-               DEVICED_INTERFACE_DISPLAY,
-               DEVICED_SIGNAL_POWER_LOCK_COUNT_CHANGED,
-               g_variant_new("(ii)", power_lock_type, num_of_pmlock));
+       power_lock_broadcast_lock_count(power_lock_type, num_of_pmlock);
 
        if (num_of_pmlock > 1)
                return;
index 2b366ee17b6cea71dccc949bbf268ccd9c127bc1..20bee10d825f4449939ff45736024a0caddaa7e7 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)
@@ -114,63 +101,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)
@@ -178,12 +108,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);
@@ -199,58 +123,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_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);
+       ret = power_lock_acquire_lock(pid, timeout);
 
 out:
        return g_variant_new("(i)", ret);
@@ -262,8 +135,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) {
@@ -272,15 +143,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..9dfa1be
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * deviced
+ *
+ * Copyright (c) 2024 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/device/hal-device-power.h>
+
+#include "power.h"
+#include "power-suspend.h"
+#include "power-lock.h"
+#include "shared/log-macro.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 is_headed_profile(bool *profile)
+{
+       static int initialized = false;
+       static bool is_headed = false;
+       int ret;
+
+       if (!profile)
+               return -EINVAL;
+
+       if (initialized) {
+               *profile = is_headed;
+               return 0;
+       }
+
+       ret = system_info_get_platform_bool("http://tizen.org/feature/display", &is_headed);
+       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);
+
+       power_lock_broadcast_lock_count(POWER_LOCK_CPU, SYS_G_LIST_LENGTH(lock_list));
+
+       /* 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;
+}
+
+int power_lock_broadcast_lock_count(int power_lock_type, int count)
+{
+       int ret;
+       bool is_headed = false;
+
+       if (power_lock_type < POWER_LOCK_CPU || power_lock_type > POWER_LOCK_DISPLAY_DIM)
+               return -EINVAL;
+
+       if (count < 0)
+               return -EINVAL;
+
+       ret = is_headed_profile(&is_headed);
+       if (ret < 0) {
+               _E("Failed to find profile, headed or headless. Suppress lock count signal broadcasting.");
+               return -EINVAL;
+       }
+
+       if (is_headed && power_lock_type != POWER_LOCK_CPU)
+               _W("Lock type other than POWER_LOCK_CPU has no effect on headless profile. But broadcast it anyway.");
+
+       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;
+}
+
+/**
+ * FIXME: It is strongly discoraged to use this function
+ *        at the profile other than headless.
+ */
+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;
+}
+
+/**
+ * FIXME: It is strongly discoraged to use this function
+ *        at the profile other than headless.
+ */
+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;
+}
+
+/**
+ * FIXME: It is strongly discoraged to use this function
+ *        at the profile other than headless.
+ */
+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..08a586e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * deviced
+ *
+ * Copyright (c) 2024 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);
+
+/**
+ * FIXME: IT IS STRONGLY DISCOURAGED TO USE BELOW FUNCTIONS AT THE
+ *        PROFILE OTHER THAN HEADLESS.
+ *
+ *        These functions are implemented only for the headless profile.
+ *        The headless profile has no display module so it is impossible
+ *        to control lock via display, which is the way how the current deviced's
+ *        locking mechanism has been working. Therefore it was necessary to
+ *        give another way for healdess profile to use lock, so these functions
+ *        have been newly introduced. However, it has not been fully taken into
+ *        consideration what side effect would be when it operates with headed,
+ *        so you might NOT use these functions at the profile other than headless.
+ *
+ *        Instead, the profiles other than headless can use display lock functions
+ *        below to get an equivalent effect.
+ *         • pm_lock_internal()
+ *         • pm_unlock_internal()
+ *         • pmlock_get_lock_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__ */
+