Name: deviced
Summary: Deviced
-Version: 10.0.0
+Version: 10.0.1
Release: 1
Group: System/Management
License: Apache-2.0
*
*/
#include <libsyscommon/proc.h>
+#include <system_info.h>
#include <system/syscommon-plugin-deviced-common-interface.h>
#include "shared/common.h"
#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
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;
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]);
{
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)
{
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)
#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)
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)
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);
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(¤t, ¤t_tm);
- if (!rettm)
- snprintf(node->locktime, sizeof(node->locktime), "Unknown");
- else
- strftime(node->locktime, sizeof(node->locktime), "%Y-%m-%d %H:%M:%S", ¤t_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);
{
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) {
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);
--- /dev/null
+/*
+ * 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(¤t, ¤t_tm);
+ if (!rettm)
+ snprintf(node->locktime, sizeof(node->locktime), "Unknown");
+ else
+ strftime(node->locktime, sizeof(node->locktime), "%Y-%m-%d %H:%M:%S", ¤t_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;
+}
--- /dev/null
+/*
+ * 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__ */
#include "power-doze.h"
#include "power-suspend.h"
#include "power-event-lock.h"
+#include "power-lock.h"
typedef union {
int32_t i32;
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;
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
.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,
+ },
}
};
--- /dev/null
+/*
+ * 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__ */