SET(DATA_DIR ${CMAKE_SOURCE_DIR}/data)
SET(CMAKELISTS_DIR ${CMAKE_SOURCE_DIR}/CMakeLists)
SET(INCLUDE_COMMON_DIR ${CMAKE_SOURCE_DIR}/src/common)
+SET(INCLUDE_PROCFS_DIR ${CMAKE_SOURCE_DIR}/src/common/procfs)
+SET(INCLUDE_MODULE_DIR ${CMAKE_SOURCE_DIR}/src/common/module)
+SET(INCLUDE_CONF_DIR ${CMAKE_SOURCE_DIR}/src/common/conf)
+SET(INCLUDE_IPC_DIR ${CMAKE_SOURCE_DIR}/src/common/ipc)
SET(INCLUDE_CGROUP_DIR ${CMAKE_SOURCE_DIR}/src/common/cgroup)
SET(INCLUDE_PUBLIC_DIR ${CMAKE_SOURCE_DIR}/include)
SET(CONF_DIR ${CMAKE_SOURCE_DIR}/conf)
-SET(RESOURCED_INCLUDEDIR ${INCLUDE_COMMON_DIR} ${INCLUDE_CGROUP_DIR} ${INCLUDE_PUBLIC_DIR})
+SET(RESOURCED_INCLUDEDIR
+ ${INCLUDE_COMMON_DIR} ${INCLUDE_CGROUP_DIR} ${INCLUDE_CONF_DIR} ${INCLUDE_IPC_DIR} ${INCLUDE_MODULE_DIR} ${INCLUDE_PROCFS_DIR} ${INCLUDE_PUBLIC_DIR})
#misc
SET(SOURCE_DIR ${CMAKE_SOURCE_DIR}/src)
#cgroup
SET(CGROUP_SOURCE_DIR ${COMMON_SOURCE_DIR}/cgroup)
+#conf
+SET(CONF_SOURCE_DIR ${COMMON_SOURCE_DIR}/conf)
+
+#ipc (dbus, signal)
+SET(IPC_SOURCE_DIR ${COMMON_SOURCE_DIR}/ipc)
+
+#module
+SET(MODULE_SOURCE_DIR ${COMMON_SOURCE_DIR}/module)
+
+#procfs
+SET(PROCFS_SOURCE_DIR ${COMMON_SOURCE_DIR}/procfs)
+
#resource-optimizer source folders
SET(RESOURCE_OPTIMIZER_SOURCE_DIR ${SOURCE_DIR}/resource-optimizer)
SET(CPU_RESOURCE_OPTIMIZER_SOURCE_DIR ${RESOURCE_OPTIMIZER_SOURCE_DIR}/cpu)
SET(MEMORY_RESOURCE_OPTIMIZER_SOURCE_DIR ${RESOURCE_OPTIMIZER_SOURCE_DIR}/memory)
-SET(DEDUP_SOURCE_DIR ${RESOURCE_OPTIMIZER_SOURCE_DIR}/memory/dedup)
+SET(DEDUP_SOURCE_DIR ${MEMORY_RESOURCE_OPTIMIZER_SOURCE_DIR})
SET(SWAP_SOURCE_DIR ${RESOURCE_OPTIMIZER_SOURCE_DIR}/memory/swap)
-SET(COMPACTION_SOURCE_DIR ${RESOURCE_OPTIMIZER_SOURCE_DIR}/memory/compaction)
+SET(COMPACTION_SOURCE_DIR ${MEMORY_RESOURCE_OPTIMIZER_SOURCE_DIR})
#resource-limiter source folders
SET(RESOURCE_LIMITER_SOURCE_DIR ${SOURCE_DIR}/resource-limiter)
SET(FREEZER_SOURCE_DIR ${RESOURCE_LIMITER_SOURCE_DIR}/freezer)
SET(MEMORY_LIMITER_SOURCE_DIR ${RESOURCE_LIMITER_SOURCE_DIR}/memory)
-SET(CPU_LIMITER_SOURCE_DIR ${RESOURCE_LIMITER_SOURCE_DIR}/cpu)
+SET(CPU_LIMITER_SOURCE_DIR ${RESOURCE_LIMITER_SOURCE_DIR})
#resource-monitor source folders
SET(RESOURCE_MONITOR_SOURCE_DIR ${SOURCE_DIR}/resource-monitor)
-SET(CPU_MONITOR_SOURCE_DIR ${RESOURCE_MONITOR_SOURCE_DIR}/cpu)
-SET(MEMORY_MONITOR_SOURCE_DIR ${RESOURCE_MONITOR_SOURCE_DIR}/memory)
-SET(STORAGE_MONITOR_SOURCE_DIR ${RESOURCE_MONITOR_SOURCE_DIR}/storage)
-SET(DBUS_MONITOR_SOURCE_DIR ${RESOURCE_MONITOR_SOURCE_DIR})
-SET(BATTERY_MONITOR_SOURCE_DIR ${RESOURCE_MONITOR_SOURCE_DIR}/battery)
-SET(ABNORMAL_MONITOR_SOURCE_DIR ${RESOURCE_MONITOR_SOURCE_DIR}/abnormal)
#process
SET(PROCESS_SOURCE_DIR ${SOURCE_DIR}/process)
SET(BLOCK_SOURCE_DIR ${PROCESS_SOURCE_DIR}/block)
SET(WATCHDOG_SOURCE_DIR ${PROCESS_SOURCE_DIR}/watchdog)
-SET(PRIORITY_SOURCE_DIR ${PROCESS_SOURCE_DIR}/priority)
-
INSTALL(FILES ${CONF_DIR}/org.tizen.resourced.conf DESTINATION /etc/dbus-1/system.d)
[APPUSAGE]
APPUSAGE=ON
-[WatchdogExcludedApps]
-PREDEFINE=indicator-win
-PREDEFINE=lockscreen
-PREDEFINE=quickpanel
-PREDEFINE=volume
-PREDEFINE=data-provider-master
-
[BLOCK]
activate=TRUE
mode=WRITE
FILE(GLOB FILES "${WATCHDOG_SOURCE_DIR}/*.c")
SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
-FILE(GLOB FILES "${PRIORITY_SOURCE_DIR}/*.c")
-SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
-
FILE(GLOB FILES "${COMMON_SOURCE_DIR}/*.c")
SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
FILE(GLOB FILES "${CGROUP_SOURCE_DIR}/*.c")
SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
+FILE(GLOB FILES "${CONF_SOURCE_DIR}/*.c")
+SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
+
+FILE(GLOB FILES "${IPC_SOURCE_DIR}/*.c")
+SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
+
+FILE(GLOB FILES "${MODULE_SOURCE_DIR}/*.c")
+SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
+
+FILE(GLOB FILES "${PROCFS_SOURCE_DIR}/*.c")
+SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
+
SET(CMAKE_EXTRA_INCLUDE_FILES unistd.h)
INCLUDE_DIRECTORIES(${RESOURCED_INCLUDEDIR}
${RESOURCED_SOURCE_DIR}
${RESOURCE_MONITOR_SOURCE_DIR}
- ${CPU_LIMITER_SOURCE_DIR}
${MEMORY_LIMITER_SOURCE_DIR}
${PROCESS_SOURCE_DIR}
${BLOCK_SOURCE_DIR}
${FREEZER_SOURCE_DIR}
- ${PRIORITY_SOURCE_DIR}
)
IF("${PROC_WATCHDOG}" STREQUAL "ON")
ENDIF()
IF("${CPU_THROTTLING_MODULE}" STREQUAL "ON")
- FILE(GLOB FILES "${CPU_LIMITER_SOURCE_DIR}/*.c")
+ FILE(GLOB FILES "${CPU_LIMITER_SOURCE_DIR}/cpu-throttling.c")
FOREACH(FILE ${FILES})
SET(SOURCES ${SOURCES} ${FILE})
ENDFOREACH()
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -pthread -fPIE -fPIC")
-CONFIGURE_FILE(${INCLUDE_COMMON_DIR}/config.h.in
- ${INCLUDE_COMMON_DIR}/config.h)
+CONFIGURE_FILE(${INCLUDE_CONF_DIR}/config.h.in
+ ${INCLUDE_CONF_DIR}/config.h)
# resourced internal private API
-FILE(GLOB FILES "${INCLUDE_COMMON_DIR}/*.h" "${INCLUDE_CGROUP_DIR}/*.h" "${INCLUDE_PUBLIC_DIR}/*.h" "${PROCESS_SOURCE_DIR}/*.h" "${RESOURCED_SOURCE_DIR}/*.h")
+FILE(GLOB FILES "${INCLUDE_COMMON_DIR}/*.h" "${INCLUDE_CGROUP_DIR}/*.h" "${INCLUDE_CONF_DIR}/*.h" "${INCLUDE_PUBLIC_DIR}/*.h" "${PROCESS_SOURCE_DIR}/*.h" "${RESOURCED_SOURCE_DIR}/*.h")
FOREACH(FILE ${FILES})
SET(RESOURCED_HEADERS ${RESOURCED_HEADERS} ${FILE})
ENDFOREACH()
ADD_LIBRARY(heart MODULE
${RESOURCE_MONITOR_SOURCE_DIR}/heart.c
- ${ABNORMAL_MONITOR_SOURCE_DIR}/heart-abnormal.c
- ${BATTERY_MONITOR_SOURCE_DIR}/heart-battery.c
- ${CPU_MONITOR_SOURCE_DIR}/heart-cpu.c
- ${DBUS_MONITOR_SOURCE_DIR}/heart-dbus.c
- ${MEMORY_MONITOR_SOURCE_DIR}/heart-memory.c
- ${STORAGE_MONITOR_SOURCE_DIR}/heart-storage.c
+ ${RESOURCE_MONITOR_SOURCE_DIR}/heart-abnormal.c
+ ${RESOURCE_MONITOR_SOURCE_DIR}/heart-battery.c
+ ${RESOURCE_MONITOR_SOURCE_DIR}/heart-cpu.c
+ ${RESOURCE_MONITOR_SOURCE_DIR}/heart-dbus.c
+ ${RESOURCE_MONITOR_SOURCE_DIR}/heart-memory.c
+ ${RESOURCE_MONITOR_SOURCE_DIR}/heart-storage.c
${RESOURCE_MONITOR_SOURCE_DIR}/logging.c)
TARGET_LINK_LIBRARIES(heart resourced-private-api ${RESOURCED_REQUIRE_PKGS_LDFLAGS})
INSTALL(TARGETS heart DESTINATION ${MAKE_INSTALL_PREFIX}${RD_PLUGIN_PATH})
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
-*/
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
-*/
+++ /dev/null
-
-#include "compact-common.h"
-#include "trace.h"
-
-static struct compact_conf *compact_conf = NULL;
-
-struct compact_conf *get_compact_conf(void)
-{
- if (!compact_conf) {
- compact_conf = (struct compact_conf *)calloc(1, sizeof (struct compact_conf));
- if (!compact_conf) {
- _E("Failed to alloc memory for cpu configuration");
- return NULL;
- }
- else {
- compact_conf->enable = false;
- compact_conf->frag_level = 0;
- }
- }
-
- return compact_conf;
-}
-
-void free_compact_conf(void)
-{
- if (compact_conf)
- free(compact_conf);
-}
-
+++ /dev/null
-#ifndef __COMPACT_COMMON_H__
-#define __COMPACT_COMMON_H__
-
-#include "resourced.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-struct compact_conf {
- bool enable;
- int frag_level;
-};
-
-struct compact_conf *get_compact_conf(void);
-void free_compact_conf(void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __COMPACT_COMMON_H__ */
--- /dev/null
+
+#include "compact-common.h"
+#include "trace.h"
+
+static struct compact_conf *compact_conf = NULL;
+
+struct compact_conf *get_compact_conf(void)
+{
+ if (!compact_conf) {
+ compact_conf = (struct compact_conf *)calloc(1, sizeof (struct compact_conf));
+ if (!compact_conf) {
+ _E("Failed to alloc memory for cpu configuration");
+ return NULL;
+ }
+ else {
+ compact_conf->enable = false;
+ compact_conf->frag_level = 0;
+ }
+ }
+
+ return compact_conf;
+}
+
+void free_compact_conf(void)
+{
+ if (compact_conf)
+ free(compact_conf);
+}
+
--- /dev/null
+#ifndef __COMPACT_COMMON_H__
+#define __COMPACT_COMMON_H__
+
+#include "resourced.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct compact_conf {
+ bool enable;
+ int frag_level;
+};
+
+struct compact_conf *get_compact_conf(void);
+void free_compact_conf(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __COMPACT_COMMON_H__ */
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 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 <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "util.h"
+#include "trace.h"
+#include "config-parser.h"
+#include "proc-common.h"
+#include "cpu-cgroup.h"
+#include "swap-common.h"
+#include "dedup-common.h"
+#include "compact-common.h"
+#include "cpu-common.h"
+
+#define MAX_SECTION 64
+
+static int config_parse_swap_types(
+ const char *rvalue,
+ void *data)
+{
+ enum swap_type *type = data;
+ char *word, *state;
+ size_t l;
+
+ if (is_empty(rvalue))
+ return 0;
+
+ *type = 0;
+
+ FOREACH_WORD_SEPARATOR(word, l, rvalue, "+|", state) {
+ if (strneq(word, "zram", l))
+ *type |= SWAP_TYPE_ZRAM;
+ else if (strneq(word, "file", l))
+ *type |= SWAP_TYPE_FILE;
+ else if (strneq(word, "zswap", l))
+ *type |= SWAP_TYPE_ZSWAP;
+ else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int config_parse_cpu_sched_features(const char *value)
+{
+ int cpu_sched_flag = CPU_SCHED_UNINITIALIZED;
+ char *word, *state;
+ size_t l;
+
+ if (is_empty(value))
+ return cpu_sched_flag;
+
+ FOREACH_WORD_SEPARATOR(word, l, value, ",", state) {
+ if (strneq(word, RT_RUNTIME_SHARE_VALUE_CONF, l))
+ cpu_sched_flag |= CPU_SCHED_RUNTIME_SHARE;
+ else if (strneq(word, NO_RT_RUNTIME_SHARE_VALUE_CONF, l))
+ cpu_sched_flag |= CPU_SCHED_NO_RUNTIME_SHARE;
+/* else if (strneq(word, RT_RUNTIME_GREED_VALUE_CONF, l))
+ cpu_sched_flag |= CPU_SCHED_RUNTIME_GREED;*/
+ else
+ return CPU_SCHED_UNINITIALIZED;
+ }
+
+ return cpu_sched_flag;
+}
+
+static char config_parse_time_unit(const char *value)
+{
+ char chr;
+ char *ptr = strchr(value, 's');
+ if (ptr == NULL) {
+ _E("[CONFIG] Cannot find 's' in the string (%s)", value);
+ return 'X';
+ }
+
+ if (value > (ptr - 1)) {
+ _E("[CONFIG] Size of string should be larger than 1");
+ return 'X';
+ }
+
+ chr = *(ptr - 1);
+ if (isdigit(chr)) {
+ *ptr = '\0';
+ return ' ';
+ }
+ else {
+ *(ptr - 1) = '\0';
+ return chr;
+ }
+}
+
+static long long config_parse_ll_time_us(const char *value)
+{
+ char unit = config_parse_time_unit(value);
+
+ if (unit == ' ') {
+ return strtoll(value, NULL, 10) * 1000 * 1000;
+ }
+ else if (unit == 'm') {
+ return strtoll(value, NULL, 10) * 1000;
+ }
+ else if (unit == 'u') {
+ return strtoll(value, NULL, 10);
+ }
+ else {
+ _E("[CONFIG] Unknown unit of time");
+ return 0;
+ }
+}
+
+static unsigned long long config_parse_ull_time_us(const char *value)
+{
+ char unit = config_parse_time_unit(value);
+
+ if (unit == ' ') {
+ return strtoull(value, NULL, 10) * 1000 * 1000;
+ }
+ else if (unit == 'm') {
+ return strtoull(value, NULL, 10) * 1000;
+ }
+ else if (unit == 'u') {
+ return strtoull(value, NULL, 10);
+ }
+ else {
+ _E("[CONFIG] Unknown unit of time");
+ return 0;
+ }
+}
+
+static bool config_parse_bool(const char *value)
+{
+ if (!strncmp(value, "yes", 4) ||
+ !strncmp(value, "1", 2) ||
+ !strncmp(value, "ok", 3) ||
+ !strncmp(value, "on", 3))
+ return true;
+ else if (!strncmp(value, "no", 3) ||
+ !strncmp(value, "0", 2) ||
+ !strncmp(value, "off", 4))
+ return false;
+ else {
+ _E("Unknown name (%s)", value);
+ return false;
+ }
+}
+
+static int config_parse_sched_type(const char *value)
+{
+ if (!strncmp(value, CPU_SCHED_IDLE_VALUE_CONF,
+ strlen(CPU_SCHED_IDLE_VALUE_CONF) +1))
+ return CPU_SCHED_IDLE;
+ else if (!strncmp(value, CPU_SCHED_OTHER_VALUE_CONF,
+ strlen(CPU_SCHED_OTHER_VALUE_CONF) +1))
+ return CPU_SCHED_OTHER;
+ else if (!strncmp(value, CPU_SCHED_BATCH_VALUE_CONF,
+ strlen(CPU_SCHED_BATCH_VALUE_CONF) +1))
+ return CPU_SCHED_BATCH;
+ else if (!strncmp(value, CPU_SCHED_FIFO_VALUE_CONF,
+ strlen(CPU_SCHED_FIFO_VALUE_CONF) +1))
+ return CPU_SCHED_FIFO;
+ else if (!strncmp(value, CPU_SCHED_RR_VALUE_CONF,
+ strlen(CPU_SCHED_RR_VALUE_CONF) +1))
+ return CPU_SCHED_RR;
+ else if (!strncmp(value, CPU_SCHED_DEADLINE_VALUE_CONF,
+ strlen(CPU_SCHED_DEADLINE_VALUE_CONF) +1))
+ return CPU_SCHED_DEADLINE;
+ else {
+ _E("invalid parameter (%s)", value);
+ return CPU_SCHED_NONE;
+ }
+}
+
+static cpu_boosting_level_e config_parse_boosting_level(const char *value)
+{
+ if (!strncmp(value, CPU_BOOSTING_LEVEL_STRONG_VALUE_CONF,
+ strlen(CPU_BOOSTING_LEVEL_STRONG_VALUE_CONF) + 1))
+ return CPU_BOOSTING_LEVEL_STRONG;
+ else if (!strncmp(value, CPU_BOOSTING_LEVEL_MEDIUM_VALUE_CONF,
+ strlen(CPU_BOOSTING_LEVEL_MEDIUM_VALUE_CONF) + 1))
+ return CPU_BOOSTING_LEVEL_MEDIUM;
+ else if (!strncmp(value, CPU_BOOSTING_LEVEL_WEAK_VALUE_CONF,
+ strlen(CPU_BOOSTING_LEVEL_WEAK_VALUE_CONF) + 1))
+ return CPU_BOOSTING_LEVEL_WEAK;
+ else
+ return CPU_BOOSTING_LEVEL_NONE;
+}
+
+static int optimizer_config(struct parse_result *result, void *user_data)
+{
+ if (!result)
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+
+ struct swap_conf *swap_conf = get_swap_conf();
+ if (swap_conf == NULL) {
+ _E("[CONFIG] memory swap configuration is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ struct dedup_conf *dedup_conf = get_dedup_conf();
+ if (dedup_conf == NULL) {
+ _E("[CONFIG] memory dedup configuration is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ struct compact_conf *compact_conf = get_compact_conf();
+ if (compact_conf == NULL) {
+ _E("[CONFIG] memory compact configuration is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ struct cpu_sched_conf *cpu_sched_conf = get_cpu_sched_conf();
+ if (cpu_sched_conf == NULL) {
+ _E("[CONFIG] cpu_sched configuration is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!strncmp(result->section, SWAP_SECTION, strlen(SWAP_SECTION)+1)) {
+ if (!swap_conf->enable)
+ swap_conf->enable = true;
+/* if (!strncmp(result->name, SWAP_ENABLE_NAME_CONF, strlen(SWAP_ENABLE_NAME_CONF)+1)) {
+ swap_conf->enable = config_parse_bool(result->value);
+ }*/
+ if (!strncmp(result->name, RECLAIM_AT_BOOT_NAME_CONF,
+ strlen(RECLAIM_AT_BOOT_NAME_CONF)+1)) {
+ swap_conf->boot_reclaim_enable = config_parse_bool(result->value);
+ }
+ else if (!strncmp(result->name, SWAP_TYPE_NAME_CONF,
+ strlen(SWAP_TYPE_NAME_CONF)+1)) {
+ if (config_parse_swap_types(result->value, &swap_conf->swap_type) < 0) {
+ _E("[CONFIG] Failed to parse type of swap, so use zram type");
+ swap_conf->swap_type = SWAP_TYPE_ZRAM;
+ }
+ }
+ else if (!strncmp(result->name, THROTTLING_SWAPPINESS_NAME_CONF,
+ strlen(THROTTLING_SWAPPINESS_NAME_CONF)+1)) {
+ swap_conf->swappiness[MEMCG_THROTTLING] = atoi(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, ZRAM_SECTION, strlen(ZRAM_SECTION)+1)) {
+ if (!strncmp(result->name, COMP_ALGORITHM_NAME_CONF, strlen(COMP_ALGORITHM_NAME_CONF)+1)) {
+ if (strlen(result->value) + 1 > sizeof(swap_conf->zram.algorithm)) {
+ _E("Size of swap_conf->zram.algorithm is not enough");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ strncpy(swap_conf->zram.algorithm, result->value,
+ sizeof(swap_conf->zram.algorithm) - 1);
+ }
+ else if (!strncmp(result->name, ZRAM_RATIO_NAME_CONF, strlen(ZRAM_RATIO_NAME_CONF)+1)) {
+ swap_conf->zram.ratio = atof(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, ZSWAP_SECTION, strlen(ZSWAP_SECTION)+1)) {
+ if (!strncmp(result->name, POOL_RATIO_NAME_CONF, strlen(POOL_RATIO_NAME_CONF)+1)) {
+ swap_conf->zswap.pool_ratio = atof(result->value);
+ }
+ else if (!strncmp(result->name, POOL_TYPE_NAME_CONF, strlen(POOL_TYPE_NAME_CONF)+1)) {
+ if (strlen(result->value) + 1 > sizeof(swap_conf->zswap.pool_type)) {
+ _E("Size of swap_conf->zswap.pool_type is not enough");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ strncpy(swap_conf->zswap.pool_type, result->value,
+ sizeof(swap_conf->zswap.pool_type) - 1);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, DEDUP_SECTION, strlen(DEDUP_SECTION)+1)) {
+ if (!dedup_conf->enable)
+ dedup_conf->enable = true;
+/* if (!strncmp(result->name, DEDUP_ENABLE_NAME_CONF, strlen(DEDUP_ENABLE_NAME_CONF)+1)) {
+ dedup_conf->enable = config_parse_bool(result->value);
+ }*/
+ if (!strncmp(result->name, DEDUP_AT_BOOT_NAME_CONF, strlen(DEDUP_AT_BOOT_NAME_CONF)+1)) {
+ dedup_conf->boot_dedup_enable = config_parse_bool(result->value);
+ }
+ else if (!strncmp(result->name, SCAN_ON_LOWMEM_NAME_CONF, strlen(SCAN_ON_LOWMEM_NAME_CONF)+1)) {
+ dedup_conf->scan_on_lowmem = config_parse_bool(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, KSM_SECTION, strlen(KSM_SECTION)+1)) {
+ if (!strncmp(result->name, KSM_MODE_NAME_CONF, strlen(KSM_MODE_NAME_CONF)+1)) {
+ if (strlen(result->value) + 1 > sizeof(dedup_conf->ksm.mode)) {
+ _E("Size of swap_conf->type is not enough");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ strncpy(dedup_conf->ksm.mode, result->value,
+ sizeof(dedup_conf->ksm.mode) - 1);
+ }
+ else if (!strncmp(result->name, PAGES_TO_SCAN_NAME_CONF, strlen(PAGES_TO_SCAN_NAME_CONF)+1)) {
+ dedup_conf->ksm.pages = atoi(result->value);
+ }
+ else if (!strncmp(result->name, PAGES_TO_SCAN_WITH_BOOST_NAME_CONF,
+ strlen(PAGES_TO_SCAN_WITH_BOOST_NAME_CONF)+1)) {
+ dedup_conf->ksm.boost_pages = atoi(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, COMPACTION_SECTION, strlen(COMPACTION_SECTION)+1)) {
+ if (!compact_conf->enable)
+ compact_conf->enable = true;
+/* if (!strncmp(result->name, COMPACTION_ENABLE_NAME_CONF,
+ strlen(COMPACTION_ENABLE_NAME_CONF)+1)) {
+ compact_conf->enable = config_parse_bool(result->value);
+ }*/
+ if (!strncmp(result->name, FRAG_LEVEL_NAME_CONF, strlen(FRAG_LEVEL_NAME_CONF)+1)) {
+ compact_conf->frag_level = atoi(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, CPU_SCHED_SECTION,
+ strlen(CPU_SCHED_SECTION)+1)) {
+ if (!strncmp(result->name, CPU_SCHED_FEATURE_NAME_CONF,
+ strlen(CPU_SCHED_FEATURE_NAME_CONF) + 1)) {
+ cpu_sched_conf->cpu_sched_flag = config_parse_cpu_sched_features(result->value);
+ }
+ else if (!strncmp(result->name, CPU_RT_RUN_TIME_NAME_CONF,
+ strlen(CPU_RT_RUN_TIME_NAME_CONF) + 1)) {
+ cpu_sched_conf->cpu_cgroup_info.rt_runtime_us = config_parse_ll_time_us(result->value);
+ }
+ else if (!strncmp(result->name, CPU_RT_PERIOD_NAME_CONF,
+ strlen(CPU_RT_PERIOD_NAME_CONF) + 1)) {
+ cpu_sched_conf->cpu_cgroup_info.rt_period_us = config_parse_ull_time_us(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, CPU_AFFINITY_SECTION,
+ strlen(CPU_AFFINITY_SECTION)+1)) {
+ int error = RESOURCED_ERROR_NONE;
+
+ if (!strncmp(result->name, FOREGROUND_APPS_NAME_CONF,
+ strlen(FOREGROUND_APPS_NAME_CONF) + 1)) {
+ error = set_cpu_affinity_conf(result->name, result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+
+ return error;
+ }
+ else if (!strncmp(result->section, CPU_BOOSTING_LEVEL_STRONG_SECTION,
+ strlen(CPU_BOOSTING_LEVEL_STRONG_SECTION)+1)) {
+ struct cpu_boosting_conf *cpu_boosting_conf =
+ get_cpu_boosting_conf(CPU_BOOSTING_LEVEL_STRONG);
+ if (cpu_boosting_conf == NULL) {
+ _E("[CONFIG] cpu_boosting configuration is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!cpu_boosting_conf->enable)
+ cpu_boosting_conf->enable = true;
+
+ if (!strncmp(result->name, CPU_SCHED_NAME_CONF,
+ strlen(CPU_SCHED_NAME_CONF) + 1)) {
+ cpu_boosting_conf->cpu_sched_info.cpu_sched_type =
+ config_parse_sched_type(result->value);
+ }
+ else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
+ strlen(CPU_NICE_NAME_CONF) + 1)) {
+ cpu_boosting_conf->cpu_sched_info.cpu_nice =
+ atoi(result->value);
+ }
+ else if (!strncmp(result->name, CPU_RT_PRIORITY_NAME_CONF,
+ strlen(CPU_RT_PRIORITY_NAME_CONF) + 1)) {
+ cpu_boosting_conf->cpu_sched_info.cpu_rt_priority =
+ atoi(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, CPU_BOOSTING_LEVEL_MEDIUM_SECTION,
+ strlen(CPU_BOOSTING_LEVEL_MEDIUM_SECTION)+1)) {
+ struct cpu_boosting_conf *cpu_boosting_conf =
+ get_cpu_boosting_conf(CPU_BOOSTING_LEVEL_MEDIUM);
+ if (cpu_boosting_conf == NULL) {
+ _E("[CONFIG] cpu_boosting configuration is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!cpu_boosting_conf->enable)
+ cpu_boosting_conf->enable = true;
+
+ if (!strncmp(result->name, CPU_SCHED_NAME_CONF,
+ strlen(CPU_SCHED_NAME_CONF) + 1)) {
+ cpu_boosting_conf->cpu_sched_info.cpu_sched_type =
+ config_parse_sched_type(result->value);
+ }
+ else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
+ strlen(CPU_NICE_NAME_CONF) + 1)) {
+ cpu_boosting_conf->cpu_sched_info.cpu_nice =
+ atoi(result->value);
+ }
+ else if (!strncmp(result->name, CPU_RT_PRIORITY_NAME_CONF,
+ strlen(CPU_RT_PRIORITY_NAME_CONF) + 1)) {
+ cpu_boosting_conf->cpu_sched_info.cpu_rt_priority =
+ atoi(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, CPU_BOOSTING_LEVEL_WEAK_SECTION,
+ strlen(CPU_BOOSTING_LEVEL_WEAK_SECTION)+1)) {
+ struct cpu_boosting_conf *cpu_boosting_conf =
+ get_cpu_boosting_conf(CPU_BOOSTING_LEVEL_WEAK);
+ if (cpu_boosting_conf == NULL) {
+ _E("[CONFIG] cpu_boosting configuration is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!cpu_boosting_conf->enable)
+ cpu_boosting_conf->enable = true;
+
+ if (!strncmp(result->name, CPU_SCHED_NAME_CONF,
+ strlen(CPU_SCHED_NAME_CONF) + 1)) {
+ cpu_boosting_conf->cpu_sched_info.cpu_sched_type =
+ config_parse_sched_type(result->value);
+ }
+ else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
+ strlen(CPU_NICE_NAME_CONF) + 1)) {
+ cpu_boosting_conf->cpu_sched_info.cpu_nice =
+ atoi(result->value);
+ }
+ else if (!strncmp(result->name, CPU_RT_PRIORITY_NAME_CONF,
+ strlen(CPU_RT_PRIORITY_NAME_CONF) + 1)) {
+ cpu_boosting_conf->cpu_sched_info.cpu_rt_priority =
+ atoi(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else {
+ _E("[CONFIG] Unknown section name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+
+static int limiter_config(struct parse_result *result, void *user_data)
+{
+ if (!result)
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+
+ struct memcg_conf *memcg_conf = get_memcg_conf();
+ if (memcg_conf == NULL) {
+ _E("[CONFIG] memory cgroup configuration is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ struct cpu_throttling_conf *cpu_throttling_conf = get_cpu_throttling_conf();
+ if (cpu_throttling_conf == NULL) {
+ _E("[CONFIG] cpu_throttling configuration is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!strncmp(result->section, MEMORY_THROTTLING_SECTION,
+ strlen(MEMORY_THROTTLING_SECTION)+1)) {
+ char *ptr = strchr(result->value, '%');
+ if (ptr == NULL) {
+ _E("[CONFIG] Cannot find '%%' in the string (%s)", result->value);
+ return RESOURCED_ERROR_FAIL;
+ }
+ else
+ *ptr = '\0';
+
+ if (!strncmp(result->name, THROTTLING_LIMIT_NAME_CONF,
+ strlen(THROTTLING_LIMIT_NAME_CONF) + 1)) {
+ memcg_conf->cgroup_limit[MEMCG_THROTTLING] = atof(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else if (!strncmp(result->section, MEMORY_LEVEL_THRESHOLD_SECTION,
+ strlen(MEMORY_LEVEL_THRESHOLD_SECTION)+1)) {
+
+ if (!strncmp(result->name, OOM_POPUP_NAME_CONF,
+ strlen(OOM_POPUP_NAME_CONF) + 1)) {
+ memcg_conf->oom_popup = config_parse_bool(result->value);
+ }
+ else {
+ char temp = '\0';
+ int error = RESOURCED_ERROR_NONE;
+ bool percent;
+ char *ptr = strchr(result->value, '%');
+ if (ptr == NULL) {
+ ptr = strchr(result->value, 'B');
+ if (ptr == NULL) {
+ _E("[CONFIG] Cannot find 'B' in the string (%s)", result->value);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (result->value > (ptr - 1)) {
+ _E("[CONFIG] Size of string should be larger than 1");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ temp = *(ptr - 1);
+ *(ptr - 1) = '\0';
+ percent = false;
+ }
+ else {
+ *ptr = '\0';
+ percent = true;
+ }
+
+ if (!strncmp(result->name, MEDIUM_LEVEL_NAME_CONF,
+ strlen(MEDIUM_LEVEL_NAME_CONF) + 1)) {
+ error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_MEDIUM, result->value);
+ }
+ else if (!strncmp(result->name, LOW_LEVEL_NAME_CONF,
+ strlen(LOW_LEVEL_NAME_CONF) + 1)) {
+ error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_LOW, result->value);
+ }
+ else if (!strncmp(result->name, CRITICAL_LEVEL_NAME_CONF,
+ strlen(CRITICAL_LEVEL_NAME_CONF) + 1)) {
+ error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_CRITICAL, result->value);
+ }
+ else if (!strncmp(result->name, OOM_LEVEL_NAME_CONF,
+ strlen(OOM_LEVEL_NAME_CONF) + 1)) {
+ error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_OOM, result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+
+ return error;
+ }
+ }
+ else if (!strncmp(result->section, MEMORY_APP_TYPE_LIMIT_SECTION,
+ strlen(MEMORY_APP_TYPE_LIMIT_SECTION)+1)) {
+ int error = RESOURCED_ERROR_NONE;
+
+ if (!strncmp(result->name, SERVICE_PER_APP_LIMIT_ACTION_NAME_CONF,
+ strlen(SERVICE_PER_APP_LIMIT_ACTION_NAME_CONF) + 1)) {
+ error = set_mem_action_conf(&memcg_conf->service, result->value);
+ }
+ else if (!strncmp(result->name, WIDGET_PER_APP_LIMIT_ACTION_NAME_CONF,
+ strlen(WIDGET_PER_APP_LIMIT_ACTION_NAME_CONF) + 1)) {
+ error = set_mem_action_conf(&memcg_conf->widget, result->value);
+ }
+ else if (!strncmp(result->name, GUI_PER_APP_LIMIT_ACTION_NAME_CONF,
+ strlen(GUI_PER_APP_LIMIT_ACTION_NAME_CONF) + 1)) {
+ error = set_mem_action_conf(&memcg_conf->guiapp, result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+
+ return error;
+ }
+ else if (!strncmp(result->section, MEMORY_APP_STATUS_LIMIT_SECTION,
+ strlen(MEMORY_APP_STATUS_LIMIT_SECTION)+1)) {
+ int error = RESOURCED_ERROR_NONE;
+
+ if (!strncmp(result->name, BACKGROUND_PER_APP_LIMIT_ACTION_NAME_CONF,
+ strlen(BACKGROUND_PER_APP_LIMIT_ACTION_NAME_CONF) + 1)) {
+ error = set_mem_action_conf(&memcg_conf->background, result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+
+ return error;
+ }
+ else if (!strncmp(result->section, CPU_THROTTLING_SECTION,
+ strlen(CPU_THROTTLING_SECTION)+1)) {
+ if (!cpu_throttling_conf->enable)
+ cpu_throttling_conf->enable = true;
+
+ if (!strncmp(result->name, CPU_SCHED_NAME_CONF,
+ strlen(CPU_SCHED_NAME_CONF)+1)) {
+ cpu_throttling_conf->cpu_sched_info.cpu_sched_type =
+ config_parse_sched_type(result->value);
+ }
+ else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
+ strlen(CPU_NICE_NAME_CONF)+1)) {
+ cpu_throttling_conf->cpu_sched_info.cpu_nice =
+ atoi(result->value);
+ }
+ else if (!strncmp(result->name, CPU_SHARE_NAME_CONF,
+ strlen(CPU_SHARE_NAME_CONF)+1)) {
+ cpu_throttling_conf->cpu_cgroup_info.cpu_share =
+ strtoull(result->value, NULL, 10);
+ }
+ else if (!strncmp(result->name, CPU_CFS_RUN_TIME_NAME_CONF,
+ strlen(CPU_CFS_RUN_TIME_NAME_CONF)+1)) {
+ cpu_throttling_conf->cpu_cgroup_info.cfs_runtime_us =
+ config_parse_ll_time_us(result->value);
+ }
+ else if (!strncmp(result->name, CPU_CFS_PERIOD_NAME_CONF,
+ strlen(CPU_CFS_PERIOD_NAME_CONF)+1)) {
+ cpu_throttling_conf->cpu_cgroup_info.cfs_period_us =
+ config_parse_ull_time_us(result->value);
+ }
+ else {
+ _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+ }
+ else {
+ _E("[CONFIG] Unknown section name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int vendor_config(struct parse_result *result, void *user_data)
+{
+ int *config_type = (int *)user_data;
+ static struct proc_conf_info *pci = NULL;
+
+ if (!result || !user_data)
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+
+ if (strncmp(result->section, PRIVATE_SECTION, strlen(PRIVATE_SECTION)+1)) {
+ if (strncmp(result->section, OLD_VIP_GROUP_SECTION, strlen(OLD_VIP_GROUP_SECTION)+1)) {
+ return RESOURCED_ERROR_NONE;
+ }
+ }
+
+ /* common(App or Service or Process) */
+ if (!strncmp(result->name, APP_NAME_CONF, strlen(APP_NAME_CONF)+1) ||
+ !strncmp(result->name, SERVICE_NAME_CONF, strlen(SERVICE_NAME_CONF)+1) ||
+ !strncmp(result->name, OLD_SERVICE_NAME_CONF, strlen(OLD_SERVICE_NAME_CONF)+1) ||
+ !strncmp(result->name, PROCESS_NAME_CONF, strlen(PROCESS_NAME_CONF)+1) ||
+ !strncmp(result->name, OLD_PROCESS_NAME_CONF, strlen(OLD_PROCESS_NAME_CONF)+1)) {
+ pci = fixed_app_and_service_exist_check(result->value,
+ result->name[0] == 'A' ? APP_TYPE :
+ result->name[0] == 'S' ? SERVICE_TYPE : PROCESS_TYPE);
+ if (pci == NULL) {
+ pci = (struct proc_conf_info *)calloc(1, sizeof(struct proc_conf_info));
+ if (pci == NULL) {
+ _E("Failed to allocate memory during parsing vendor configurations");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ pci->cpu_sched_info.cpu_sched_type = CPU_SCHED_NONE;
+ pci->cpu_sched_info.cpu_rt_priority = CPU_INIT_PRIO;
+ pci->cpu_sched_info.cpu_nice = CPU_INIT_NICE;
+ pci->watchdog_action = PROC_ACTION_KILL;
+ pci->fail_action = PROC_ACTION_IGNORE;
+ pci->cpu_boosting_level = CPU_BOOSTING_LEVEL_NONE;
+ strncpy(pci->name, result->value, sizeof(pci->name)-1);
+
+ if (result->name[0] == 'A')
+ fixed_app_list_insert(pci);
+ else if (result->name[0] == 'S')
+ fixed_service_list_insert(pci);
+ else
+ fixed_process_list_insert(pci);
+ }
+ }
+ /* limiter.conf.d */
+/* else if (!strncmp(result->name, MEM_CGROUP_NAME_CONF, strlen(MEM_CGROUP_NAME_CONF)+1) &&
+ *config_type == LIMITER_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!strncmp(result->value, CGROUP_HIGH_VALUE_CONF,
+ strlen(CGROUP_HIGH_VALUE_CONF) +1)) {
+ pci->mem_type = MEMCG_HIGH;
+ }
+ else if (!strncmp(result->value, CGROUP_MEDIUM_VALUE_CONF,
+ strlen(CGROUP_MEDIUM_VALUE_CONF) +1)) {
+ pci->mem_type = MEMCG_MEDIUM;
+ }
+ else if (!strncmp(result->value, CGROUP_LOW_VALUE_CONF,
+ strlen(CGROUP_LOW_VALUE_CONF) +1)) {
+ pci->mem_type = MEMCG_LOW;
+ }
+ else {
+ _E("invalid parameter (%s)", result->value);
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+ }
+ }*/
+ else if (!strncmp(result->name, MEM_LIMIT_ACTION_NAME_CONF,
+ strlen(MEM_LIMIT_ACTION_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) {
+ int error;
+
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ error = set_mem_action_conf(&pci->mem_action, result->value);
+ return error;
+ }
+ else if (!strncmp(result->name, MEMORY_THROTTLING_NAME_CONF,
+ strlen(MEMORY_THROTTLING_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) {
+
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ /* Enable throttling of a service */
+ pci->memory_throttling_enable = config_parse_bool(result->value);
+ }
+ else if (!strncmp(result->name, CPU_THROTTLING_NAME_CONF,
+ strlen(CPU_THROTTLING_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) {
+
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ /* Enable throttling of an app (or a service) */
+ pci->cpu_throttling_enable = config_parse_bool(result->value);
+ }
+ /* optimizer.conf.d */
+ else if (!strncmp(result->name, CPU_SCHED_NAME_CONF, strlen(CPU_SCHED_NAME_CONF)+1) &&
+ *config_type == OPTIMIZER_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ pci->cpu_sched_info.cpu_sched_type = config_parse_sched_type(result->value);
+
+ }
+ else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
+ strlen(CPU_NICE_NAME_CONF)+1) && *config_type == OPTIMIZER_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ pci->cpu_sched_info.cpu_nice = atoi(result->value);
+ }
+ else if (!strncmp(result->name, CPU_RT_PRIORITY_NAME_CONF,
+ strlen(CPU_RT_PRIORITY_NAME_CONF)+1) && *config_type == OPTIMIZER_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ pci->cpu_sched_info.cpu_rt_priority = atoi(result->value);
+ }
+ else if (!strncmp(result->name, CPU_BOOSTING_LEVEL_NAME_CONF,
+ strlen(CPU_BOOSTING_LEVEL_NAME_CONF)+1) && *config_type == OPTIMIZER_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ pci->cpu_boosting_level = config_parse_boosting_level(result->value);
+ }
+/* else if (!strncmp(result->name, CPU_RT_RUN_TIME_NAME_CONF,
+ strlen(CPU_RT_RUN_TIME_NAME_CONF)+1) &&
+ *config_type == OPTIMIZER_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+ pci->cpu_sched_info.rt_runtime_us = config_parse_time_us(result->value);
+ }
+ else if (!strncmp(result->name, CPU_RT_PERIOD_NAME_CONF,
+ strlen(CPU_RT_PERIOD_NAME_CONF)+1) &&
+ *config_type == OPTIMIZER_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+ pci->cpu_sched_info.rt_period_us = config_parse_time_us(result->value);
+ }*/
+ else if (!strncmp(result->name, ACTION_ON_FAILURE_NAME_CONF,
+ strlen(ACTION_ON_FAILURE_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!strncmp(result->value, ACTION_REBOOT_VALUE_CONF,
+ strlen(ACTION_REBOOT_VALUE_CONF) +1)) {
+ pci->fail_action = PROC_ACTION_REBOOT;
+ }
+ else {
+ _E("invalid parameter (%s)", result->value);
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+ }
+ }
+ else if (!strncmp(result->name, WATCHDOG_ACTION_NAME_CONF,
+ strlen(WATCHDOG_ACTION_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!strncmp(result->value, ACTION_IGNORE_VALUE_CONF,
+ strlen(ACTION_IGNORE_VALUE_CONF) +1)) {
+ pci->watchdog_action = PROC_ACTION_IGNORE;
+ }
+ else if (!strncmp(result->value, ACTION_KILL_VALUE_CONF,
+ strlen(ACTION_KILL_VALUE_CONF) +1)) {
+ pci->watchdog_action = PROC_ACTION_KILL;
+ }
+ else {
+ _E("invalid parameter (%s)", result->value);
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+ }
+ }
+ /* old style */
+ else if (!strncmp(result->name, OLD_ACTION_ON_FAILURE_NAME_CONF,
+ strlen(OLD_ACTION_ON_FAILURE_NAME_CONF)+1) && *config_type == VIP_CONFIG) {
+ if (!pci) {
+ _E("process configuration information pointer should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!strncmp(result->value, ACTION_REBOOT_VALUE_CONF,
+ strlen(ACTION_REBOOT_VALUE_CONF) +1)) {
+ pci->fail_action = PROC_ACTION_REBOOT;
+ }
+ else {
+ _E("invalid parameter (%s)", result->value);
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+ }
+ }
+ else {
+ _E("Unknown configuration name (%s) and value (%s) on section (%s)",
+ result->name, result->value, result->section);
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static void load_per_vendor_configs(const char *dir, int func(struct parse_result *result,
+ void *user_data), void *user_data)
+{
+ int count;
+ int idx;
+ struct dirent **namelist;
+
+ if ((count = scandir(dir, &namelist, NULL, alphasort)) == -1) {
+ _I("(%s) conf dir does not exist", dir);
+ return;
+ }
+
+ for (idx = 0; idx < count; idx++) {
+ char path[PATH_MAX] = {0, };
+
+ if (!strstr(namelist[idx]->d_name, CONF_FILE_SUFFIX))
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", dir, namelist[idx]->d_name);
+ config_parse(path, func, user_data);
+ free(namelist[idx]);
+ }
+
+ free(namelist);
+}
+
+void resourced_parse_vendor_configs(void)
+{
+ int config_type;
+
+ fixed_app_and_service_list_init();
+
+ /* Load configurations in limiter.conf and limiter.conf.d/ */
+ config_parse(LIMITER_CONF_FILE, limiter_config, NULL);
+ config_type = LIMITER_CONFIG;
+ load_per_vendor_configs(LIMITER_CONF_DIR, vendor_config, &config_type);
+
+ /* Load configurations in optimizer.conf and optimizer.conf.d */
+ config_parse(OPTIMIZER_CONF_FILE, optimizer_config, NULL);
+ config_type = OPTIMIZER_CONFIG;
+ load_per_vendor_configs(OPTIMIZER_CONF_DIR, vendor_config, &config_type);
+
+ /* Load configuration in process.conf */
+ config_type = PROCESS_CONFIG;
+ load_per_vendor_configs(PROC_CONF_DIR, vendor_config, &config_type);
+
+ /* old style */
+ config_type = VIP_CONFIG;
+ load_per_vendor_configs(VIP_CONF_DIR, vendor_config, &config_type);
+}
+
+void resourced_free_vendor_configs(void)
+{
+ fixed_app_and_service_list_exit();
+}
+
+int config_parse(const char *file_name, int cb(struct parse_result *result,
+ void *user_data), void *user_data)
+{
+ FILE *f = NULL;
+ struct parse_result result;
+ /* use stack for parsing */
+ char line[LINE_MAX];
+ char section[MAX_SECTION];
+ char *start, *end, *name, *value;
+ int lineno = 0, ret = 0;
+
+ if (!file_name || !cb) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* open conf file */
+ f = fopen(file_name, "r");
+ if (!f) {
+ _E("Failed to open file %s", file_name);
+ ret = -EIO;
+ goto error;
+ }
+
+ /* parsing line by line */
+ while (fgets(line, LINE_MAX, f) != NULL) {
+ lineno++;
+
+ start = line;
+ truncate_nl(start);
+ start = strstrip(start);
+
+ if (*start == COMMENT) {
+ continue;
+ } else if (*start == '[') {
+ /* parse section */
+ end = strchr(start, ']');
+ if (!end || *end != ']') {
+ ret = -EBADMSG;
+ goto error;
+ }
+
+ *end = '\0';
+ strncpy(section, start + 1, sizeof(section)-1);
+ section[MAX_SECTION-1] = '\0';
+ } else if (*start) {
+ /* parse name & value */
+ end = strchr(start, '=');
+ if (!end || *end != '=') {
+ ret = -EBADMSG;
+ goto error;
+ }
+ *end = '\0';
+ name = strstrip(start);
+ value = strstrip(end + 1);
+ end = strchr(value, COMMENT);
+ if (end && *end == COMMENT) {
+ *end = '\0';
+ value = strstrip(value);
+ }
+
+ result.section = section;
+ result.name = name;
+ result.value = value;
+ /* callback with parse result */
+ ret = cb(&result, user_data);
+ if (ret < 0) {
+ ret = -EBADMSG;
+ goto error;
+ }
+ }
+ }
+ _D("Success to load %s", file_name);
+ fclose(f);
+ return 0;
+
+error:
+ if (f)
+ fclose(f);
+ _E("Failed to read %s:%d!", file_name, lineno);
+ return ret;
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 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 __CONFIG_PARSER_H__
+#define __CONFIG_PARSER_H__
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define CONF_FILE_SUFFIX ".conf"
+
+#define LIMITER_CONF_FILE RD_CONFIG_FILE(limiter)
+#define OPTIMIZER_CONF_FILE RD_CONFIG_FILE(optimizer)
+#define LIMITER_CONF_DIR RD_CONFIG_PATH"/limiter.conf.d"
+#define OPTIMIZER_CONF_DIR RD_CONFIG_PATH"/optimizer.conf.d"
+#define PROC_CONF_DIR RD_CONFIG_PATH"/process.conf.d"
+/* old style */
+#define VIP_CONF_DIR RD_CONFIG_PATH"/vip-process.d"
+
+/* section name */
+/* limiter.conf */
+#define PRIVATE_SECTION "Private"
+#define MEMORY_LEVEL_THRESHOLD_SECTION "MemoryLevelThreshold"
+#define MEMORY_APP_TYPE_LIMIT_SECTION "MemoryAppTypeLimit"
+#define MEMORY_APP_STATUS_LIMIT_SECTION "MemoryAppStatusLimit"
+#define MEMORY_THROTTLING_SECTION "MemoryThrottling"
+#define CPU_THROTTLING_SECTION "CpuThrottling"
+#define OLD_VIP_GROUP_SECTION "VIP_GROUP"
+
+/* optimizer.conf */
+#define SWAP_SECTION "MemorySwap"
+#define ZRAM_SECTION "MemoryZram"
+#define ZSWAP_SECTION "MemoryZswap"
+#define DEDUP_SECTION "MemoryDedup"
+#define KSM_SECTION "MemoryKsm"
+#define COMPACTION_SECTION "MemoryCompaction"
+#define CPU_SCHED_SECTION "CpuSched"
+#define CPU_AFFINITY_SECTION "CpuAffinity"
+#define CPU_BOOSTING_LEVEL_STRONG_SECTION "CpuBoostingLevelStrong"
+#define CPU_BOOSTING_LEVEL_MEDIUM_SECTION "CpuBoostingLevelMedium"
+#define CPU_BOOSTING_LEVEL_WEAK_SECTION "CpuBoostingLevelWeak"
+
+/* configuration name */
+/* limiter.conf */
+#define APP_NAME_CONF "App"
+#define SERVICE_NAME_CONF "Service"
+#define OLD_SERVICE_NAME_CONF "SERVICE" /* old style */
+#define PROCESS_NAME_CONF "Process"
+#define OLD_PROCESS_NAME_CONF "PROCESS" /* old style */
+#define MEM_CGROUP_NAME_CONF "MemGroup"
+#define MEM_LIMIT_ACTION_NAME_CONF "MemLimitAction"
+#define ACTION_ON_FAILURE_NAME_CONF "ActionOnFailure"
+#define OLD_ACTION_ON_FAILURE_NAME_CONF "ACTION_ON_FAILURE"
+#define WATCHDOG_ACTION_NAME_CONF "WatchdogAction"
+#define THROTTLING_LIMIT_NAME_CONF "ThrottlingLimit"
+#define MEDIUM_LEVEL_NAME_CONF "MediumLevel"
+#define LOW_LEVEL_NAME_CONF "LowLevel"
+#define CRITICAL_LEVEL_NAME_CONF "CriticalLevel"
+#define OOM_LEVEL_NAME_CONF "OomLevel"
+#define OOM_POPUP_NAME_CONF "OomPopup"
+#define SERVICE_PER_APP_LIMIT_ACTION_NAME_CONF "ServicePerAppLimitAction"
+#define WIDGET_PER_APP_LIMIT_ACTION_NAME_CONF "WidgetPerAppLimitAction"
+#define GUI_PER_APP_LIMIT_ACTION_NAME_CONF "GUIPerAppLimitAction"
+#define BACKGROUND_PER_APP_LIMIT_ACTION_NAME_CONF "BackgroundPerAppLimitAction"
+
+/* CPU specific configuration name */
+#define CPU_SCHED_NAME_CONF "CpuSched"
+#define CPU_NICE_NAME_CONF "CpuNice"
+#define CPU_SHARE_NAME_CONF "CpuShare"
+#define CPU_RT_PRIORITY_NAME_CONF "CpuRTPriority"
+#define CPU_SCHED_FEATURE_NAME_CONF "CpuSchedFeature"
+#define CPU_RT_RUN_TIME_NAME_CONF "CpuRTRuntime"
+#define CPU_RT_PERIOD_NAME_CONF "CpuRTPeriod"
+#define CPU_CFS_RUN_TIME_NAME_CONF "CpuCFSRuntime"
+#define CPU_CFS_PERIOD_NAME_CONF "CpuCFSPeriod"
+#define CPU_BOOSTING_LEVEL_NAME_CONF "CpuBoostingLevel"
+#define MEMORY_THROTTLING_NAME_CONF "MemoryThrottling"
+#define CPU_THROTTLING_NAME_CONF "CpuThrottling"
+
+/* optimizer.conf */
+#define SWAP_ENABLE_NAME_CONF "SwapEnable"
+#define RECLAIM_AT_BOOT_NAME_CONF "ReclaimAtBoot"
+#define SWAP_TYPE_NAME_CONF "SwapType"
+#define THROTTLING_SWAPPINESS_NAME_CONF "ThrottlingSwappiness"
+#define COMP_ALGORITHM_NAME_CONF "CompAlgorithm"
+#define ZRAM_RATIO_NAME_CONF "ZramRatio"
+#define POOL_RATIO_NAME_CONF "PoolRatio"
+#define POOL_TYPE_NAME_CONF "PoolType"
+#define DEDUP_ENABLE_NAME_CONF "DedupEnable"
+#define DEDUP_AT_BOOT_NAME_CONF "DedupAtBoot"
+#define SCAN_ON_LOWMEM_NAME_CONF "ScanOnLowmem"
+#define KSM_MODE_NAME_CONF "KsmMode"
+#define PAGES_TO_SCAN_NAME_CONF "PagesToScan"
+#define PAGES_TO_SCAN_WITH_BOOST_NAME_CONF "PagesToScanWithBoost"
+#define COMPACTION_ENABLE_NAME_CONF "CompactionEnable"
+#define FRAG_LEVEL_NAME_CONF "FragLevel"
+#define FOREGROUND_APPS_NAME_CONF "ForegroundApps"
+
+/* configuration value */
+#define CGROUP_LOW_VALUE_CONF "lowest"
+#define ACTION_BROADCAST_VALUE_CONF "broadcast"
+#define ACTION_RECLAIM_VALUE_CONF "reclaim"
+#define ACTION_KILL_VALUE_CONF "kill"
+#define ACTION_REBOOT_VALUE_CONF "reboot"
+#define ACTION_IGNORE_VALUE_CONF "ignore"
+
+/* CPU specific configuration name */
+#define RT_RUNTIME_SHARE_VALUE_CONF "rt_runtime_share"
+#define NO_RT_RUNTIME_SHARE_VALUE_CONF "no_rt_runtime_share"
+#define CPU_SCHED_DEADLINE_VALUE_CONF "deadline"
+#define CPU_SCHED_FIFO_VALUE_CONF "fifo"
+#define CPU_SCHED_RR_VALUE_CONF "rr"
+#define CPU_SCHED_OTHER_VALUE_CONF "other"
+#define CPU_SCHED_IDLE_VALUE_CONF "idle"
+#define CPU_SCHED_BATCH_VALUE_CONF "batch"
+#define CPU_BOOSTING_LEVEL_STRONG_VALUE_CONF "strong"
+#define CPU_BOOSTING_LEVEL_MEDIUM_VALUE_CONF "medium"
+#define CPU_BOOSTING_LEVEL_WEAK_VALUE_CONF "weak"
+
+#define MATCH(a, b) (!strncmp(a, b, strlen(a) + 1) ? 1 : 0)
+#define SET_CONF(a, b) (a = (b > 0.0 ? b : a))
+
+enum config_type {
+ LIMITER_CONFIG,
+ OPTIMIZER_CONFIG,
+ MONITOR_CONFIG,
+ PROCESS_CONFIG,
+ VIP_CONFIG, /* old style */
+};
+
+struct parse_result {
+ char *section;
+ char *name;
+ char *value;
+};
+
+/**
+ * @brief Parse config file and call callback\n
+ * @param[in] file_name conf file.
+ * @param[in] cb cb is called when conf file is parsed line by line.
+ * @param[in] user_data user data is passed to cb.
+ * @return 0 on success, negative if failed
+ */
+int config_parse(const char *file_name, int cb(struct parse_result *result,
+ void *user_data), void *user_data);
+
+/* Prototype for a parser for a specific configuration setting */
+typedef int (*ConfigParserCallback)(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data);
+
+typedef int (*ConfigParseFunc)(const char *path, void *data);
+
+/* Wraps information for parsing a specific configuration variable, to
+ * be stored in a simple array */
+typedef struct ConfigTableItem {
+ const char *section; /* Section */
+ const char *lvalue; /* Name of the variable */
+ ConfigParserCallback cb; /* Function that is called to
+ * parse the variable's
+ * value */
+ int ltype; /* Distinguish different
+ * variables passed to the
+ * same callback */
+ void *data; /* Where to store the
+ * variable's data */
+} ConfigTableItem;
+
+void remove_app_conf_info_list(void);
+void remove_service_conf_info_list(void);
+GSList *get_app_conf_info_list(void);
+GSList *get_service_conf_info_list(void);
+void resourced_parse_vendor_configs(void);
+void resourced_free_vendor_configs(void);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
--- /dev/null
+#ifndef _CONFIG_H_GENERATED
+#define _CONFIG_H_GENERATED
+
+#cmakedefine EXCLUDE_LIST_RO_PATH "@EXCLUDE_LIST_RO_PATH@"
+#cmakedefine EXCLUDE_LIST_RW_PATH "@EXCLUDE_LIST_RW_PATH@"
+/* It's command line arguments*/
+
+#cmakedefine CONFIG_DATAUSAGE_NFACCT @CONFIG_DATAUSAGE_NFACCT@
+#cmakedefine TETHERING_FEATURE @TETHERING_FEATURE@
+
+#endif /* _CONFIG_H_GENERATED*/
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 "macro.h"
+#include "cpu-common.h"
+#include "trace.h"
+#include "resourced.h"
+
+static struct cpu_sched_conf *cpu_sched_conf = NULL;
+static struct cpu_affinity_conf *cpu_affinity_conf = NULL;
+static struct cpu_throttling_conf *cpu_throttling_conf = NULL;
+static struct cpu_boosting_conf *cpu_boosting_conf[CPU_BOOSTING_LEVEL_END] = {NULL, };
+
+struct cpu_sched_conf *get_cpu_sched_conf(void)
+{
+ if (!cpu_sched_conf) {
+ cpu_sched_conf = (struct cpu_sched_conf *)calloc(1, sizeof (struct cpu_sched_conf));
+ if (!cpu_sched_conf) {
+ _E("Failed to alloc memory for cpu scheduler configuration");
+ return NULL;
+ }
+ else {
+ cpu_sched_conf->cpu_sched_flag = CPU_SCHED_UNINITIALIZED;
+ cpu_sched_conf->cpu_cgroup_info.rt_runtime_us = 0;
+ cpu_sched_conf->cpu_cgroup_info.rt_period_us = 0;
+ }
+ }
+
+ return cpu_sched_conf;
+}
+
+void free_cpu_sched_conf(void)
+{
+ if (cpu_sched_conf)
+ free(cpu_sched_conf);
+}
+
+char *get_cpu_affinity_conf_name(void)
+{
+ if (cpu_affinity_conf)
+ return cpu_affinity_conf->cpuset_cgroup_info.name;
+ else
+ return NULL;
+}
+
+char *get_cpu_affinity_conf_value(void)
+{
+ if (cpu_affinity_conf)
+ return cpu_affinity_conf->cpuset_cgroup_info.value;
+ else
+ return NULL;
+}
+
+int set_cpu_affinity_conf(const char *name, const char *value)
+{
+ if (!cpu_affinity_conf) {
+ cpu_affinity_conf = (struct cpu_affinity_conf *)calloc(1, sizeof (struct cpu_affinity_conf));
+ if (!cpu_affinity_conf) {
+ _E("Failed to alloc memory for cpu affinity configuration");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
+ if (strlen(name) + 1 > sizeof(cpu_affinity_conf->cpuset_cgroup_info.name)) {
+ _E("Size of cpu configuration for name is not enough");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ strncpy(cpu_affinity_conf->cpuset_cgroup_info.name, name, sizeof(cpu_affinity_conf->cpuset_cgroup_info.name) - 1);
+
+ if (strlen(value) + 1 > sizeof(cpu_affinity_conf->cpuset_cgroup_info.value)) {
+ _E("Size of cpu configuration for value is not enough");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ strncpy(cpu_affinity_conf->cpuset_cgroup_info.value, value, sizeof(cpu_affinity_conf->cpuset_cgroup_info.value) - 1);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+void free_cpu_affinity_conf(void)
+{
+ if (cpu_affinity_conf)
+ free(cpu_affinity_conf);
+}
+
+struct cpu_throttling_conf *get_cpu_throttling_conf(void)
+{
+ if (!cpu_throttling_conf) {
+ cpu_throttling_conf = (struct cpu_throttling_conf *)calloc(1, sizeof (struct cpu_throttling_conf));
+ if (!cpu_throttling_conf) {
+ _E("Failed to alloc memory for cpu throttling configuration");
+ return NULL;
+ }
+ else {
+ cpu_throttling_conf->enable = false;
+ cpu_throttling_conf->cpu_sched_info.cpu_sched_type = CPU_SCHED_NONE;
+ cpu_throttling_conf->cpu_sched_info.cpu_nice = CPU_INIT_NICE;
+ cpu_throttling_conf->cpu_cgroup_info.cfs_runtime_us = 0;
+ cpu_throttling_conf->cpu_cgroup_info.cfs_period_us = 0;
+ cpu_throttling_conf->cpu_cgroup_info.cpu_share = 0;
+ }
+ }
+
+ return cpu_throttling_conf;
+}
+
+void free_cpu_throttling_conf(void)
+{
+ if (cpu_throttling_conf)
+ free(cpu_throttling_conf);
+}
+
+struct cpu_boosting_conf *get_cpu_boosting_conf(cpu_boosting_level_e level)
+{
+ if (!cpu_boosting_conf[level]) {
+ cpu_boosting_conf[level] = (struct cpu_boosting_conf *)
+ calloc(1, sizeof (struct cpu_boosting_conf));
+
+ if (!cpu_boosting_conf[level]) {
+ _E("Failed to alloc memory for cpu boosting (level = %d) configuration", level);
+ return NULL;
+ }
+ else {
+ cpu_boosting_conf[level]->enable = false;
+ cpu_boosting_conf[level]->cpu_sched_info.cpu_sched_type = CPU_SCHED_NONE;
+ cpu_boosting_conf[level]->cpu_sched_info.cpu_nice = CPU_INIT_NICE;
+ cpu_boosting_conf[level]->cpu_sched_info.cpu_rt_priority = CPU_INIT_PRIO;
+ }
+ }
+
+ return cpu_boosting_conf[level];
+}
+
+void free_cpu_boosting_conf(cpu_boosting_level_e level)
+{
+ if (cpu_boosting_conf[level])
+ free(cpu_boosting_conf[level]);
+}
--- /dev/null
+#ifndef __CPU_COMMON_H__
+#define __CPU_COMMON_H__
+
+#include <stdbool.h>
+
+#include <cpu-boosting-type.h>
+#include <cpu-boosting-private.h>
+
+#include "util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define CPU_INIT_NICE 100
+#define CPU_MAX_NICE 19
+#define CPU_MIN_NICE -20
+#define CPU_DEFAULT_NICE 0
+
+#define CPU_INIT_PRIO 0
+#define CPU_MAX_PRIO 99
+#define CPU_MIN_PRIO 1
+
+#define CPU_DEFAULT_SHARE 1024
+#define CPU_THROTTLING_SHARE 64
+
+enum cpu_sched_flag {
+ CPU_SCHED_UNINITIALIZED = 0,
+ CPU_SCHED_RUNTIME_SHARE = 1,
+ CPU_SCHED_NO_RUNTIME_SHARE = 2,
+ CPU_SCHED_RUNTIME_GREED = 4,
+};
+
+enum cpu_sched_type {
+ CPU_SCHED_NONE = 0,
+ CPU_SCHED_IDLE = 1,
+ CPU_SCHED_BATCH,
+ CPU_SCHED_OTHER,
+ CPU_SCHED_FIFO,
+ CPU_SCHED_RR,
+ CPU_SCHED_DEADLINE,
+};
+
+struct cpu_boosting_info {
+ pid_t tid;
+ int level; /* current boosting level */
+ guint gsource_id; /* timer id */
+};
+
+struct cpu_boosting_input {
+ cpu_boosting_input_t client_input;
+ int sock;
+ guint *gsource_id;
+ bool remove_input;
+};
+
+struct cpu_sched_info {
+ enum cpu_sched_type cpu_sched_type;
+ int cpu_nice; /* fixed cpu nice */
+ int cpu_rt_priority; /* fixed cpu priority for rt schedulers */
+};
+
+struct cpuset_cgroup_info {
+ char name[64];
+ char value[64];
+};
+
+struct cpu_cgroup_info {
+ long long cfs_runtime_us;
+ long long rt_runtime_us;
+ unsigned long long cfs_period_us;
+ unsigned long long rt_period_us;
+ unsigned long long cpu_share;
+};
+
+struct cpu_sched_conf {
+ enum cpu_sched_flag cpu_sched_flag;
+ struct cpu_cgroup_info cpu_cgroup_info;
+};
+
+struct cpu_affinity_conf {
+ struct cpuset_cgroup_info cpuset_cgroup_info;
+};
+
+struct cpu_throttling_conf {
+ bool enable;
+ struct cpu_sched_info cpu_sched_info;
+ struct cpu_cgroup_info cpu_cgroup_info;
+};
+
+struct cpu_boosting_conf {
+ bool enable;
+ struct cpu_sched_info cpu_sched_info;
+};
+
+struct cpu_sched_conf *get_cpu_sched_conf(void);
+void free_cpu_sched_conf(void);
+
+char *get_cpu_affinity_conf_name(void);
+char *get_cpu_affinity_conf_value(void);
+int set_cpu_affinity_conf(const char *name, const char *value);
+void free_cpu_affinity_conf(void);
+
+struct cpu_throttling_conf *get_cpu_throttling_conf(void);
+void free_cpu_throttling_conf(void);
+
+struct cpu_boosting_conf *get_cpu_boosting_conf(cpu_boosting_level_e level);
+void free_cpu_boosting_conf(cpu_boosting_level_e level);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CPU_COMMON_H__ */
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 "macro.h"
+#include "dedup-common.h"
+#include "trace.h"
+
+static struct dedup_conf *dedup_conf = NULL;
+
+static enum dedup_state dedup_state;
+
+struct dedup_conf *get_dedup_conf(void)
+{
+ if (!dedup_conf) {
+ dedup_conf = (struct dedup_conf *)calloc(1, sizeof (struct dedup_conf));
+ if (!dedup_conf) {
+ _E("Failed to alloc memory for cpu configuration");
+ return NULL;
+ }
+ else {
+ dedup_conf->enable = false;
+ dedup_conf->boot_dedup_enable = false;
+ dedup_conf->scan_on_lowmem = false;
+ }
+ }
+
+ return dedup_conf;
+}
+
+void free_dedup_conf(void)
+{
+ if (dedup_conf)
+ free(dedup_conf);
+}
+
+enum dedup_state dedup_get_state(void)
+{
+ return dedup_state;
+}
+
+void dedup_set_state(enum dedup_state state)
+{
+ if ((state != DEDUP_ON) && (state != DEDUP_OFF) &&
+ state != DEDUP_ONE_SHOT)
+ return;
+
+ dedup_state = state;
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file dedup-common.h
+ * @desc dedup common process
+ **/
+
+#ifndef __DEDUP_COMMON_H__
+#define __DEDUP_COMMON_H__
+
+#include <stdio.h>
+#include "resourced.h"
+#include "memory-cgroup.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define DEDUP_CONF_FILE RD_CONFIG_FILE(optimizer)
+#define DEDUP_SYSFS_KSM_PATH "/sys/kernel/mm/ksm"
+
+/* KSM operations */
+#define DEDUP_SYSFS_KSM_RUN "/sys/kernel/mm/ksm/run"
+#define DEDUP_SYSFS_KSM_ONESHOT "/sys/kernel/mm/ksm/one_shot_scanning"
+
+enum dedup_state {
+ DEDUP_ARG_START = -1,
+ DEDUP_OFF,
+ DEDUP_ON,
+ DEDUP_ONE_SHOT,
+ DEDUP_ARG_END,
+};
+
+enum dedup_mode {
+ DEDUP_MODE_NONE = 0,
+ DEDUP_MODE_PERIODIC,
+ DEDUP_MODE_ONESHOT,
+ DEDUP_MODE_MAX,
+};
+
+enum ksm_stat {
+ KSM_STAT_PAGES_SHARING = 0,
+ KSM_STAT_PAGES_SHARED,
+ KSM_STAT_MAX,
+};
+
+enum ksm_scan_mode {
+ KSM_SCAN_NONE = 0,
+ KSM_SCAN_PARTIAL,
+ KSM_SCAN_FULL,
+};
+
+struct ksm {
+ char mode[MAX_TYPE_LENGTH];
+ int pages;
+ int boost_pages;
+};
+
+struct dedup_conf {
+ bool enable;
+ bool boot_dedup_enable;
+ bool scan_on_lowmem;
+ struct ksm ksm;
+};
+
+struct dedup_conf *get_dedup_conf(void);
+void free_dedup_conf(void);
+
+enum dedup_state dedup_get_state(void);
+void dedup_set_state(enum dedup_state state);
+unsigned int dedup_get_ksm_stat(enum ksm_stat stat_type);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __DEDUP_COMMON_H__ */
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 "macro.h"
+#include "swap-common.h"
+#include "trace.h"
+
+static struct swap_conf *swap_conf = NULL;
+
+static enum swap_state swap_state = SWAP_OFF;
+
+struct swap_conf *get_swap_conf(void)
+{
+ if (!swap_conf) {
+ swap_conf = (struct swap_conf *)calloc(1, sizeof (struct swap_conf));
+ if (!swap_conf) {
+ _E("Failed to alloc memory for cpu configuration");
+ return NULL;
+ }
+ else {
+ swap_conf->enable = false;
+ swap_conf->boot_reclaim_enable = false;
+ swap_conf->swap_type = SWAP_TYPE_NONE;
+ swap_conf->swappiness[MEMCG_THROTTLING] = MEMORY_INIT_SWAPPINESS;
+ }
+ }
+
+ return swap_conf;
+}
+
+
+void free_swap_conf(void)
+{
+ if (swap_conf)
+ free(swap_conf);
+}
+
+enum swap_state swap_get_state(void)
+{
+ return swap_state;
+}
+
+/* Following function is supposed to be used by swap module only.
+ *
+ * Implemented in common part for the purpose of integration with
+ * dynamically loaded "swap" plugin.
+ *
+ * From available options it seems cleaner to export getter/setter
+ * like the one below (with a bit of swap-internal logic).
+ * Other option would be keeping set function in swap module, but
+ * that would require us to reference and alter then-global swap_state
+ * variable (in common part) from swap shared object.
+ */
+void swap_set_state(enum swap_state state)
+{
+ if ((state != SWAP_ON) && (state != SWAP_OFF))
+ return;
+
+ swap_state = state;
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file swap-common.h
+ * @desc swap common process
+ **/
+
+#ifndef __SWAP_COMMON_H__
+#define __SWAP_COMMON_H__
+
+#include <stdio.h>
+#include "resourced.h"
+#include "memory-cgroup.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define SWAP_ZRAM_SYSFILE "/sys/block/zram0/"
+#define SWAP_FILE_NAME "/opt/usr/.swapfile"
+#define SWAP_CONF_FILE RD_CONFIG_FILE(optimizer)
+
+#define MEMORY_INIT_SWAPPINESS 200
+
+enum swap_state {
+ SWAP_ARG_START = -1,
+ SWAP_OFF,
+ SWAP_ON,
+ SWAP_ARG_END,
+};
+
+enum swap_type {
+ SWAP_TYPE_NONE = 0x0,
+ SWAP_TYPE_ZRAM = 0x1,
+ SWAP_TYPE_FILE = 0x2,
+ SWAP_TYPE_ZSWAP = 0x4,
+ SWAP_TYPE_MAX,
+};
+
+struct swap_status_msg {
+ char path[MAX_PATH_LENGTH];
+};
+
+enum swap_compact_reason {
+ SWAP_COMPACT_MEM_LEVEL_CRITICAL,
+ SWAP_COMPACT_MEM_LEVEL_OOM,
+ SWAP_COMPACT_SWAP_FULL,
+ SWAP_COMPACT_RESASON_MAX,
+};
+
+/*
+ * Each swap modoule can have priority.
+ * The swap list of kernel has low-to-high order
+ * while swap ordering is high-to-low.
+ * So, if a swap module has lower priority, it should be intialized eariler.
+ * On the top of that, SWAP_PRI_DISABLE will be used
+ * not to support multiple swap devices.
+ */
+enum swap_priority {
+ SWAP_PRI_DISABLE = -255,
+ SWAP_PRI_LOW = -1,
+ SWAP_PRI_DEFAULT = 0,
+ SWAP_PRI_HIGH = 1,
+};
+
+struct swap_module_ops {
+ char *name;
+ enum swap_type type;
+ char *path;
+ int priority;
+ unsigned int k_size;
+ int (*init)(void *data);
+ int (*exit) (void *data);
+ int (*activate)(void *data);
+ int (*reclaim)(void *data);
+ int (*conf)(void *data);
+};
+
+struct zram_conf {
+ char algorithm[MAX_TYPE_LENGTH - 1];
+ float ratio;
+};
+
+struct zswap_conf {
+ float pool_ratio;
+ char pool_type[MAX_TYPE_LENGTH -1];
+};
+
+struct swap_conf {
+ bool enable;
+ bool boot_reclaim_enable;
+ enum swap_type swap_type;
+ int swappiness[MEMCG_END];
+ struct zram_conf zram;
+ struct zswap_conf zswap;
+};
+
+struct swap_conf *get_swap_conf(void);
+void free_swap_conf(void);
+
+enum swap_state swap_get_state(void);
+void swap_set_state(enum swap_state state);
+
+int swap_set_file(char *file, struct swap_module_ops *swap, char *crypt_type);
+int do_mkswap(const char *device);
+int do_dd(char *input, char *output, unsigned int size, unsigned int count);
+
+bool swap_is_on(const char *name);
+
+void swap_add(const struct swap_module_ops *swap);
+void swap_remove(const struct swap_module_ops *swap);
+
+#define SWAP_MODULE_REGISTER(swap) \
+static void __attribute__ ((constructor)) swap_module_register(void) \
+{ \
+ swap_add(swap); \
+} \
+static void __attribute__ ((destructor)) swap_module_unregister(void) \
+{ \
+ swap_remove(swap); \
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __SWAP_COMMON_H__ */
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2013 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 <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <limits.h>
-#include <ctype.h>
-
-#include "util.h"
-#include "trace.h"
-#include "config-parser.h"
-#include "proc-common.h"
-#include "cpu-cgroup.h"
-#include "swap-common.h"
-#include "dedup-common.h"
-#include "compact-common.h"
-#include "cpu-common.h"
-
-#define MAX_SECTION 64
-
-static int config_parse_swap_types(
- const char *rvalue,
- void *data)
-{
- enum swap_type *type = data;
- char *word, *state;
- size_t l;
-
- if (is_empty(rvalue))
- return 0;
-
- *type = 0;
-
- FOREACH_WORD_SEPARATOR(word, l, rvalue, "+|", state) {
- if (strneq(word, "zram", l))
- *type |= SWAP_TYPE_ZRAM;
- else if (strneq(word, "file", l))
- *type |= SWAP_TYPE_FILE;
- else if (strneq(word, "zswap", l))
- *type |= SWAP_TYPE_ZSWAP;
- else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int config_parse_cpu_sched_features(const char *value)
-{
- int cpu_sched_flag = CPU_SCHED_UNINITIALIZED;
- char *word, *state;
- size_t l;
-
- if (is_empty(value))
- return cpu_sched_flag;
-
- FOREACH_WORD_SEPARATOR(word, l, value, ",", state) {
- if (strneq(word, RT_RUNTIME_SHARE_VALUE_CONF, l))
- cpu_sched_flag |= CPU_SCHED_RUNTIME_SHARE;
- else if (strneq(word, NO_RT_RUNTIME_SHARE_VALUE_CONF, l))
- cpu_sched_flag |= CPU_SCHED_NO_RUNTIME_SHARE;
-/* else if (strneq(word, RT_RUNTIME_GREED_VALUE_CONF, l))
- cpu_sched_flag |= CPU_SCHED_RUNTIME_GREED;*/
- else
- return CPU_SCHED_UNINITIALIZED;
- }
-
- return cpu_sched_flag;
-}
-
-static char config_parse_time_unit(const char *value)
-{
- char chr;
- char *ptr = strchr(value, 's');
- if (ptr == NULL) {
- _E("[CONFIG] Cannot find 's' in the string (%s)", value);
- return 'X';
- }
-
- if (value > (ptr - 1)) {
- _E("[CONFIG] Size of string should be larger than 1");
- return 'X';
- }
-
- chr = *(ptr - 1);
- if (isdigit(chr)) {
- *ptr = '\0';
- return ' ';
- }
- else {
- *(ptr - 1) = '\0';
- return chr;
- }
-}
-
-static long long config_parse_ll_time_us(const char *value)
-{
- char unit = config_parse_time_unit(value);
-
- if (unit == ' ') {
- return strtoll(value, NULL, 10) * 1000 * 1000;
- }
- else if (unit == 'm') {
- return strtoll(value, NULL, 10) * 1000;
- }
- else if (unit == 'u') {
- return strtoll(value, NULL, 10);
- }
- else {
- _E("[CONFIG] Unknown unit of time");
- return 0;
- }
-}
-
-static unsigned long long config_parse_ull_time_us(const char *value)
-{
- char unit = config_parse_time_unit(value);
-
- if (unit == ' ') {
- return strtoull(value, NULL, 10) * 1000 * 1000;
- }
- else if (unit == 'm') {
- return strtoull(value, NULL, 10) * 1000;
- }
- else if (unit == 'u') {
- return strtoull(value, NULL, 10);
- }
- else {
- _E("[CONFIG] Unknown unit of time");
- return 0;
- }
-}
-
-static bool config_parse_bool(const char *value)
-{
- if (!strncmp(value, "yes", 4) ||
- !strncmp(value, "1", 2) ||
- !strncmp(value, "ok", 3) ||
- !strncmp(value, "on", 3))
- return true;
- else if (!strncmp(value, "no", 3) ||
- !strncmp(value, "0", 2) ||
- !strncmp(value, "off", 4))
- return false;
- else {
- _E("Unknown name (%s)", value);
- return false;
- }
-}
-
-static int config_parse_sched_type(const char *value)
-{
- if (!strncmp(value, CPU_SCHED_IDLE_VALUE_CONF,
- strlen(CPU_SCHED_IDLE_VALUE_CONF) +1))
- return CPU_SCHED_IDLE;
- else if (!strncmp(value, CPU_SCHED_OTHER_VALUE_CONF,
- strlen(CPU_SCHED_OTHER_VALUE_CONF) +1))
- return CPU_SCHED_OTHER;
- else if (!strncmp(value, CPU_SCHED_BATCH_VALUE_CONF,
- strlen(CPU_SCHED_BATCH_VALUE_CONF) +1))
- return CPU_SCHED_BATCH;
- else if (!strncmp(value, CPU_SCHED_FIFO_VALUE_CONF,
- strlen(CPU_SCHED_FIFO_VALUE_CONF) +1))
- return CPU_SCHED_FIFO;
- else if (!strncmp(value, CPU_SCHED_RR_VALUE_CONF,
- strlen(CPU_SCHED_RR_VALUE_CONF) +1))
- return CPU_SCHED_RR;
- else if (!strncmp(value, CPU_SCHED_DEADLINE_VALUE_CONF,
- strlen(CPU_SCHED_DEADLINE_VALUE_CONF) +1))
- return CPU_SCHED_DEADLINE;
- else {
- _E("invalid parameter (%s)", value);
- return CPU_SCHED_NONE;
- }
-}
-
-static cpu_boosting_level_e config_parse_boosting_level(const char *value)
-{
- if (!strncmp(value, CPU_BOOSTING_LEVEL_STRONG_VALUE_CONF,
- strlen(CPU_BOOSTING_LEVEL_STRONG_VALUE_CONF) + 1))
- return CPU_BOOSTING_LEVEL_STRONG;
- else if (!strncmp(value, CPU_BOOSTING_LEVEL_MEDIUM_VALUE_CONF,
- strlen(CPU_BOOSTING_LEVEL_MEDIUM_VALUE_CONF) + 1))
- return CPU_BOOSTING_LEVEL_MEDIUM;
- else if (!strncmp(value, CPU_BOOSTING_LEVEL_WEAK_VALUE_CONF,
- strlen(CPU_BOOSTING_LEVEL_WEAK_VALUE_CONF) + 1))
- return CPU_BOOSTING_LEVEL_WEAK;
- else
- return CPU_BOOSTING_LEVEL_NONE;
-}
-
-static int optimizer_config(struct parse_result *result, void *user_data)
-{
- if (!result)
- return RESOURCED_ERROR_INVALID_PARAMETER;
-
- struct swap_conf *swap_conf = get_swap_conf();
- if (swap_conf == NULL) {
- _E("[CONFIG] memory swap configuration is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- struct dedup_conf *dedup_conf = get_dedup_conf();
- if (dedup_conf == NULL) {
- _E("[CONFIG] memory dedup configuration is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- struct compact_conf *compact_conf = get_compact_conf();
- if (compact_conf == NULL) {
- _E("[CONFIG] memory compact configuration is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- struct cpu_sched_conf *cpu_sched_conf = get_cpu_sched_conf();
- if (cpu_sched_conf == NULL) {
- _E("[CONFIG] cpu_sched configuration is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!strncmp(result->section, SWAP_SECTION, strlen(SWAP_SECTION)+1)) {
- if (!swap_conf->enable)
- swap_conf->enable = true;
-/* if (!strncmp(result->name, SWAP_ENABLE_NAME_CONF, strlen(SWAP_ENABLE_NAME_CONF)+1)) {
- swap_conf->enable = config_parse_bool(result->value);
- }*/
- if (!strncmp(result->name, RECLAIM_AT_BOOT_NAME_CONF,
- strlen(RECLAIM_AT_BOOT_NAME_CONF)+1)) {
- swap_conf->boot_reclaim_enable = config_parse_bool(result->value);
- }
- else if (!strncmp(result->name, SWAP_TYPE_NAME_CONF,
- strlen(SWAP_TYPE_NAME_CONF)+1)) {
- if (config_parse_swap_types(result->value, &swap_conf->swap_type) < 0) {
- _E("[CONFIG] Failed to parse type of swap, so use zram type");
- swap_conf->swap_type = SWAP_TYPE_ZRAM;
- }
- }
- else if (!strncmp(result->name, THROTTLING_SWAPPINESS_NAME_CONF,
- strlen(THROTTLING_SWAPPINESS_NAME_CONF)+1)) {
- swap_conf->swappiness[MEMCG_THROTTLING] = atoi(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, ZRAM_SECTION, strlen(ZRAM_SECTION)+1)) {
- if (!strncmp(result->name, COMP_ALGORITHM_NAME_CONF, strlen(COMP_ALGORITHM_NAME_CONF)+1)) {
- if (strlen(result->value) + 1 > sizeof(swap_conf->zram.algorithm)) {
- _E("Size of swap_conf->zram.algorithm is not enough");
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- strncpy(swap_conf->zram.algorithm, result->value,
- sizeof(swap_conf->zram.algorithm) - 1);
- }
- else if (!strncmp(result->name, ZRAM_RATIO_NAME_CONF, strlen(ZRAM_RATIO_NAME_CONF)+1)) {
- swap_conf->zram.ratio = atof(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, ZSWAP_SECTION, strlen(ZSWAP_SECTION)+1)) {
- if (!strncmp(result->name, POOL_RATIO_NAME_CONF, strlen(POOL_RATIO_NAME_CONF)+1)) {
- swap_conf->zswap.pool_ratio = atof(result->value);
- }
- else if (!strncmp(result->name, POOL_TYPE_NAME_CONF, strlen(POOL_TYPE_NAME_CONF)+1)) {
- if (strlen(result->value) + 1 > sizeof(swap_conf->zswap.pool_type)) {
- _E("Size of swap_conf->zswap.pool_type is not enough");
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- strncpy(swap_conf->zswap.pool_type, result->value,
- sizeof(swap_conf->zswap.pool_type) - 1);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, DEDUP_SECTION, strlen(DEDUP_SECTION)+1)) {
- if (!dedup_conf->enable)
- dedup_conf->enable = true;
-/* if (!strncmp(result->name, DEDUP_ENABLE_NAME_CONF, strlen(DEDUP_ENABLE_NAME_CONF)+1)) {
- dedup_conf->enable = config_parse_bool(result->value);
- }*/
- if (!strncmp(result->name, DEDUP_AT_BOOT_NAME_CONF, strlen(DEDUP_AT_BOOT_NAME_CONF)+1)) {
- dedup_conf->boot_dedup_enable = config_parse_bool(result->value);
- }
- else if (!strncmp(result->name, SCAN_ON_LOWMEM_NAME_CONF, strlen(SCAN_ON_LOWMEM_NAME_CONF)+1)) {
- dedup_conf->scan_on_lowmem = config_parse_bool(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, KSM_SECTION, strlen(KSM_SECTION)+1)) {
- if (!strncmp(result->name, KSM_MODE_NAME_CONF, strlen(KSM_MODE_NAME_CONF)+1)) {
- if (strlen(result->value) + 1 > sizeof(dedup_conf->ksm.mode)) {
- _E("Size of swap_conf->type is not enough");
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- strncpy(dedup_conf->ksm.mode, result->value,
- sizeof(dedup_conf->ksm.mode) - 1);
- }
- else if (!strncmp(result->name, PAGES_TO_SCAN_NAME_CONF, strlen(PAGES_TO_SCAN_NAME_CONF)+1)) {
- dedup_conf->ksm.pages = atoi(result->value);
- }
- else if (!strncmp(result->name, PAGES_TO_SCAN_WITH_BOOST_NAME_CONF,
- strlen(PAGES_TO_SCAN_WITH_BOOST_NAME_CONF)+1)) {
- dedup_conf->ksm.boost_pages = atoi(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, COMPACTION_SECTION, strlen(COMPACTION_SECTION)+1)) {
- if (!compact_conf->enable)
- compact_conf->enable = true;
-/* if (!strncmp(result->name, COMPACTION_ENABLE_NAME_CONF,
- strlen(COMPACTION_ENABLE_NAME_CONF)+1)) {
- compact_conf->enable = config_parse_bool(result->value);
- }*/
- if (!strncmp(result->name, FRAG_LEVEL_NAME_CONF, strlen(FRAG_LEVEL_NAME_CONF)+1)) {
- compact_conf->frag_level = atoi(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, CPU_SCHED_SECTION,
- strlen(CPU_SCHED_SECTION)+1)) {
- if (!strncmp(result->name, CPU_SCHED_FEATURE_NAME_CONF,
- strlen(CPU_SCHED_FEATURE_NAME_CONF) + 1)) {
- cpu_sched_conf->cpu_sched_flag = config_parse_cpu_sched_features(result->value);
- }
- else if (!strncmp(result->name, CPU_RT_RUN_TIME_NAME_CONF,
- strlen(CPU_RT_RUN_TIME_NAME_CONF) + 1)) {
- cpu_sched_conf->cpu_cgroup_info.rt_runtime_us = config_parse_ll_time_us(result->value);
- }
- else if (!strncmp(result->name, CPU_RT_PERIOD_NAME_CONF,
- strlen(CPU_RT_PERIOD_NAME_CONF) + 1)) {
- cpu_sched_conf->cpu_cgroup_info.rt_period_us = config_parse_ull_time_us(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, CPU_AFFINITY_SECTION,
- strlen(CPU_AFFINITY_SECTION)+1)) {
- int error = RESOURCED_ERROR_NONE;
-
- if (!strncmp(result->name, FOREGROUND_APPS_NAME_CONF,
- strlen(FOREGROUND_APPS_NAME_CONF) + 1)) {
- error = set_cpu_affinity_conf(result->name, result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
-
- return error;
- }
- else if (!strncmp(result->section, CPU_BOOSTING_LEVEL_STRONG_SECTION,
- strlen(CPU_BOOSTING_LEVEL_STRONG_SECTION)+1)) {
- struct cpu_boosting_conf *cpu_boosting_conf =
- get_cpu_boosting_conf(CPU_BOOSTING_LEVEL_STRONG);
- if (cpu_boosting_conf == NULL) {
- _E("[CONFIG] cpu_boosting configuration is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!cpu_boosting_conf->enable)
- cpu_boosting_conf->enable = true;
-
- if (!strncmp(result->name, CPU_SCHED_NAME_CONF,
- strlen(CPU_SCHED_NAME_CONF) + 1)) {
- cpu_boosting_conf->cpu_sched_info.cpu_sched_type =
- config_parse_sched_type(result->value);
- }
- else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
- strlen(CPU_NICE_NAME_CONF) + 1)) {
- cpu_boosting_conf->cpu_sched_info.cpu_nice =
- atoi(result->value);
- }
- else if (!strncmp(result->name, CPU_RT_PRIORITY_NAME_CONF,
- strlen(CPU_RT_PRIORITY_NAME_CONF) + 1)) {
- cpu_boosting_conf->cpu_sched_info.cpu_rt_priority =
- atoi(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, CPU_BOOSTING_LEVEL_MEDIUM_SECTION,
- strlen(CPU_BOOSTING_LEVEL_MEDIUM_SECTION)+1)) {
- struct cpu_boosting_conf *cpu_boosting_conf =
- get_cpu_boosting_conf(CPU_BOOSTING_LEVEL_MEDIUM);
- if (cpu_boosting_conf == NULL) {
- _E("[CONFIG] cpu_boosting configuration is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!cpu_boosting_conf->enable)
- cpu_boosting_conf->enable = true;
-
- if (!strncmp(result->name, CPU_SCHED_NAME_CONF,
- strlen(CPU_SCHED_NAME_CONF) + 1)) {
- cpu_boosting_conf->cpu_sched_info.cpu_sched_type =
- config_parse_sched_type(result->value);
- }
- else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
- strlen(CPU_NICE_NAME_CONF) + 1)) {
- cpu_boosting_conf->cpu_sched_info.cpu_nice =
- atoi(result->value);
- }
- else if (!strncmp(result->name, CPU_RT_PRIORITY_NAME_CONF,
- strlen(CPU_RT_PRIORITY_NAME_CONF) + 1)) {
- cpu_boosting_conf->cpu_sched_info.cpu_rt_priority =
- atoi(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, CPU_BOOSTING_LEVEL_WEAK_SECTION,
- strlen(CPU_BOOSTING_LEVEL_WEAK_SECTION)+1)) {
- struct cpu_boosting_conf *cpu_boosting_conf =
- get_cpu_boosting_conf(CPU_BOOSTING_LEVEL_WEAK);
- if (cpu_boosting_conf == NULL) {
- _E("[CONFIG] cpu_boosting configuration is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!cpu_boosting_conf->enable)
- cpu_boosting_conf->enable = true;
-
- if (!strncmp(result->name, CPU_SCHED_NAME_CONF,
- strlen(CPU_SCHED_NAME_CONF) + 1)) {
- cpu_boosting_conf->cpu_sched_info.cpu_sched_type =
- config_parse_sched_type(result->value);
- }
- else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
- strlen(CPU_NICE_NAME_CONF) + 1)) {
- cpu_boosting_conf->cpu_sched_info.cpu_nice =
- atoi(result->value);
- }
- else if (!strncmp(result->name, CPU_RT_PRIORITY_NAME_CONF,
- strlen(CPU_RT_PRIORITY_NAME_CONF) + 1)) {
- cpu_boosting_conf->cpu_sched_info.cpu_rt_priority =
- atoi(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else {
- _E("[CONFIG] Unknown section name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-
-static int limiter_config(struct parse_result *result, void *user_data)
-{
- if (!result)
- return RESOURCED_ERROR_INVALID_PARAMETER;
-
- struct memcg_conf *memcg_conf = get_memcg_conf();
- if (memcg_conf == NULL) {
- _E("[CONFIG] memory cgroup configuration is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- struct cpu_throttling_conf *cpu_throttling_conf = get_cpu_throttling_conf();
- if (cpu_throttling_conf == NULL) {
- _E("[CONFIG] cpu_throttling configuration is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!strncmp(result->section, MEMORY_THROTTLING_SECTION,
- strlen(MEMORY_THROTTLING_SECTION)+1)) {
- char *ptr = strchr(result->value, '%');
- if (ptr == NULL) {
- _E("[CONFIG] Cannot find '%%' in the string (%s)", result->value);
- return RESOURCED_ERROR_FAIL;
- }
- else
- *ptr = '\0';
-
- if (!strncmp(result->name, THROTTLING_LIMIT_NAME_CONF,
- strlen(THROTTLING_LIMIT_NAME_CONF) + 1)) {
- memcg_conf->cgroup_limit[MEMCG_THROTTLING] = atof(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else if (!strncmp(result->section, MEMORY_LEVEL_THRESHOLD_SECTION,
- strlen(MEMORY_LEVEL_THRESHOLD_SECTION)+1)) {
-
- if (!strncmp(result->name, OOM_POPUP_NAME_CONF,
- strlen(OOM_POPUP_NAME_CONF) + 1)) {
- memcg_conf->oom_popup = config_parse_bool(result->value);
- }
- else {
- char temp = '\0';
- int error = RESOURCED_ERROR_NONE;
- bool percent;
- char *ptr = strchr(result->value, '%');
- if (ptr == NULL) {
- ptr = strchr(result->value, 'B');
- if (ptr == NULL) {
- _E("[CONFIG] Cannot find 'B' in the string (%s)", result->value);
- return RESOURCED_ERROR_FAIL;
- }
-
- if (result->value > (ptr - 1)) {
- _E("[CONFIG] Size of string should be larger than 1");
- return RESOURCED_ERROR_FAIL;
- }
-
- temp = *(ptr - 1);
- *(ptr - 1) = '\0';
- percent = false;
- }
- else {
- *ptr = '\0';
- percent = true;
- }
-
- if (!strncmp(result->name, MEDIUM_LEVEL_NAME_CONF,
- strlen(MEDIUM_LEVEL_NAME_CONF) + 1)) {
- error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_MEDIUM, result->value);
- }
- else if (!strncmp(result->name, LOW_LEVEL_NAME_CONF,
- strlen(LOW_LEVEL_NAME_CONF) + 1)) {
- error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_LOW, result->value);
- }
- else if (!strncmp(result->name, CRITICAL_LEVEL_NAME_CONF,
- strlen(CRITICAL_LEVEL_NAME_CONF) + 1)) {
- error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_CRITICAL, result->value);
- }
- else if (!strncmp(result->name, OOM_LEVEL_NAME_CONF,
- strlen(OOM_LEVEL_NAME_CONF) + 1)) {
- error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_OOM, result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
-
- return error;
- }
- }
- else if (!strncmp(result->section, MEMORY_APP_TYPE_LIMIT_SECTION,
- strlen(MEMORY_APP_TYPE_LIMIT_SECTION)+1)) {
- int error = RESOURCED_ERROR_NONE;
-
- if (!strncmp(result->name, SERVICE_PER_APP_LIMIT_ACTION_NAME_CONF,
- strlen(SERVICE_PER_APP_LIMIT_ACTION_NAME_CONF) + 1)) {
- error = set_mem_action_conf(&memcg_conf->service, result->value);
- }
- else if (!strncmp(result->name, WIDGET_PER_APP_LIMIT_ACTION_NAME_CONF,
- strlen(WIDGET_PER_APP_LIMIT_ACTION_NAME_CONF) + 1)) {
- error = set_mem_action_conf(&memcg_conf->widget, result->value);
- }
- else if (!strncmp(result->name, GUI_PER_APP_LIMIT_ACTION_NAME_CONF,
- strlen(GUI_PER_APP_LIMIT_ACTION_NAME_CONF) + 1)) {
- error = set_mem_action_conf(&memcg_conf->guiapp, result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
-
- return error;
- }
- else if (!strncmp(result->section, MEMORY_APP_STATUS_LIMIT_SECTION,
- strlen(MEMORY_APP_STATUS_LIMIT_SECTION)+1)) {
- int error = RESOURCED_ERROR_NONE;
-
- if (!strncmp(result->name, BACKGROUND_PER_APP_LIMIT_ACTION_NAME_CONF,
- strlen(BACKGROUND_PER_APP_LIMIT_ACTION_NAME_CONF) + 1)) {
- error = set_mem_action_conf(&memcg_conf->background, result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
-
- return error;
- }
- else if (!strncmp(result->section, CPU_THROTTLING_SECTION,
- strlen(CPU_THROTTLING_SECTION)+1)) {
- if (!cpu_throttling_conf->enable)
- cpu_throttling_conf->enable = true;
-
- if (!strncmp(result->name, CPU_SCHED_NAME_CONF,
- strlen(CPU_SCHED_NAME_CONF)+1)) {
- cpu_throttling_conf->cpu_sched_info.cpu_sched_type =
- config_parse_sched_type(result->value);
- }
- else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
- strlen(CPU_NICE_NAME_CONF)+1)) {
- cpu_throttling_conf->cpu_sched_info.cpu_nice =
- atoi(result->value);
- }
- else if (!strncmp(result->name, CPU_SHARE_NAME_CONF,
- strlen(CPU_SHARE_NAME_CONF)+1)) {
- cpu_throttling_conf->cpu_cgroup_info.cpu_share =
- strtoull(result->value, NULL, 10);
- }
- else if (!strncmp(result->name, CPU_CFS_RUN_TIME_NAME_CONF,
- strlen(CPU_CFS_RUN_TIME_NAME_CONF)+1)) {
- cpu_throttling_conf->cpu_cgroup_info.cfs_runtime_us =
- config_parse_ll_time_us(result->value);
- }
- else if (!strncmp(result->name, CPU_CFS_PERIOD_NAME_CONF,
- strlen(CPU_CFS_PERIOD_NAME_CONF)+1)) {
- cpu_throttling_conf->cpu_cgroup_info.cfs_period_us =
- config_parse_ull_time_us(result->value);
- }
- else {
- _E("[CONFIG] Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
- }
- else {
- _E("[CONFIG] Unknown section name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int vendor_config(struct parse_result *result, void *user_data)
-{
- int *config_type = (int *)user_data;
- static struct proc_conf_info *pci = NULL;
-
- if (!result || !user_data)
- return RESOURCED_ERROR_INVALID_PARAMETER;
-
- if (strncmp(result->section, PRIVATE_SECTION, strlen(PRIVATE_SECTION)+1)) {
- if (strncmp(result->section, OLD_VIP_GROUP_SECTION, strlen(OLD_VIP_GROUP_SECTION)+1)) {
- return RESOURCED_ERROR_NONE;
- }
- }
-
- /* common(App or Service or Process) */
- if (!strncmp(result->name, APP_NAME_CONF, strlen(APP_NAME_CONF)+1) ||
- !strncmp(result->name, SERVICE_NAME_CONF, strlen(SERVICE_NAME_CONF)+1) ||
- !strncmp(result->name, OLD_SERVICE_NAME_CONF, strlen(OLD_SERVICE_NAME_CONF)+1) ||
- !strncmp(result->name, PROCESS_NAME_CONF, strlen(PROCESS_NAME_CONF)+1) ||
- !strncmp(result->name, OLD_PROCESS_NAME_CONF, strlen(OLD_PROCESS_NAME_CONF)+1)) {
- pci = fixed_app_and_service_exist_check(result->value,
- result->name[0] == 'A' ? APP_TYPE :
- result->name[0] == 'S' ? SERVICE_TYPE : PROCESS_TYPE);
- if (pci == NULL) {
- pci = (struct proc_conf_info *)calloc(1, sizeof(struct proc_conf_info));
- if (pci == NULL) {
- _E("Failed to allocate memory during parsing vendor configurations");
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- pci->cpu_sched_info.cpu_sched_type = CPU_SCHED_NONE;
- pci->cpu_sched_info.cpu_rt_priority = CPU_INIT_PRIO;
- pci->cpu_sched_info.cpu_nice = CPU_INIT_NICE;
- pci->watchdog_action = PROC_ACTION_KILL;
- pci->fail_action = PROC_ACTION_IGNORE;
- pci->cpu_boosting_level = CPU_BOOSTING_LEVEL_NONE;
- strncpy(pci->name, result->value, sizeof(pci->name)-1);
-
- if (result->name[0] == 'A')
- fixed_app_list_insert(pci);
- else if (result->name[0] == 'S')
- fixed_service_list_insert(pci);
- else
- fixed_process_list_insert(pci);
- }
- }
- /* limiter.conf.d */
-/* else if (!strncmp(result->name, MEM_CGROUP_NAME_CONF, strlen(MEM_CGROUP_NAME_CONF)+1) &&
- *config_type == LIMITER_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!strncmp(result->value, CGROUP_HIGH_VALUE_CONF,
- strlen(CGROUP_HIGH_VALUE_CONF) +1)) {
- pci->mem_type = MEMCG_HIGH;
- }
- else if (!strncmp(result->value, CGROUP_MEDIUM_VALUE_CONF,
- strlen(CGROUP_MEDIUM_VALUE_CONF) +1)) {
- pci->mem_type = MEMCG_MEDIUM;
- }
- else if (!strncmp(result->value, CGROUP_LOW_VALUE_CONF,
- strlen(CGROUP_LOW_VALUE_CONF) +1)) {
- pci->mem_type = MEMCG_LOW;
- }
- else {
- _E("invalid parameter (%s)", result->value);
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
- }*/
- else if (!strncmp(result->name, MEM_LIMIT_ACTION_NAME_CONF,
- strlen(MEM_LIMIT_ACTION_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) {
- int error;
-
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- error = set_mem_action_conf(&pci->mem_action, result->value);
- return error;
- }
- else if (!strncmp(result->name, MEMORY_THROTTLING_NAME_CONF,
- strlen(MEMORY_THROTTLING_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) {
-
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- /* Enable throttling of a service */
- pci->memory_throttling_enable = config_parse_bool(result->value);
- }
- else if (!strncmp(result->name, CPU_THROTTLING_NAME_CONF,
- strlen(CPU_THROTTLING_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) {
-
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- /* Enable throttling of an app (or a service) */
- pci->cpu_throttling_enable = config_parse_bool(result->value);
- }
- /* optimizer.conf.d */
- else if (!strncmp(result->name, CPU_SCHED_NAME_CONF, strlen(CPU_SCHED_NAME_CONF)+1) &&
- *config_type == OPTIMIZER_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- pci->cpu_sched_info.cpu_sched_type = config_parse_sched_type(result->value);
-
- }
- else if (!strncmp(result->name, CPU_NICE_NAME_CONF,
- strlen(CPU_NICE_NAME_CONF)+1) && *config_type == OPTIMIZER_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- pci->cpu_sched_info.cpu_nice = atoi(result->value);
- }
- else if (!strncmp(result->name, CPU_RT_PRIORITY_NAME_CONF,
- strlen(CPU_RT_PRIORITY_NAME_CONF)+1) && *config_type == OPTIMIZER_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- pci->cpu_sched_info.cpu_rt_priority = atoi(result->value);
- }
- else if (!strncmp(result->name, CPU_BOOSTING_LEVEL_NAME_CONF,
- strlen(CPU_BOOSTING_LEVEL_NAME_CONF)+1) && *config_type == OPTIMIZER_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- pci->cpu_boosting_level = config_parse_boosting_level(result->value);
- }
-/* else if (!strncmp(result->name, CPU_RT_RUN_TIME_NAME_CONF,
- strlen(CPU_RT_RUN_TIME_NAME_CONF)+1) &&
- *config_type == OPTIMIZER_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
- pci->cpu_sched_info.rt_runtime_us = config_parse_time_us(result->value);
- }
- else if (!strncmp(result->name, CPU_RT_PERIOD_NAME_CONF,
- strlen(CPU_RT_PERIOD_NAME_CONF)+1) &&
- *config_type == OPTIMIZER_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
- pci->cpu_sched_info.rt_period_us = config_parse_time_us(result->value);
- }*/
- else if (!strncmp(result->name, ACTION_ON_FAILURE_NAME_CONF,
- strlen(ACTION_ON_FAILURE_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!strncmp(result->value, ACTION_REBOOT_VALUE_CONF,
- strlen(ACTION_REBOOT_VALUE_CONF) +1)) {
- pci->fail_action = PROC_ACTION_REBOOT;
- }
- else {
- _E("invalid parameter (%s)", result->value);
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
- }
- else if (!strncmp(result->name, WATCHDOG_ACTION_NAME_CONF,
- strlen(WATCHDOG_ACTION_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!strncmp(result->value, ACTION_IGNORE_VALUE_CONF,
- strlen(ACTION_IGNORE_VALUE_CONF) +1)) {
- pci->watchdog_action = PROC_ACTION_IGNORE;
- }
- else if (!strncmp(result->value, ACTION_KILL_VALUE_CONF,
- strlen(ACTION_KILL_VALUE_CONF) +1)) {
- pci->watchdog_action = PROC_ACTION_KILL;
- }
- else {
- _E("invalid parameter (%s)", result->value);
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
- }
- /* old style */
- else if (!strncmp(result->name, OLD_ACTION_ON_FAILURE_NAME_CONF,
- strlen(OLD_ACTION_ON_FAILURE_NAME_CONF)+1) && *config_type == VIP_CONFIG) {
- if (!pci) {
- _E("process configuration information pointer should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!strncmp(result->value, ACTION_REBOOT_VALUE_CONF,
- strlen(ACTION_REBOOT_VALUE_CONF) +1)) {
- pci->fail_action = PROC_ACTION_REBOOT;
- }
- else {
- _E("invalid parameter (%s)", result->value);
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
- }
- else {
- _E("Unknown configuration name (%s) and value (%s) on section (%s)",
- result->name, result->value, result->section);
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-static void load_per_vendor_configs(const char *dir, int func(struct parse_result *result,
- void *user_data), void *user_data)
-{
- int count;
- int idx;
- struct dirent **namelist;
-
- if ((count = scandir(dir, &namelist, NULL, alphasort)) == -1) {
- _I("(%s) conf dir does not exist", dir);
- return;
- }
-
- for (idx = 0; idx < count; idx++) {
- char path[PATH_MAX] = {0, };
-
- if (!strstr(namelist[idx]->d_name, CONF_FILE_SUFFIX))
- continue;
-
- snprintf(path, sizeof(path), "%s/%s", dir, namelist[idx]->d_name);
- config_parse(path, func, user_data);
- free(namelist[idx]);
- }
-
- free(namelist);
-}
-
-void resourced_parse_vendor_configs(void)
-{
- int config_type;
-
- fixed_app_and_service_list_init();
-
- /* Load configurations in limiter.conf and limiter.conf.d/ */
- config_parse(LIMITER_CONF_FILE, limiter_config, NULL);
- config_type = LIMITER_CONFIG;
- load_per_vendor_configs(LIMITER_CONF_DIR, vendor_config, &config_type);
-
- /* Load configurations in optimizer.conf and optimizer.conf.d */
- config_parse(OPTIMIZER_CONF_FILE, optimizer_config, NULL);
- config_type = OPTIMIZER_CONFIG;
- load_per_vendor_configs(OPTIMIZER_CONF_DIR, vendor_config, &config_type);
-
- /* Load configuration in process.conf */
- config_type = PROCESS_CONFIG;
- load_per_vendor_configs(PROC_CONF_DIR, vendor_config, &config_type);
-
- /* old style */
- config_type = VIP_CONFIG;
- load_per_vendor_configs(VIP_CONF_DIR, vendor_config, &config_type);
-}
-
-void resourced_free_vendor_configs(void)
-{
- fixed_app_and_service_list_exit();
-}
-
-int config_parse(const char *file_name, int cb(struct parse_result *result,
- void *user_data), void *user_data)
-{
- FILE *f = NULL;
- struct parse_result result;
- /* use stack for parsing */
- char line[LINE_MAX];
- char section[MAX_SECTION];
- char *start, *end, *name, *value;
- int lineno = 0, ret = 0;
-
- if (!file_name || !cb) {
- ret = -EINVAL;
- goto error;
- }
-
- /* open conf file */
- f = fopen(file_name, "r");
- if (!f) {
- _E("Failed to open file %s", file_name);
- ret = -EIO;
- goto error;
- }
-
- /* parsing line by line */
- while (fgets(line, LINE_MAX, f) != NULL) {
- lineno++;
-
- start = line;
- truncate_nl(start);
- start = strstrip(start);
-
- if (*start == COMMENT) {
- continue;
- } else if (*start == '[') {
- /* parse section */
- end = strchr(start, ']');
- if (!end || *end != ']') {
- ret = -EBADMSG;
- goto error;
- }
-
- *end = '\0';
- strncpy(section, start + 1, sizeof(section)-1);
- section[MAX_SECTION-1] = '\0';
- } else if (*start) {
- /* parse name & value */
- end = strchr(start, '=');
- if (!end || *end != '=') {
- ret = -EBADMSG;
- goto error;
- }
- *end = '\0';
- name = strstrip(start);
- value = strstrip(end + 1);
- end = strchr(value, COMMENT);
- if (end && *end == COMMENT) {
- *end = '\0';
- value = strstrip(value);
- }
-
- result.section = section;
- result.name = name;
- result.value = value;
- /* callback with parse result */
- ret = cb(&result, user_data);
- if (ret < 0) {
- ret = -EBADMSG;
- goto error;
- }
- }
- }
- _D("Success to load %s", file_name);
- fclose(f);
- return 0;
-
-error:
- if (f)
- fclose(f);
- _E("Failed to read %s:%d!", file_name, lineno);
- return ret;
-}
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2013 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 __CONFIG_PARSER_H__
-#define __CONFIG_PARSER_H__
-
-#include <stdio.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-
-#define CONF_FILE_SUFFIX ".conf"
-
-#define LIMITER_CONF_FILE RD_CONFIG_FILE(limiter)
-#define OPTIMIZER_CONF_FILE RD_CONFIG_FILE(optimizer)
-#define LIMITER_CONF_DIR RD_CONFIG_PATH"/limiter.conf.d"
-#define OPTIMIZER_CONF_DIR RD_CONFIG_PATH"/optimizer.conf.d"
-#define PROC_CONF_DIR RD_CONFIG_PATH"/process.conf.d"
-/* old style */
-#define VIP_CONF_DIR RD_CONFIG_PATH"/vip-process.d"
-
-/* section name */
-/* limiter.conf */
-#define PRIVATE_SECTION "Private"
-#define MEMORY_LEVEL_THRESHOLD_SECTION "MemoryLevelThreshold"
-#define MEMORY_APP_TYPE_LIMIT_SECTION "MemoryAppTypeLimit"
-#define MEMORY_APP_STATUS_LIMIT_SECTION "MemoryAppStatusLimit"
-#define MEMORY_THROTTLING_SECTION "MemoryThrottling"
-#define CPU_THROTTLING_SECTION "CpuThrottling"
-#define OLD_VIP_GROUP_SECTION "VIP_GROUP"
-
-/* optimizer.conf */
-#define SWAP_SECTION "MemorySwap"
-#define ZRAM_SECTION "MemoryZram"
-#define ZSWAP_SECTION "MemoryZswap"
-#define DEDUP_SECTION "MemoryDedup"
-#define KSM_SECTION "MemoryKsm"
-#define COMPACTION_SECTION "MemoryCompaction"
-#define CPU_SCHED_SECTION "CpuSched"
-#define CPU_AFFINITY_SECTION "CpuAffinity"
-#define CPU_BOOSTING_LEVEL_STRONG_SECTION "CpuBoostingLevelStrong"
-#define CPU_BOOSTING_LEVEL_MEDIUM_SECTION "CpuBoostingLevelMedium"
-#define CPU_BOOSTING_LEVEL_WEAK_SECTION "CpuBoostingLevelWeak"
-
-/* configuration name */
-/* limiter.conf */
-#define APP_NAME_CONF "App"
-#define SERVICE_NAME_CONF "Service"
-#define OLD_SERVICE_NAME_CONF "SERVICE" /* old style */
-#define PROCESS_NAME_CONF "Process"
-#define OLD_PROCESS_NAME_CONF "PROCESS" /* old style */
-#define MEM_CGROUP_NAME_CONF "MemGroup"
-#define MEM_LIMIT_ACTION_NAME_CONF "MemLimitAction"
-#define ACTION_ON_FAILURE_NAME_CONF "ActionOnFailure"
-#define OLD_ACTION_ON_FAILURE_NAME_CONF "ACTION_ON_FAILURE"
-#define WATCHDOG_ACTION_NAME_CONF "WatchdogAction"
-#define THROTTLING_LIMIT_NAME_CONF "ThrottlingLimit"
-#define MEDIUM_LEVEL_NAME_CONF "MediumLevel"
-#define LOW_LEVEL_NAME_CONF "LowLevel"
-#define CRITICAL_LEVEL_NAME_CONF "CriticalLevel"
-#define OOM_LEVEL_NAME_CONF "OomLevel"
-#define OOM_POPUP_NAME_CONF "OomPopup"
-#define SERVICE_PER_APP_LIMIT_ACTION_NAME_CONF "ServicePerAppLimitAction"
-#define WIDGET_PER_APP_LIMIT_ACTION_NAME_CONF "WidgetPerAppLimitAction"
-#define GUI_PER_APP_LIMIT_ACTION_NAME_CONF "GUIPerAppLimitAction"
-#define BACKGROUND_PER_APP_LIMIT_ACTION_NAME_CONF "BackgroundPerAppLimitAction"
-
-/* CPU specific configuration name */
-#define CPU_SCHED_NAME_CONF "CpuSched"
-#define CPU_NICE_NAME_CONF "CpuNice"
-#define CPU_SHARE_NAME_CONF "CpuShare"
-#define CPU_RT_PRIORITY_NAME_CONF "CpuRTPriority"
-#define CPU_SCHED_FEATURE_NAME_CONF "CpuSchedFeature"
-#define CPU_RT_RUN_TIME_NAME_CONF "CpuRTRuntime"
-#define CPU_RT_PERIOD_NAME_CONF "CpuRTPeriod"
-#define CPU_CFS_RUN_TIME_NAME_CONF "CpuCFSRuntime"
-#define CPU_CFS_PERIOD_NAME_CONF "CpuCFSPeriod"
-#define CPU_BOOSTING_LEVEL_NAME_CONF "CpuBoostingLevel"
-#define MEMORY_THROTTLING_NAME_CONF "MemoryThrottling"
-#define CPU_THROTTLING_NAME_CONF "CpuThrottling"
-
-/* optimizer.conf */
-#define SWAP_ENABLE_NAME_CONF "SwapEnable"
-#define RECLAIM_AT_BOOT_NAME_CONF "ReclaimAtBoot"
-#define SWAP_TYPE_NAME_CONF "SwapType"
-#define THROTTLING_SWAPPINESS_NAME_CONF "ThrottlingSwappiness"
-#define COMP_ALGORITHM_NAME_CONF "CompAlgorithm"
-#define ZRAM_RATIO_NAME_CONF "ZramRatio"
-#define POOL_RATIO_NAME_CONF "PoolRatio"
-#define POOL_TYPE_NAME_CONF "PoolType"
-#define DEDUP_ENABLE_NAME_CONF "DedupEnable"
-#define DEDUP_AT_BOOT_NAME_CONF "DedupAtBoot"
-#define SCAN_ON_LOWMEM_NAME_CONF "ScanOnLowmem"
-#define KSM_MODE_NAME_CONF "KsmMode"
-#define PAGES_TO_SCAN_NAME_CONF "PagesToScan"
-#define PAGES_TO_SCAN_WITH_BOOST_NAME_CONF "PagesToScanWithBoost"
-#define COMPACTION_ENABLE_NAME_CONF "CompactionEnable"
-#define FRAG_LEVEL_NAME_CONF "FragLevel"
-#define FOREGROUND_APPS_NAME_CONF "ForegroundApps"
-
-/* configuration value */
-#define CGROUP_LOW_VALUE_CONF "lowest"
-#define ACTION_BROADCAST_VALUE_CONF "broadcast"
-#define ACTION_RECLAIM_VALUE_CONF "reclaim"
-#define ACTION_KILL_VALUE_CONF "kill"
-#define ACTION_REBOOT_VALUE_CONF "reboot"
-#define ACTION_IGNORE_VALUE_CONF "ignore"
-
-/* CPU specific configuration name */
-#define RT_RUNTIME_SHARE_VALUE_CONF "rt_runtime_share"
-#define NO_RT_RUNTIME_SHARE_VALUE_CONF "no_rt_runtime_share"
-#define CPU_SCHED_DEADLINE_VALUE_CONF "deadline"
-#define CPU_SCHED_FIFO_VALUE_CONF "fifo"
-#define CPU_SCHED_RR_VALUE_CONF "rr"
-#define CPU_SCHED_OTHER_VALUE_CONF "other"
-#define CPU_SCHED_IDLE_VALUE_CONF "idle"
-#define CPU_SCHED_BATCH_VALUE_CONF "batch"
-#define CPU_BOOSTING_LEVEL_STRONG_VALUE_CONF "strong"
-#define CPU_BOOSTING_LEVEL_MEDIUM_VALUE_CONF "medium"
-#define CPU_BOOSTING_LEVEL_WEAK_VALUE_CONF "weak"
-
-#define MATCH(a, b) (!strncmp(a, b, strlen(a) + 1) ? 1 : 0)
-#define SET_CONF(a, b) (a = (b > 0.0 ? b : a))
-
-enum config_type {
- LIMITER_CONFIG,
- OPTIMIZER_CONFIG,
- MONITOR_CONFIG,
- PROCESS_CONFIG,
- VIP_CONFIG, /* old style */
-};
-
-struct parse_result {
- char *section;
- char *name;
- char *value;
-};
-
-/**
- * @brief Parse config file and call callback\n
- * @param[in] file_name conf file.
- * @param[in] cb cb is called when conf file is parsed line by line.
- * @param[in] user_data user data is passed to cb.
- * @return 0 on success, negative if failed
- */
-int config_parse(const char *file_name, int cb(struct parse_result *result,
- void *user_data), void *user_data);
-
-/* Prototype for a parser for a specific configuration setting */
-typedef int (*ConfigParserCallback)(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data);
-
-typedef int (*ConfigParseFunc)(const char *path, void *data);
-
-/* Wraps information for parsing a specific configuration variable, to
- * be stored in a simple array */
-typedef struct ConfigTableItem {
- const char *section; /* Section */
- const char *lvalue; /* Name of the variable */
- ConfigParserCallback cb; /* Function that is called to
- * parse the variable's
- * value */
- int ltype; /* Distinguish different
- * variables passed to the
- * same callback */
- void *data; /* Where to store the
- * variable's data */
-} ConfigTableItem;
-
-void remove_app_conf_info_list(void);
-void remove_service_conf_info_list(void);
-GSList *get_app_conf_info_list(void);
-GSList *get_service_conf_info_list(void);
-void resourced_parse_vendor_configs(void);
-void resourced_free_vendor_configs(void);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif
+++ /dev/null
-#ifndef _CONFIG_H_GENERATED
-#define _CONFIG_H_GENERATED
-
-#cmakedefine EXCLUDE_LIST_RO_PATH "@EXCLUDE_LIST_RO_PATH@"
-#cmakedefine EXCLUDE_LIST_RW_PATH "@EXCLUDE_LIST_RW_PATH@"
-/* It's command line arguments*/
-
-#cmakedefine CONFIG_DATAUSAGE_NFACCT @CONFIG_DATAUSAGE_NFACCT@
-#cmakedefine TETHERING_FEATURE @TETHERING_FEATURE@
-
-#endif /* _CONFIG_H_GENERATED*/
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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 "macro.h"
-#include "cpu-common.h"
-#include "trace.h"
-#include "resourced.h"
-
-static struct cpu_sched_conf *cpu_sched_conf = NULL;
-static struct cpu_affinity_conf *cpu_affinity_conf = NULL;
-static struct cpu_throttling_conf *cpu_throttling_conf = NULL;
-static struct cpu_boosting_conf *cpu_boosting_conf[CPU_BOOSTING_LEVEL_END] = {NULL, };
-
-struct cpu_sched_conf *get_cpu_sched_conf(void)
-{
- if (!cpu_sched_conf) {
- cpu_sched_conf = (struct cpu_sched_conf *)calloc(1, sizeof (struct cpu_sched_conf));
- if (!cpu_sched_conf) {
- _E("Failed to alloc memory for cpu scheduler configuration");
- return NULL;
- }
- else {
- cpu_sched_conf->cpu_sched_flag = CPU_SCHED_UNINITIALIZED;
- cpu_sched_conf->cpu_cgroup_info.rt_runtime_us = 0;
- cpu_sched_conf->cpu_cgroup_info.rt_period_us = 0;
- }
- }
-
- return cpu_sched_conf;
-}
-
-void free_cpu_sched_conf(void)
-{
- if (cpu_sched_conf)
- free(cpu_sched_conf);
-}
-
-char *get_cpu_affinity_conf_name(void)
-{
- if (cpu_affinity_conf)
- return cpu_affinity_conf->cpuset_cgroup_info.name;
- else
- return NULL;
-}
-
-char *get_cpu_affinity_conf_value(void)
-{
- if (cpu_affinity_conf)
- return cpu_affinity_conf->cpuset_cgroup_info.value;
- else
- return NULL;
-}
-
-int set_cpu_affinity_conf(const char *name, const char *value)
-{
- if (!cpu_affinity_conf) {
- cpu_affinity_conf = (struct cpu_affinity_conf *)calloc(1, sizeof (struct cpu_affinity_conf));
- if (!cpu_affinity_conf) {
- _E("Failed to alloc memory for cpu affinity configuration");
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- }
-
- if (strlen(name) + 1 > sizeof(cpu_affinity_conf->cpuset_cgroup_info.name)) {
- _E("Size of cpu configuration for name is not enough");
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- strncpy(cpu_affinity_conf->cpuset_cgroup_info.name, name, sizeof(cpu_affinity_conf->cpuset_cgroup_info.name) - 1);
-
- if (strlen(value) + 1 > sizeof(cpu_affinity_conf->cpuset_cgroup_info.value)) {
- _E("Size of cpu configuration for value is not enough");
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- strncpy(cpu_affinity_conf->cpuset_cgroup_info.value, value, sizeof(cpu_affinity_conf->cpuset_cgroup_info.value) - 1);
-
- return RESOURCED_ERROR_NONE;
-}
-
-void free_cpu_affinity_conf(void)
-{
- if (cpu_affinity_conf)
- free(cpu_affinity_conf);
-}
-
-struct cpu_throttling_conf *get_cpu_throttling_conf(void)
-{
- if (!cpu_throttling_conf) {
- cpu_throttling_conf = (struct cpu_throttling_conf *)calloc(1, sizeof (struct cpu_throttling_conf));
- if (!cpu_throttling_conf) {
- _E("Failed to alloc memory for cpu throttling configuration");
- return NULL;
- }
- else {
- cpu_throttling_conf->enable = false;
- cpu_throttling_conf->cpu_sched_info.cpu_sched_type = CPU_SCHED_NONE;
- cpu_throttling_conf->cpu_sched_info.cpu_nice = CPU_INIT_NICE;
- cpu_throttling_conf->cpu_cgroup_info.cfs_runtime_us = 0;
- cpu_throttling_conf->cpu_cgroup_info.cfs_period_us = 0;
- cpu_throttling_conf->cpu_cgroup_info.cpu_share = 0;
- }
- }
-
- return cpu_throttling_conf;
-}
-
-void free_cpu_throttling_conf(void)
-{
- if (cpu_throttling_conf)
- free(cpu_throttling_conf);
-}
-
-struct cpu_boosting_conf *get_cpu_boosting_conf(cpu_boosting_level_e level)
-{
- if (!cpu_boosting_conf[level]) {
- cpu_boosting_conf[level] = (struct cpu_boosting_conf *)
- calloc(1, sizeof (struct cpu_boosting_conf));
-
- if (!cpu_boosting_conf[level]) {
- _E("Failed to alloc memory for cpu boosting (level = %d) configuration", level);
- return NULL;
- }
- else {
- cpu_boosting_conf[level]->enable = false;
- cpu_boosting_conf[level]->cpu_sched_info.cpu_sched_type = CPU_SCHED_NONE;
- cpu_boosting_conf[level]->cpu_sched_info.cpu_nice = CPU_INIT_NICE;
- cpu_boosting_conf[level]->cpu_sched_info.cpu_rt_priority = CPU_INIT_PRIO;
- }
- }
-
- return cpu_boosting_conf[level];
-}
-
-void free_cpu_boosting_conf(cpu_boosting_level_e level)
-{
- if (cpu_boosting_conf[level])
- free(cpu_boosting_conf[level]);
-}
+++ /dev/null
-#ifndef __CPU_COMMON_H__
-#define __CPU_COMMON_H__
-
-#include <stdbool.h>
-
-#include <cpu-boosting-type.h>
-#include <cpu-boosting-private.h>
-
-#include "util.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define CPU_INIT_NICE 100
-#define CPU_MAX_NICE 19
-#define CPU_MIN_NICE -20
-#define CPU_DEFAULT_NICE 0
-
-#define CPU_INIT_PRIO 0
-#define CPU_MAX_PRIO 99
-#define CPU_MIN_PRIO 1
-
-#define CPU_DEFAULT_SHARE 1024
-#define CPU_THROTTLING_SHARE 64
-
-enum cpu_sched_flag {
- CPU_SCHED_UNINITIALIZED = 0,
- CPU_SCHED_RUNTIME_SHARE = 1,
- CPU_SCHED_NO_RUNTIME_SHARE = 2,
- CPU_SCHED_RUNTIME_GREED = 4,
-};
-
-enum cpu_sched_type {
- CPU_SCHED_NONE = 0,
- CPU_SCHED_IDLE = 1,
- CPU_SCHED_BATCH,
- CPU_SCHED_OTHER,
- CPU_SCHED_FIFO,
- CPU_SCHED_RR,
- CPU_SCHED_DEADLINE,
-};
-
-struct cpu_boosting_info {
- pid_t tid;
- int level; /* current boosting level */
- guint gsource_id; /* timer id */
-};
-
-struct cpu_boosting_input {
- cpu_boosting_input_t client_input;
- int sock;
- guint *gsource_id;
- bool remove_input;
-};
-
-struct cpu_sched_info {
- enum cpu_sched_type cpu_sched_type;
- int cpu_nice; /* fixed cpu nice */
- int cpu_rt_priority; /* fixed cpu priority for rt schedulers */
-};
-
-struct cpuset_cgroup_info {
- char name[64];
- char value[64];
-};
-
-struct cpu_cgroup_info {
- long long cfs_runtime_us;
- long long rt_runtime_us;
- unsigned long long cfs_period_us;
- unsigned long long rt_period_us;
- unsigned long long cpu_share;
-};
-
-struct cpu_sched_conf {
- enum cpu_sched_flag cpu_sched_flag;
- struct cpu_cgroup_info cpu_cgroup_info;
-};
-
-struct cpu_affinity_conf {
- struct cpuset_cgroup_info cpuset_cgroup_info;
-};
-
-struct cpu_throttling_conf {
- bool enable;
- struct cpu_sched_info cpu_sched_info;
- struct cpu_cgroup_info cpu_cgroup_info;
-};
-
-struct cpu_boosting_conf {
- bool enable;
- struct cpu_sched_info cpu_sched_info;
-};
-
-struct cpu_sched_conf *get_cpu_sched_conf(void);
-void free_cpu_sched_conf(void);
-
-char *get_cpu_affinity_conf_name(void);
-char *get_cpu_affinity_conf_value(void);
-int set_cpu_affinity_conf(const char *name, const char *value);
-void free_cpu_affinity_conf(void);
-
-struct cpu_throttling_conf *get_cpu_throttling_conf(void);
-void free_cpu_throttling_conf(void);
-
-struct cpu_boosting_conf *get_cpu_boosting_conf(cpu_boosting_level_e level);
-void free_cpu_boosting_conf(cpu_boosting_level_e level);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __CPU_COMMON_H__ */
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/*
- * @file dbus-handler.c
- *
- * @desc dbus handler using libdbus
- *
- */
-
-#include <glib.h>
-#include <gio/gio.h>
-#include <stdint.h>
-
-#include "trace.h"
-#include "dbus-handler.h"
-#include "macro.h"
-#include "resourced.h"
-#include "util.h"
-#include "fd-handler.h"
-
-static guint owner_id;
-static GList *dbus_signal_list;
-static GList *dbus_method_handle_list;
-
-GDBusConnection *d_bus_get_connection(void)
-{
- static GDBusConnection *g_dbus_conn = NULL;
-
- if (g_dbus_conn)
- return g_dbus_conn;
-
- g_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
- g_assert(g_dbus_conn);
-
- g_dbus_connection_set_exit_on_close(g_dbus_conn, FALSE);
- return g_dbus_conn;
-}
-
-static struct d_bus_signal *d_bus_find_signal(const char *path, const char *interface, const char *name)
-{
- size_t path_len, interface_len, name_len;
- GList *iter;
- struct d_bus_signal *signal;
-
- path_len = strlen(path) + 1;
- interface_len = strlen(interface) + 1;
- name_len = strlen(name) + 1;
-
- for (iter = dbus_signal_list; iter; iter = g_list_next(iter)) {
- signal = (struct d_bus_signal *)iter->data;
- if (strncmp(signal->path, path, path_len))
- continue;
- if (strncmp(signal->interface, interface, interface_len))
- continue;
- if (strncmp(signal->name, name, name_len))
- continue;
- return signal;
- }
-
- return NULL;
-}
-
-/* Find appropriate method and call its callback */
-static void d_bus_method_handler(GDBusConnection *connection,
- const gchar *sender, const gchar *object_path,
- const gchar *interface_name, const gchar *method_name,
- GVariant *parameters, GDBusMethodInvocation *invocation,
- gpointer user_data)
-{
- int i;
- struct d_bus_method_handle *handle;
- int name_len;
-
- if (!user_data) {
- _E("There is no handle about received gdbus method");
- return;
- }
- handle = (struct d_bus_method_handle *)user_data;
-
- name_len = strlen(method_name) + 1;
- for (i = 0; i < handle->num_methods; i++) {
- if (strncmp(handle->methods[i].name, method_name, name_len))
- continue;
-
- handle->methods[i].callback(invocation, parameters);
- break;
- }
-}
-
-static const GDBusInterfaceVTable vtable = { d_bus_method_handler, NULL, NULL };
-
-static void d_bus_signal_handler(GDBusConnection *connection,
- const gchar *sender, const gchar *object_path,
- const gchar *interface_name, const gchar *signal_name,
- GVariant *parameters, gpointer user_data)
-{
- struct d_bus_signal *signal = (struct d_bus_signal *)user_data;
- if (!signal || !signal->callback)
- return;
-
- signal->callback(parameters);
-}
-
-struct dbus_int {
- int *list;
- int size;
-};
-
-static GVariant *append_variant(const char *sig, char *param[])
-{
- GVariantBuilder builder;
- GVariantBuilder *sub_builder;
- GVariant *var;
- struct dbus_int *array_int;
- char *ch;
- int i, j;
-
- if (!sig || !param)
- return NULL;
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
-
- for (ch = (char *)sig, i = 0; *ch != '\0'; ++i, ++ch) {
- switch (*ch) {
- case 'i':
- g_variant_builder_add(&builder, "i", atoi(param[i]));
- break;
- case 'u':
- g_variant_builder_add(&builder, "u", strtoul(param[i], NULL, 10));
- break;
- case 't':
- g_variant_builder_add(&builder, "t", atoll(param[i]));
- break;
- case 's':
- g_variant_builder_add(&builder, "s", param[i]);
- break;
- case 'a':
- ++ch;
- switch (*ch) {
- case 'i':
- sub_builder = g_variant_builder_new(G_VARIANT_TYPE("ai"));
- array_int = (struct dbus_int *)param[i];
- for (j = 0; j < array_int->size; j++)
- g_variant_builder_add(sub_builder, "i", array_int->list[j]);
- var = g_variant_new("ai", sub_builder);
- g_variant_builder_unref(sub_builder);
- g_variant_builder_add_value(&builder, var);
- break;
- default:
- break;
- }
- break;
- default:
- return NULL;
- }
- }
-
- return g_variant_builder_end(&builder);
-}
-
-int d_bus_call_method_sync(const char *dest, const char *path,
- const char *interface, const char *method,
- const char *sig, char *param[])
-{
- GVariant *gv = NULL;
-
- if (sig || param) {
- gv = append_variant(sig, param);
- if (!gv) {
- _E("Failed to build g_variant");
- return -EINVAL;
- }
- }
-
- return d_bus_call_method_sync_gvariant(dest, path, interface, method, gv);
-}
-
-int d_bus_call_method_sync_gvariant(const char *dest, const char *path,
- const char *interface, const char *method,
- GVariant *gv)
-{
- int ret;
- GVariant *reply = NULL;
- GError *err = NULL;
-
- reply = g_dbus_connection_call_sync(d_bus_get_connection(), dest, path,
- interface, method, gv, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
- if (err || !reply) {
- /* The case where !err && !reply (i.e. reply type mismatch) can't currently happen
- * because we don't specify the desired reply type, but it's good to be future-proof */
- _E("Failed to call D-Bus name %s, objpath %s, iface %s, method %s: %s",
- dest, path, interface, method, err ? err->message : "reply signature mismatch");
- if (err)
- g_error_free(err);
- return -ECOMM;
- }
-
- do_expr_unless_g_variant_consume_typechecked(return -EINVAL, reply, "(i)", &ret);
-
- return ret;
-}
-
-int d_bus_call_method_sync_gvariant_with_reply(const char *dest, const char *path,
- const char *interface, const char *method,
- GVariant *gv, GVariant **out_reply)
-{
- GVariant *reply = NULL;
- GError *err = NULL;
-
- reply = g_dbus_connection_call_sync(d_bus_get_connection(), dest, path,
- interface, method, gv, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
- if (err || !reply) {
- /* The case where !err && !reply (i.e. reply type mismatch) can't currently happen
- * because we don't specify the desired reply type, but it's good to be future-proof */
- _E("Failed to call D-Bus name %s, objpath %s, iface %s, method %s: %s",
- dest, path, interface, method, err ? err->message : "reply signature mismatch");
- if (err)
- g_error_free(err);
- return -ECOMM;
- }
-
- *out_reply = reply;
-
- return 0;
-}
-
-int d_bus_call_method_async(const char *dest, const char *path,
- const char *interface, const char *method,
- const char *sig, char *param[])
-{
- GVariant *gv = append_variant(sig, param);
- if (!gv) {
- _E("Failed to build g_variant");
- return -EINVAL;
- }
- return d_bus_call_method_async_gvariant(dest, path, interface, method, gv);
-}
-
-int d_bus_call_method_async_gvariant(const char *dest, const char *path,
- const char *interface, const char *method, GVariant *gv)
-{
- g_dbus_connection_call(d_bus_get_connection(), dest, path, interface, method,
- gv, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
-
- return 0;
-}
-
-resourced_ret_c d_bus_register_signal(const char *path, const char *interface,
- const char *name, d_bus_signal_callback callback, void *user_data)
-{
- struct d_bus_signal *signal;
-
- if (d_bus_find_signal(path, interface, name)) {
- _E("Same D-Bus signal is already registered");
- return RESOURCED_ERROR_FAIL;
- }
-
- signal = calloc(1, sizeof(struct d_bus_signal));
- if (!signal) {
- _E("Not enough memory!");
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- signal->path = path;
- signal->interface = interface;
- signal->name = name;
- signal->callback = callback;
- signal->user_data = user_data;
-
- signal->subscription_id = g_dbus_connection_signal_subscribe(d_bus_get_connection(),
- NULL, interface, name, path, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
- d_bus_signal_handler, signal, NULL);
- if (!(signal->subscription_id)) {
- _E("Failed to subscribe signal %s", name);
- free(signal);
- return RESOURCED_ERROR_FAIL;
- }
-
- dbus_signal_list = g_list_append(dbus_signal_list, signal);
-
- return RESOURCED_ERROR_NONE;
-}
-
-int d_bus_broadcast_signal_gvariant(const char *path, const char *interface,
- const char *name, GVariant *gv)
-{
- int ret;
-
- ret = g_dbus_connection_emit_signal(d_bus_get_connection(),
- NULL, path, interface, name, gv, NULL);
- if (ret != TRUE) {
- _E("Failed to emit gdbus signal(%s:%s-%s)", path, interface, name);
- return -ECOMM;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-int d_bus_broadcast_signal(const char *path, const char *interface,
- const char *name, const char *sig, char *param[])
-{
- GVariant *gv = append_variant(sig, param);
- if (!gv) {
- _E("Failed to build g_variant");
- return -EINVAL;
- }
- return d_bus_broadcast_signal_gvariant(path, interface, name, gv);
-}
-
-resourced_ret_c d_bus_register_methods(const char *path, const char *xml,
- const struct d_bus_method *methods, const size_t num_methods)
-{
- struct d_bus_method_handle *handle = NULL;
- GError *err = NULL;
-
- if (!path || !xml || !methods) {
- _E("You must input path, introspection xml and method list");
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
-
- handle = (struct d_bus_method_handle *)calloc(1, sizeof(struct d_bus_method_handle));
- if (!handle) {
- _E("Not enough memory!");
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- handle->path = path;
- handle->methods = methods;
- handle->num_methods = num_methods;
-
- handle->node_info = g_dbus_node_info_new_for_xml(xml, &err);
- if (!handle->node_info) {
- _E("Failed to make node_info : %s", err->message);
- goto on_error;
- }
-
- handle->subscription_id = g_dbus_connection_register_object(d_bus_get_connection(),
- path, handle->node_info->interfaces[0], &vtable, (gpointer)handle, NULL, &err);
- if (!handle->subscription_id) {
- _E("Failed to register gdbus methods with path %s : %s", path, err->message);
- g_dbus_node_info_unref(handle->node_info);
- goto on_error;
- } else
- dbus_method_handle_list = g_list_append(dbus_method_handle_list, (gpointer)handle);
-
- return RESOURCED_ERROR_NONE;
-
-on_error:
- g_clear_error(&err);
- free(handle);
-
- return RESOURCED_ERROR_FAIL;
-}
-
-resourced_ret_c d_bus_register_signals(const struct d_bus_signal *signals, const size_t size)
-{
- int i;
- int ret;
-
- for (i = 0; i < size; i++) {
- if (!signals[i].path || !signals[i].interface || !signals[i].name || !signals[i].callback)
- continue;
-
- ret = d_bus_register_signal(
- signals[i].path,
- signals[i].interface,
- signals[i].name,
- signals[i].callback,
- signals[i].user_data);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Fail to add signal %s, %s!\n", signals[i].path, signals[i].name);
- return RESOURCED_ERROR_FAIL;
- }
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-resourced_ret_c d_bus_reply_message(GDBusMessage *msg)
-{
- GError *err = NULL;
-
- if (!g_dbus_connection_send_message(d_bus_get_connection(), msg,
- G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &err)) {
- _E("Fail to reply gdbus message");
- g_clear_error(&err);
- return RESOURCED_ERROR_FAIL;
- }
-
- g_clear_error(&err);
- return RESOURCED_ERROR_NONE;
-}
-
-void d_bus_init(void)
-{
- owner_id = g_bus_own_name_on_connection(d_bus_get_connection(), RESOURCED_BUS_NAME,
- G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL);
- if (owner_id == 0) {
- _E("Failed to get gdbus own name");
- }
-}
-
-void d_bus_exit(void)
-{
- GList *iter;
- struct d_bus_signal *signal;
- struct d_bus_method_handle *method_handle;
- GDBusConnection *conn = d_bus_get_connection();
-
- if (owner_id != 0)
- g_bus_unown_name(owner_id);
-
- /* Remove D-Bus signal list */
- for (iter = dbus_signal_list; iter; iter = g_list_next(iter)) {
- signal = (struct d_bus_signal *)iter->data;
- g_dbus_connection_signal_unsubscribe(conn, signal->subscription_id);
- dbus_signal_list = g_list_remove(dbus_signal_list, signal);
- free(signal);
- }
-
- /* Remove D-Bus method list */
- for (iter = dbus_method_handle_list; iter; iter = g_list_next(iter)) {
- method_handle = (struct d_bus_method_handle *)iter->data;
- g_dbus_connection_unregister_object(conn, method_handle->subscription_id);
- g_dbus_node_info_unref(method_handle->node_info);
- dbus_method_handle_list = g_list_remove(dbus_method_handle_list, method_handle);
- free(method_handle);
- }
-
- g_object_unref(conn);
-}
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2013 - 2019 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/**
- * @file dbus-handler.h
- * @desc dbus handler using libdbus
- **/
-
-#ifndef __DBUS_HANDLER_H__
-#define __DBUS_HANDLER_H__
-
-#include <dbus-names-local.h>
-#include <dbus-names-external.h>
-#include <gio/gio.h>
-#include <resourced.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-typedef void (*d_bus_method_callback)(GDBusMethodInvocation *invocation, GVariant *params);
-typedef void (*d_bus_signal_callback)(GVariant *params);
-
-struct d_bus_method {
- const char *name;
- d_bus_method_callback callback;
-};
-
-struct d_bus_method_handle {
- const char *path;
- const struct d_bus_method *methods;
- size_t num_methods;
- GDBusNodeInfo *node_info;
- guint subscription_id;
-};
-
-struct d_bus_signal {
- const char *path;
- const char *interface;
- const char *name;
- d_bus_signal_callback callback;
- void *user_data;
- guint subscription_id;
-};
-
-/*
- * If reply signature is existed, GDBus allows the return type
- * to declared type or error.
- *
- * However, before GDBus is applied, resourced returns NULL
- * when error is occurred.
- *
- * Therefore, for backward compatibility, we don't use the function
- * g_dbus_method_invocation_return_error and return NULL with sending new message
- *
- * cf) Process resource usage functions use return_error because
- * it is only for Runtime-info (we can control this package)
- */
-#define D_BUS_REPLY_EMPTY_TUPLE(ivc, signature) \
-{ \
- GDBusMessage *re = g_dbus_message_new_method_reply(g_dbus_method_invocation_get_message(ivc)); \
- d_bus_reply_message(re); \
- g_object_unref(re); \
- g_object_unref(ivc); \
-}
-
-#define D_BUS_REPLY_NULL(ivc, signature) \
-{ \
- g_dbus_method_invocation_return_value(ivc, g_variant_new(signature)); \
-}
-
-#define D_BUS_REPLY_ERR(ivc) \
-{ \
- g_dbus_method_invocation_return_error(ivc, \
- G_DBUS_ERROR, G_DBUS_ERROR_FAILED, \
- "%s failed", g_dbus_method_invocation_get_method_name(ivc)); \
-}
-
-GDBusConnection *d_bus_get_connection(void);
-
-int d_bus_call_method_sync_gvariant(const char *dest, const char *path,
- const char *interface, const char *method,
- GVariant *gv);
-
-int d_bus_call_method_sync(const char *dest, const char *path,
- const char *interface, const char *method,
- const char *sig, char *param[]);
-
-int d_bus_call_method_async_gvariant(const char *dest, const char *path,
- const char *interface, const char *method,
- GVariant *gv);
-
-int d_bus_call_method_sync_gvariant_with_reply(const char *dest, const char *path,
- const char *interface, const char *method,
- GVariant *gv, GVariant **out_reply);
-
-int d_bus_call_method_async(const char *dest, const char *path,
- const char *interface, const char *method,
- const char *sig, char *param[]);
-
-resourced_ret_c d_bus_register_signal(const char *path, const char *interface,
- const char *name, d_bus_signal_callback callback, void *user_data);
-
-int d_bus_broadcast_signal_gvariant(const char *path, const char *interface,
- const char *name, GVariant *gv);
-
-int d_bus_broadcast_signal(const char *path, const char *interface,
- const char *name, const char *sig, char *param[]);
-
-resourced_ret_c d_bus_register_methods(const char *path, const char *xml,
- const struct d_bus_method *methods, const size_t num_methods);
-
-resourced_ret_c d_bus_register_signals(const struct d_bus_signal *signals,
- const size_t size);
-
-resourced_ret_c d_bus_reply_message(GDBusMessage *msg);
-
-int launch_system_app_by_dbus(const char *dest, const char *path,
- const char *iface, const char *method, const char *arg_type, ...);
-
-void d_bus_init(void);
-void d_bus_exit(void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __DBUS_HANDLER_H__ */
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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 DBUS_NAMES_EXTERNAL_H_INCLUDE_GUARD
-#define DBUS_NAMES_EXTERNAL_H_INCLUDE_GUARD
-
-/*
- * System popup
- */
-#define SYSTEM_POPUP_BUS_NAME "org.tizen.system.popup"
-#define SYSTEM_POPUP_PATH_NAME "/Org/Tizen/System/Popup"
-
-#define SYSTEM_POPUP_PATH_SYSTEM SYSTEM_POPUP_PATH_NAME"/System"
-#define SYSTEM_POPUP_IFACE_SYSTEM SYSTEM_POPUP_BUS_NAME".System"
-
-/*
- * Deviced
- */
-/*#define DEVICED_BUS_NAME "org.tizen.system.deviced"
-#define DEVICED_OBJECT_PATH "/Org/Tizen/System/DeviceD"
-
-#define DEVICED_PATH_PROCESS DEVICED_OBJECT_PATH"/Process"
-#define DEVICED_INTERFACE_PROCESS DEVICED_BUS_NAME".Process"
-
-#define DEVICED_PATH_DISPLAY DEVICED_OBJECT_PATH"/Display"
-#define DEVICED_INTERFACE_DISPLAY DEVICED_BUS_NAME".display"
-
-#define DEVICED_PATH_BATTERY DEVICED_OBJECT_PATH"/Battery"
-#define DEVICED_INTERFACE_BATTERY DEVICED_BUS_NAME".Battery"
-
-#define DEVICED_PATH_POWEROFF DEVICED_OBJECT_PATH"/PowerOff"
-#define DEVICED_INTERFACE_POWEROFF DEVICED_BUS_NAME".PowerOff"
-
-#define DEVICED_PATH_TIME DEVICED_OBJECT_PATH"/Time"
-#define DEVICED_INTERFACE_TIME DEVICED_BUS_NAME".Time"*/
-
-
-#define SIGNAL_DEVICED_LCDON "LCDOn"
-#define SIGNAL_DEVICED_LCDOFF "LCDOff"
-#define SIGNAL_DEVICED_LCDONCOMPLETE "LCDOnCompleted"
-#define SIGNAL_DEVICED_POWEROFF_STATE "ChangeState"
-#define SIGNAL_DEVICED_SYSTEMTIME_CHANGED "SystemTimeChanged"
-#define SIGNAL_DEVICED_LOW_BATTERY "BatteryStatusLow"
-#define SIGNAL_DEVICED_SUSPEND "sleep"
-#define SIGNAL_DEVICED_WAKEUP "wakeup"
-
-/*
- * dump service
- */
-#define DUMP_SERVICE_BUS_NAME "org.tizen.system.dumpservice"
-#define DUMP_SERVICE_OBJECT_PATH "/Org/Tizen/System/DumpService"
-#define DUMP_SERVICE_INTERFACE_NAME DUMP_SERVICE_BUS_NAME
-
-#define SIGNAL_DUMP "Dump"
-#define SIGNAL_DUMP_START "Start"
-#define SIGNAL_DUMP_FINISH "Finish"
-
-/*
- * Crash
- */
-#define CRASH_BUS_NAME "org.tizen.system.crash"
-#define CRASH_OBJECT_PATH "/Org/Tizen/System/Crash"
-#define CRASH_INTERFACE_NAME CRASH_BUS_NAME
-#define CRASH_PATH_CRASH CRASH_OBJECT_PATH"/Crash"
-#define CRASH_INTERFACE_CRASH CRASH_INTERFACE_NAME".Crash"
-#define PROCESS_CRASHED "ProcessCrashed"
-
-/*
- * AMD
- */
-#define AUL_APPSTATUS_BUS_NAME "org.tizen.aul.AppStatus"
-#define AUL_APPSTATUS_OBJECT_PATH "/Org/Tizen/Aul/AppStatus"
-#define AUL_APPSTATUS_INTERFACE_NAME AUL_APPSTATUS_BUS_NAME
-
-#define AUL_SUSPEND_BUS_NAME "org.tizen.appfw.SuspendHint"
-#define AUL_SUSPEND_OBJECT_PATH "/Org/Tizen/Appfw/SuspendHint"
-#define AUL_SUSPEND_INTERFACE_NAME AUL_SUSPEND_BUS_NAME
-
-#define SIGNAL_AMD_LAUNCH "AppLaunch"
-#define SIGNAL_AMD_RESUME "AppResume"
-#define SIGNAL_AMD_TERMINATE "AppTerminate"
-#define SIGNAL_AMD_STATE "AppStatusChange"
-#define SIGNAL_AMD_GROUP "AppGroup"
-#define SIGNAL_AMD_TERMINATED "AppTerminated"
-#define SIGNAL_AMD_SUSPNED "SuspendHint"
-
-/*
- * D-Bus daemon
- */
-#define DBUS_BUS_NAME "org.freedesktop.DBus"
-#define DBUS_OBJECT_PATH "/org/freedesktop/DBus"
-#define DBUS_INTERFACE_NAME DBUS_BUS_NAME
-
-/*
- * booting
- */
-#define BOOTING_DONE_PATH "/org/tizen/system"
-#define BOOTING_DONE_INTERFACE "org.tizen.system.Booting"
-#define SIGNAL_BOOTING_DONE "BootingDone"
-
-#endif
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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 DBUS_NAMES_LOCAL_H_INCLUDE_GUARD
-#define DBUS_NAMES_LOCAL_H_INCLUDE_GUARD
-
-#include <libsyscommon/libsystemd.h>
-
-/*#define RESOURCED_DBUS_BUS_NAME "org.tizen.resourced"
-#define RESOURCED_DBUS_OBJECT_PATH "/Org/Tizen/ResourceD"
-#define RESOURCED_DBUS_INTERFACE_NAME RESOURCED_DBUS_BUS_NAME*/
-
-/*
- * Core service
- * get/set swap status
- * operations about swap
- */
-#define RESOURCED_PATH_SWAP RESOURCED_OBJECT_PATH"/Swap"
-#define RESOURCED_INTERFACE_SWAP RESOURCED_INTERFACE_NAME".swap"
-
-/*#define RESOURCED_PATH_FREEZER RESOURCED_DBUS_OBJECT_PATH"/Freezer"
-#define RESOURCED_INTERFACE_FREEZER RESOURCED_DBUS_INTERFACE_NAME".freezer"*/
-
-#define RESOURCED_PATH_OOM RESOURCED_OBJECT_PATH"/Oom"
-#define RESOURCED_INTERFACE_OOM RESOURCED_INTERFACE_NAME".oom"
-
-/*#define RESOURCED_PATH_PROCESS RESOURCED_DBUS_OBJECT_PATH"/Process"
-#define RESOURCED_INTERFACE_PROCESS RESOURCED_DBUS_INTERFACE_NAME".process"*/
-
-#define RESOURCED_PATH_WATCHDOG RESOURCED_OBJECT_PATH"/Watchdog"
-#define RESOURCED_INTERFACE_WATCHDOG RESOURCED_INTERFACE_NAME".watchdog"
-
-
-#define SIGNAL_PROC_ACTIVE "Active"
-#define SIGNAL_PROC_EXCLUDE "ProcExclude"
-#define SIGNAL_PROC_PRELAUNCH "ProcPrelaunch"
-#define SIGNAL_PROC_SWEEP "ProcSweep"
-#define SIGNAL_APP_WATCHDOG "AppWatchdog"
-#define SIGNAL_PROC_SYSTEMSERVICE "SystemService"
-#define SIGNAL_PROC_EXCLUDEAPPID "ProcExcludeByAppid"
-#define SIGNAL_PROC_SET_PRIORITY "ProcSetPriority"
-
-#define SIGNAL_OOM_SET_THRESHOLD "SetThreshold"
-#define SIGNAL_OOM_SET_LEAVE_THRESHOLD "SetLeaveThreshold"
-#define SIGNAL_OOM_TRIGGER "Trigger"
-#define SIGNAL_OOM_SET_PERCEPTIBLE "SetPerceptible"
-#define SIGNAL_OOM_SET_PLATFORM "SetPlatformSwap"
-#define SIGNAL_OOM_SET_MEMLIMIT "SetMemLimit"
-#define SIGNAL_OOM_MEMLIMIT_EVENT "MemLimitEvent"
-
-#define SIGNAL_NAME_SWAP_START_PID "SwapStartPid"
-/*
- * Logging
- */
-/*#define RESOURCED_PATH_LOGGING RESOURCED_DBUS_OBJECT_PATH"/Logging"
-#define RESOURCED_INTERFACE_LOGGING RESOURCED_DBUS_INTERFACE_NAME".logging"*/
-
-#endif
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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 "macro.h"
-#include "dedup-common.h"
-#include "trace.h"
-
-static struct dedup_conf *dedup_conf = NULL;
-
-static enum dedup_state dedup_state;
-
-struct dedup_conf *get_dedup_conf(void)
-{
- if (!dedup_conf) {
- dedup_conf = (struct dedup_conf *)calloc(1, sizeof (struct dedup_conf));
- if (!dedup_conf) {
- _E("Failed to alloc memory for cpu configuration");
- return NULL;
- }
- else {
- dedup_conf->enable = false;
- dedup_conf->boot_dedup_enable = false;
- dedup_conf->scan_on_lowmem = false;
- }
- }
-
- return dedup_conf;
-}
-
-void free_dedup_conf(void)
-{
- if (dedup_conf)
- free(dedup_conf);
-}
-
-enum dedup_state dedup_get_state(void)
-{
- return dedup_state;
-}
-
-void dedup_set_state(enum dedup_state state)
-{
- if ((state != DEDUP_ON) && (state != DEDUP_OFF) &&
- state != DEDUP_ONE_SHOT)
- return;
-
- dedup_state = state;
-}
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/**
- * @file dedup-common.h
- * @desc dedup common process
- **/
-
-#ifndef __DEDUP_COMMON_H__
-#define __DEDUP_COMMON_H__
-
-#include <stdio.h>
-#include "resourced.h"
-#include "memory-cgroup.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define DEDUP_CONF_FILE RD_CONFIG_FILE(optimizer)
-#define DEDUP_SYSFS_KSM_PATH "/sys/kernel/mm/ksm"
-
-/* KSM operations */
-#define DEDUP_SYSFS_KSM_RUN "/sys/kernel/mm/ksm/run"
-#define DEDUP_SYSFS_KSM_ONESHOT "/sys/kernel/mm/ksm/one_shot_scanning"
-
-enum dedup_state {
- DEDUP_ARG_START = -1,
- DEDUP_OFF,
- DEDUP_ON,
- DEDUP_ONE_SHOT,
- DEDUP_ARG_END,
-};
-
-enum dedup_mode {
- DEDUP_MODE_NONE = 0,
- DEDUP_MODE_PERIODIC,
- DEDUP_MODE_ONESHOT,
- DEDUP_MODE_MAX,
-};
-
-enum ksm_stat {
- KSM_STAT_PAGES_SHARING = 0,
- KSM_STAT_PAGES_SHARED,
- KSM_STAT_MAX,
-};
-
-enum ksm_scan_mode {
- KSM_SCAN_NONE = 0,
- KSM_SCAN_PARTIAL,
- KSM_SCAN_FULL,
-};
-
-struct ksm {
- char mode[MAX_TYPE_LENGTH];
- int pages;
- int boost_pages;
-};
-
-struct dedup_conf {
- bool enable;
- bool boot_dedup_enable;
- bool scan_on_lowmem;
- struct ksm ksm;
-};
-
-struct dedup_conf *get_dedup_conf(void);
-void free_dedup_conf(void);
-
-enum dedup_state dedup_get_state(void);
-void dedup_set_state(enum dedup_state state);
-unsigned int dedup_get_ksm_stat(enum ksm_stat stat_type);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __DEDUP_COMMON_H__ */
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * @file dbus-handler.c
+ *
+ * @desc dbus handler using libdbus
+ *
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <stdint.h>
+
+#include "trace.h"
+#include "dbus-handler.h"
+#include "macro.h"
+#include "resourced.h"
+#include "util.h"
+#include "fd-handler.h"
+
+static guint owner_id;
+static GList *dbus_signal_list;
+static GList *dbus_method_handle_list;
+
+GDBusConnection *d_bus_get_connection(void)
+{
+ static GDBusConnection *g_dbus_conn = NULL;
+
+ if (g_dbus_conn)
+ return g_dbus_conn;
+
+ g_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
+ g_assert(g_dbus_conn);
+
+ g_dbus_connection_set_exit_on_close(g_dbus_conn, FALSE);
+ return g_dbus_conn;
+}
+
+static struct d_bus_signal *d_bus_find_signal(const char *path, const char *interface, const char *name)
+{
+ size_t path_len, interface_len, name_len;
+ GList *iter;
+ struct d_bus_signal *signal;
+
+ path_len = strlen(path) + 1;
+ interface_len = strlen(interface) + 1;
+ name_len = strlen(name) + 1;
+
+ for (iter = dbus_signal_list; iter; iter = g_list_next(iter)) {
+ signal = (struct d_bus_signal *)iter->data;
+ if (strncmp(signal->path, path, path_len))
+ continue;
+ if (strncmp(signal->interface, interface, interface_len))
+ continue;
+ if (strncmp(signal->name, name, name_len))
+ continue;
+ return signal;
+ }
+
+ return NULL;
+}
+
+/* Find appropriate method and call its callback */
+static void d_bus_method_handler(GDBusConnection *connection,
+ const gchar *sender, const gchar *object_path,
+ const gchar *interface_name, const gchar *method_name,
+ GVariant *parameters, GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ int i;
+ struct d_bus_method_handle *handle;
+ int name_len;
+
+ if (!user_data) {
+ _E("There is no handle about received gdbus method");
+ return;
+ }
+ handle = (struct d_bus_method_handle *)user_data;
+
+ name_len = strlen(method_name) + 1;
+ for (i = 0; i < handle->num_methods; i++) {
+ if (strncmp(handle->methods[i].name, method_name, name_len))
+ continue;
+
+ handle->methods[i].callback(invocation, parameters);
+ break;
+ }
+}
+
+static const GDBusInterfaceVTable vtable = { d_bus_method_handler, NULL, NULL };
+
+static void d_bus_signal_handler(GDBusConnection *connection,
+ const gchar *sender, const gchar *object_path,
+ const gchar *interface_name, const gchar *signal_name,
+ GVariant *parameters, gpointer user_data)
+{
+ struct d_bus_signal *signal = (struct d_bus_signal *)user_data;
+ if (!signal || !signal->callback)
+ return;
+
+ signal->callback(parameters);
+}
+
+struct dbus_int {
+ int *list;
+ int size;
+};
+
+static GVariant *append_variant(const char *sig, char *param[])
+{
+ GVariantBuilder builder;
+ GVariantBuilder *sub_builder;
+ GVariant *var;
+ struct dbus_int *array_int;
+ char *ch;
+ int i, j;
+
+ if (!sig || !param)
+ return NULL;
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+
+ for (ch = (char *)sig, i = 0; *ch != '\0'; ++i, ++ch) {
+ switch (*ch) {
+ case 'i':
+ g_variant_builder_add(&builder, "i", atoi(param[i]));
+ break;
+ case 'u':
+ g_variant_builder_add(&builder, "u", strtoul(param[i], NULL, 10));
+ break;
+ case 't':
+ g_variant_builder_add(&builder, "t", atoll(param[i]));
+ break;
+ case 's':
+ g_variant_builder_add(&builder, "s", param[i]);
+ break;
+ case 'a':
+ ++ch;
+ switch (*ch) {
+ case 'i':
+ sub_builder = g_variant_builder_new(G_VARIANT_TYPE("ai"));
+ array_int = (struct dbus_int *)param[i];
+ for (j = 0; j < array_int->size; j++)
+ g_variant_builder_add(sub_builder, "i", array_int->list[j]);
+ var = g_variant_new("ai", sub_builder);
+ g_variant_builder_unref(sub_builder);
+ g_variant_builder_add_value(&builder, var);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+ return g_variant_builder_end(&builder);
+}
+
+int d_bus_call_method_sync(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[])
+{
+ GVariant *gv = NULL;
+
+ if (sig || param) {
+ gv = append_variant(sig, param);
+ if (!gv) {
+ _E("Failed to build g_variant");
+ return -EINVAL;
+ }
+ }
+
+ return d_bus_call_method_sync_gvariant(dest, path, interface, method, gv);
+}
+
+int d_bus_call_method_sync_gvariant(const char *dest, const char *path,
+ const char *interface, const char *method,
+ GVariant *gv)
+{
+ int ret;
+ GVariant *reply = NULL;
+ GError *err = NULL;
+
+ reply = g_dbus_connection_call_sync(d_bus_get_connection(), dest, path,
+ interface, method, gv, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+ if (err || !reply) {
+ /* The case where !err && !reply (i.e. reply type mismatch) can't currently happen
+ * because we don't specify the desired reply type, but it's good to be future-proof */
+ _E("Failed to call D-Bus name %s, objpath %s, iface %s, method %s: %s",
+ dest, path, interface, method, err ? err->message : "reply signature mismatch");
+ if (err)
+ g_error_free(err);
+ return -ECOMM;
+ }
+
+ do_expr_unless_g_variant_consume_typechecked(return -EINVAL, reply, "(i)", &ret);
+
+ return ret;
+}
+
+int d_bus_call_method_sync_gvariant_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ GVariant *gv, GVariant **out_reply)
+{
+ GVariant *reply = NULL;
+ GError *err = NULL;
+
+ reply = g_dbus_connection_call_sync(d_bus_get_connection(), dest, path,
+ interface, method, gv, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+ if (err || !reply) {
+ /* The case where !err && !reply (i.e. reply type mismatch) can't currently happen
+ * because we don't specify the desired reply type, but it's good to be future-proof */
+ _E("Failed to call D-Bus name %s, objpath %s, iface %s, method %s: %s",
+ dest, path, interface, method, err ? err->message : "reply signature mismatch");
+ if (err)
+ g_error_free(err);
+ return -ECOMM;
+ }
+
+ *out_reply = reply;
+
+ return 0;
+}
+
+int d_bus_call_method_async(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[])
+{
+ GVariant *gv = append_variant(sig, param);
+ if (!gv) {
+ _E("Failed to build g_variant");
+ return -EINVAL;
+ }
+ return d_bus_call_method_async_gvariant(dest, path, interface, method, gv);
+}
+
+int d_bus_call_method_async_gvariant(const char *dest, const char *path,
+ const char *interface, const char *method, GVariant *gv)
+{
+ g_dbus_connection_call(d_bus_get_connection(), dest, path, interface, method,
+ gv, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+
+ return 0;
+}
+
+resourced_ret_c d_bus_register_signal(const char *path, const char *interface,
+ const char *name, d_bus_signal_callback callback, void *user_data)
+{
+ struct d_bus_signal *signal;
+
+ if (d_bus_find_signal(path, interface, name)) {
+ _E("Same D-Bus signal is already registered");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ signal = calloc(1, sizeof(struct d_bus_signal));
+ if (!signal) {
+ _E("Not enough memory!");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ signal->path = path;
+ signal->interface = interface;
+ signal->name = name;
+ signal->callback = callback;
+ signal->user_data = user_data;
+
+ signal->subscription_id = g_dbus_connection_signal_subscribe(d_bus_get_connection(),
+ NULL, interface, name, path, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
+ d_bus_signal_handler, signal, NULL);
+ if (!(signal->subscription_id)) {
+ _E("Failed to subscribe signal %s", name);
+ free(signal);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ dbus_signal_list = g_list_append(dbus_signal_list, signal);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int d_bus_broadcast_signal_gvariant(const char *path, const char *interface,
+ const char *name, GVariant *gv)
+{
+ int ret;
+
+ ret = g_dbus_connection_emit_signal(d_bus_get_connection(),
+ NULL, path, interface, name, gv, NULL);
+ if (ret != TRUE) {
+ _E("Failed to emit gdbus signal(%s:%s-%s)", path, interface, name);
+ return -ECOMM;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int d_bus_broadcast_signal(const char *path, const char *interface,
+ const char *name, const char *sig, char *param[])
+{
+ GVariant *gv = append_variant(sig, param);
+ if (!gv) {
+ _E("Failed to build g_variant");
+ return -EINVAL;
+ }
+ return d_bus_broadcast_signal_gvariant(path, interface, name, gv);
+}
+
+resourced_ret_c d_bus_register_methods(const char *path, const char *xml,
+ const struct d_bus_method *methods, const size_t num_methods)
+{
+ struct d_bus_method_handle *handle = NULL;
+ GError *err = NULL;
+
+ if (!path || !xml || !methods) {
+ _E("You must input path, introspection xml and method list");
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+ }
+
+ handle = (struct d_bus_method_handle *)calloc(1, sizeof(struct d_bus_method_handle));
+ if (!handle) {
+ _E("Not enough memory!");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ handle->path = path;
+ handle->methods = methods;
+ handle->num_methods = num_methods;
+
+ handle->node_info = g_dbus_node_info_new_for_xml(xml, &err);
+ if (!handle->node_info) {
+ _E("Failed to make node_info : %s", err->message);
+ goto on_error;
+ }
+
+ handle->subscription_id = g_dbus_connection_register_object(d_bus_get_connection(),
+ path, handle->node_info->interfaces[0], &vtable, (gpointer)handle, NULL, &err);
+ if (!handle->subscription_id) {
+ _E("Failed to register gdbus methods with path %s : %s", path, err->message);
+ g_dbus_node_info_unref(handle->node_info);
+ goto on_error;
+ } else
+ dbus_method_handle_list = g_list_append(dbus_method_handle_list, (gpointer)handle);
+
+ return RESOURCED_ERROR_NONE;
+
+on_error:
+ g_clear_error(&err);
+ free(handle);
+
+ return RESOURCED_ERROR_FAIL;
+}
+
+resourced_ret_c d_bus_register_signals(const struct d_bus_signal *signals, const size_t size)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < size; i++) {
+ if (!signals[i].path || !signals[i].interface || !signals[i].name || !signals[i].callback)
+ continue;
+
+ ret = d_bus_register_signal(
+ signals[i].path,
+ signals[i].interface,
+ signals[i].name,
+ signals[i].callback,
+ signals[i].user_data);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Fail to add signal %s, %s!\n", signals[i].path, signals[i].name);
+ return RESOURCED_ERROR_FAIL;
+ }
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+resourced_ret_c d_bus_reply_message(GDBusMessage *msg)
+{
+ GError *err = NULL;
+
+ if (!g_dbus_connection_send_message(d_bus_get_connection(), msg,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &err)) {
+ _E("Fail to reply gdbus message");
+ g_clear_error(&err);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ g_clear_error(&err);
+ return RESOURCED_ERROR_NONE;
+}
+
+void d_bus_init(void)
+{
+ owner_id = g_bus_own_name_on_connection(d_bus_get_connection(), RESOURCED_BUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL);
+ if (owner_id == 0) {
+ _E("Failed to get gdbus own name");
+ }
+}
+
+void d_bus_exit(void)
+{
+ GList *iter;
+ struct d_bus_signal *signal;
+ struct d_bus_method_handle *method_handle;
+ GDBusConnection *conn = d_bus_get_connection();
+
+ if (owner_id != 0)
+ g_bus_unown_name(owner_id);
+
+ /* Remove D-Bus signal list */
+ for (iter = dbus_signal_list; iter; iter = g_list_next(iter)) {
+ signal = (struct d_bus_signal *)iter->data;
+ g_dbus_connection_signal_unsubscribe(conn, signal->subscription_id);
+ dbus_signal_list = g_list_remove(dbus_signal_list, signal);
+ free(signal);
+ }
+
+ /* Remove D-Bus method list */
+ for (iter = dbus_method_handle_list; iter; iter = g_list_next(iter)) {
+ method_handle = (struct d_bus_method_handle *)iter->data;
+ g_dbus_connection_unregister_object(conn, method_handle->subscription_id);
+ g_dbus_node_info_unref(method_handle->node_info);
+ dbus_method_handle_list = g_list_remove(dbus_method_handle_list, method_handle);
+ free(method_handle);
+ }
+
+ g_object_unref(conn);
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 - 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file dbus-handler.h
+ * @desc dbus handler using libdbus
+ **/
+
+#ifndef __DBUS_HANDLER_H__
+#define __DBUS_HANDLER_H__
+
+#include <dbus-names-local.h>
+#include <dbus-names-external.h>
+#include <gio/gio.h>
+#include <resourced.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef void (*d_bus_method_callback)(GDBusMethodInvocation *invocation, GVariant *params);
+typedef void (*d_bus_signal_callback)(GVariant *params);
+
+struct d_bus_method {
+ const char *name;
+ d_bus_method_callback callback;
+};
+
+struct d_bus_method_handle {
+ const char *path;
+ const struct d_bus_method *methods;
+ size_t num_methods;
+ GDBusNodeInfo *node_info;
+ guint subscription_id;
+};
+
+struct d_bus_signal {
+ const char *path;
+ const char *interface;
+ const char *name;
+ d_bus_signal_callback callback;
+ void *user_data;
+ guint subscription_id;
+};
+
+/*
+ * If reply signature is existed, GDBus allows the return type
+ * to declared type or error.
+ *
+ * However, before GDBus is applied, resourced returns NULL
+ * when error is occurred.
+ *
+ * Therefore, for backward compatibility, we don't use the function
+ * g_dbus_method_invocation_return_error and return NULL with sending new message
+ *
+ * cf) Process resource usage functions use return_error because
+ * it is only for Runtime-info (we can control this package)
+ */
+#define D_BUS_REPLY_EMPTY_TUPLE(ivc, signature) \
+{ \
+ GDBusMessage *re = g_dbus_message_new_method_reply(g_dbus_method_invocation_get_message(ivc)); \
+ d_bus_reply_message(re); \
+ g_object_unref(re); \
+ g_object_unref(ivc); \
+}
+
+#define D_BUS_REPLY_NULL(ivc, signature) \
+{ \
+ g_dbus_method_invocation_return_value(ivc, g_variant_new(signature)); \
+}
+
+#define D_BUS_REPLY_ERR(ivc) \
+{ \
+ g_dbus_method_invocation_return_error(ivc, \
+ G_DBUS_ERROR, G_DBUS_ERROR_FAILED, \
+ "%s failed", g_dbus_method_invocation_get_method_name(ivc)); \
+}
+
+GDBusConnection *d_bus_get_connection(void);
+
+int d_bus_call_method_sync_gvariant(const char *dest, const char *path,
+ const char *interface, const char *method,
+ GVariant *gv);
+
+int d_bus_call_method_sync(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[]);
+
+int d_bus_call_method_async_gvariant(const char *dest, const char *path,
+ const char *interface, const char *method,
+ GVariant *gv);
+
+int d_bus_call_method_sync_gvariant_with_reply(const char *dest, const char *path,
+ const char *interface, const char *method,
+ GVariant *gv, GVariant **out_reply);
+
+int d_bus_call_method_async(const char *dest, const char *path,
+ const char *interface, const char *method,
+ const char *sig, char *param[]);
+
+resourced_ret_c d_bus_register_signal(const char *path, const char *interface,
+ const char *name, d_bus_signal_callback callback, void *user_data);
+
+int d_bus_broadcast_signal_gvariant(const char *path, const char *interface,
+ const char *name, GVariant *gv);
+
+int d_bus_broadcast_signal(const char *path, const char *interface,
+ const char *name, const char *sig, char *param[]);
+
+resourced_ret_c d_bus_register_methods(const char *path, const char *xml,
+ const struct d_bus_method *methods, const size_t num_methods);
+
+resourced_ret_c d_bus_register_signals(const struct d_bus_signal *signals,
+ const size_t size);
+
+resourced_ret_c d_bus_reply_message(GDBusMessage *msg);
+
+int launch_system_app_by_dbus(const char *dest, const char *path,
+ const char *iface, const char *method, const char *arg_type, ...);
+
+void d_bus_init(void);
+void d_bus_exit(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __DBUS_HANDLER_H__ */
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 DBUS_NAMES_EXTERNAL_H_INCLUDE_GUARD
+#define DBUS_NAMES_EXTERNAL_H_INCLUDE_GUARD
+
+/*
+ * System popup
+ */
+#define SYSTEM_POPUP_BUS_NAME "org.tizen.system.popup"
+#define SYSTEM_POPUP_PATH_NAME "/Org/Tizen/System/Popup"
+
+#define SYSTEM_POPUP_PATH_SYSTEM SYSTEM_POPUP_PATH_NAME"/System"
+#define SYSTEM_POPUP_IFACE_SYSTEM SYSTEM_POPUP_BUS_NAME".System"
+
+/*
+ * Deviced
+ */
+/*#define DEVICED_BUS_NAME "org.tizen.system.deviced"
+#define DEVICED_OBJECT_PATH "/Org/Tizen/System/DeviceD"
+
+#define DEVICED_PATH_PROCESS DEVICED_OBJECT_PATH"/Process"
+#define DEVICED_INTERFACE_PROCESS DEVICED_BUS_NAME".Process"
+
+#define DEVICED_PATH_DISPLAY DEVICED_OBJECT_PATH"/Display"
+#define DEVICED_INTERFACE_DISPLAY DEVICED_BUS_NAME".display"
+
+#define DEVICED_PATH_BATTERY DEVICED_OBJECT_PATH"/Battery"
+#define DEVICED_INTERFACE_BATTERY DEVICED_BUS_NAME".Battery"
+
+#define DEVICED_PATH_POWEROFF DEVICED_OBJECT_PATH"/PowerOff"
+#define DEVICED_INTERFACE_POWEROFF DEVICED_BUS_NAME".PowerOff"
+
+#define DEVICED_PATH_TIME DEVICED_OBJECT_PATH"/Time"
+#define DEVICED_INTERFACE_TIME DEVICED_BUS_NAME".Time"*/
+
+
+#define SIGNAL_DEVICED_LCDON "LCDOn"
+#define SIGNAL_DEVICED_LCDOFF "LCDOff"
+#define SIGNAL_DEVICED_LCDONCOMPLETE "LCDOnCompleted"
+#define SIGNAL_DEVICED_POWEROFF_STATE "ChangeState"
+#define SIGNAL_DEVICED_SYSTEMTIME_CHANGED "SystemTimeChanged"
+#define SIGNAL_DEVICED_LOW_BATTERY "BatteryStatusLow"
+#define SIGNAL_DEVICED_SUSPEND "sleep"
+#define SIGNAL_DEVICED_WAKEUP "wakeup"
+
+/*
+ * dump service
+ */
+#define DUMP_SERVICE_BUS_NAME "org.tizen.system.dumpservice"
+#define DUMP_SERVICE_OBJECT_PATH "/Org/Tizen/System/DumpService"
+#define DUMP_SERVICE_INTERFACE_NAME DUMP_SERVICE_BUS_NAME
+
+#define SIGNAL_DUMP "Dump"
+#define SIGNAL_DUMP_START "Start"
+#define SIGNAL_DUMP_FINISH "Finish"
+
+/*
+ * Crash
+ */
+#define CRASH_BUS_NAME "org.tizen.system.crash"
+#define CRASH_OBJECT_PATH "/Org/Tizen/System/Crash"
+#define CRASH_INTERFACE_NAME CRASH_BUS_NAME
+#define CRASH_PATH_CRASH CRASH_OBJECT_PATH"/Crash"
+#define CRASH_INTERFACE_CRASH CRASH_INTERFACE_NAME".Crash"
+#define PROCESS_CRASHED "ProcessCrashed"
+
+/*
+ * AMD
+ */
+#define AUL_APPSTATUS_BUS_NAME "org.tizen.aul.AppStatus"
+#define AUL_APPSTATUS_OBJECT_PATH "/Org/Tizen/Aul/AppStatus"
+#define AUL_APPSTATUS_INTERFACE_NAME AUL_APPSTATUS_BUS_NAME
+
+#define AUL_SUSPEND_BUS_NAME "org.tizen.appfw.SuspendHint"
+#define AUL_SUSPEND_OBJECT_PATH "/Org/Tizen/Appfw/SuspendHint"
+#define AUL_SUSPEND_INTERFACE_NAME AUL_SUSPEND_BUS_NAME
+
+#define SIGNAL_AMD_LAUNCH "AppLaunch"
+#define SIGNAL_AMD_RESUME "AppResume"
+#define SIGNAL_AMD_TERMINATE "AppTerminate"
+#define SIGNAL_AMD_STATE "AppStatusChange"
+#define SIGNAL_AMD_GROUP "AppGroup"
+#define SIGNAL_AMD_TERMINATED "AppTerminated"
+#define SIGNAL_AMD_SUSPNED "SuspendHint"
+
+/*
+ * D-Bus daemon
+ */
+#define DBUS_BUS_NAME "org.freedesktop.DBus"
+#define DBUS_OBJECT_PATH "/org/freedesktop/DBus"
+#define DBUS_INTERFACE_NAME DBUS_BUS_NAME
+
+/*
+ * booting
+ */
+#define BOOTING_DONE_PATH "/org/tizen/system"
+#define BOOTING_DONE_INTERFACE "org.tizen.system.Booting"
+#define SIGNAL_BOOTING_DONE "BootingDone"
+
+#endif
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 DBUS_NAMES_LOCAL_H_INCLUDE_GUARD
+#define DBUS_NAMES_LOCAL_H_INCLUDE_GUARD
+
+#include <libsyscommon/libsystemd.h>
+
+/*#define RESOURCED_DBUS_BUS_NAME "org.tizen.resourced"
+#define RESOURCED_DBUS_OBJECT_PATH "/Org/Tizen/ResourceD"
+#define RESOURCED_DBUS_INTERFACE_NAME RESOURCED_DBUS_BUS_NAME*/
+
+/*
+ * Core service
+ * get/set swap status
+ * operations about swap
+ */
+#define RESOURCED_PATH_SWAP RESOURCED_OBJECT_PATH"/Swap"
+#define RESOURCED_INTERFACE_SWAP RESOURCED_INTERFACE_NAME".swap"
+
+/*#define RESOURCED_PATH_FREEZER RESOURCED_DBUS_OBJECT_PATH"/Freezer"
+#define RESOURCED_INTERFACE_FREEZER RESOURCED_DBUS_INTERFACE_NAME".freezer"*/
+
+#define RESOURCED_PATH_OOM RESOURCED_OBJECT_PATH"/Oom"
+#define RESOURCED_INTERFACE_OOM RESOURCED_INTERFACE_NAME".oom"
+
+/*#define RESOURCED_PATH_PROCESS RESOURCED_DBUS_OBJECT_PATH"/Process"
+#define RESOURCED_INTERFACE_PROCESS RESOURCED_DBUS_INTERFACE_NAME".process"*/
+
+#define RESOURCED_PATH_WATCHDOG RESOURCED_OBJECT_PATH"/Watchdog"
+#define RESOURCED_INTERFACE_WATCHDOG RESOURCED_INTERFACE_NAME".watchdog"
+
+
+#define SIGNAL_PROC_ACTIVE "Active"
+#define SIGNAL_PROC_EXCLUDE "ProcExclude"
+#define SIGNAL_PROC_PRELAUNCH "ProcPrelaunch"
+#define SIGNAL_PROC_SWEEP "ProcSweep"
+#define SIGNAL_APP_WATCHDOG "AppWatchdog"
+#define SIGNAL_PROC_SYSTEMSERVICE "SystemService"
+#define SIGNAL_PROC_EXCLUDEAPPID "ProcExcludeByAppid"
+#define SIGNAL_PROC_SET_PRIORITY "ProcSetPriority"
+
+#define SIGNAL_OOM_SET_THRESHOLD "SetThreshold"
+#define SIGNAL_OOM_SET_LEAVE_THRESHOLD "SetLeaveThreshold"
+#define SIGNAL_OOM_TRIGGER "Trigger"
+#define SIGNAL_OOM_SET_PERCEPTIBLE "SetPerceptible"
+#define SIGNAL_OOM_SET_PLATFORM "SetPlatformSwap"
+#define SIGNAL_OOM_SET_MEMLIMIT "SetMemLimit"
+#define SIGNAL_OOM_MEMLIMIT_EVENT "MemLimitEvent"
+
+#define SIGNAL_NAME_SWAP_START_PID "SwapStartPid"
+/*
+ * Logging
+ */
+/*#define RESOURCED_PATH_LOGGING RESOURCED_DBUS_OBJECT_PATH"/Logging"
+#define RESOURCED_INTERFACE_LOGGING RESOURCED_DBUS_INTERFACE_NAME".logging"*/
+
+#endif
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file safe-kill.c
+ *
+ * @desc check if process is dumping core before sending a signal
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include "safe-kill.h"
+#include "trace.h"
+#include "util.h"
+#include "macro.h"
+#include <signal.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdbool.h>
+
+EXPORT_TEST bool is_process_coredumping(pid_t pid)
+{
+ char buf[LINE_MAX];
+ _cleanup_fclose_ FILE *fp = NULL;
+ int val = 0;
+
+ snprintf(buf, sizeof buf, "/proc/%d/status", pid);
+ fp = fopen(buf, "r");
+ if (!fp)
+ return false;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ /* Skip the lines, until first match */
+ if (!strstart_with(buf, "CoreDumping:"))
+ continue;
+
+ if (sscanf(buf, "CoreDumping: %d", &val) == 1)
+ break;
+
+ return false;
+ }
+
+ return (val == 1);
+}
+
+int safe_kill(pid_t pid, int sig)
+{
+ /* Pass signals other than SIGKILL, as other signals are not delivered to
+ * a process that's dumping a core anyway, and SIGKILL is the only one that
+ * can potentially break that process.
+ * Alternatively, with SIGKILL check if process is coredumping.
+ */
+ if (sig != SIGKILL || !is_process_coredumping(pid)) {
+ _D("safe-kill: delivering signal %d to process %d immediately", sig, pid);
+ return kill(pid, sig);
+ }
+
+ _I("safe-kill: process %d is coredumping - signal SIGKILL not sent", pid);
+ return 0;
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 SAFE_KILL_H
+#define SAFE_KILL_H
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+int safe_kill(pid_t pid, int sig);
+
+#ifdef _UNIT_TEST
+bool is_process_coredumping(pid_t pid);
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SAFE_KILL_H */
+++ /dev/null
-/* NOTE: this file was dynamically generated by gperf but is included verbatim
- * (instead of being regenerated) due to various build environment issues */
-
-/* ANSI-C code produced by gperf version 3.0.4 */
-/* Command-line: gperf /home/abuild/rpmbuild/BUILD/resourced-6.0.2/src/common/meminfo-lookup.gperf */
-/* Computed positions: -k'1-2,10' */
-
-#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
- && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
- && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
- && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
- && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
- && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
- && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
- && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
- && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
- && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
- && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
- && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
- && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
- && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
- && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
- && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
- && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
- && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
- && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
- && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
- && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
- && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
- && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
-/* The character set is not based on ISO-646. */
-#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
-#endif
-
-#include "procfs.h"
-#include <string.h>
-
-#define TOTAL_KEYWORDS 38
-#define MIN_WORD_LENGTH 4
-#define MAX_WORD_LENGTH 14
-#define MIN_HASH_VALUE 4
-#define MAX_HASH_VALUE 67
-/* maximum key range = 64, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-static unsigned int
-meminfo_mapping_hash (register const char *str, register unsigned int len)
-{
- static const unsigned char asso_values[] =
- {
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 5, 25, 10, 20, 68,
- 15, 68, 25, 10, 68, 25, 15, 0, 10, 68,
- 5, 68, 20, 0, 35, 10, 15, 5, 68, 68,
- 68, 68, 68, 68, 68, 25, 68, 0, 30, 0,
- 0, 5, 5, 68, 0, 0, 68, 68, 0, 0,
- 0, 5, 68, 68, 5, 0, 15, 5, 68, 0,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68
- };
- register int hval = len;
-
- switch (hval)
- {
- default:
- hval += asso_values[(unsigned char)str[9]];
- /*FALLTHROUGH*/
- case 9:
- case 8:
- case 7:
- case 6:
- case 5:
- case 4:
- case 3:
- case 2:
- hval += asso_values[(unsigned char)str[1]];
- /*FALLTHROUGH*/
- case 1:
- hval += asso_values[(unsigned char)str[0]];
- break;
- }
- return hval;
-}
-
-#ifdef __GNUC__
-__inline
-#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
-__attribute__ ((__gnu_inline__))
-#endif
-#endif
-const meminfo_mapping *
-meminfo_mapping_lookup (register const char *str, register unsigned int len)
-{
- static const meminfo_mapping wordlist[] =
- {
- {""}, {""}, {""}, {""},
- {"Slab", MEMINFO_ID_SLAB},
- {"Shmem", MEMINFO_ID_SHMEM},
- {"Mapped", MEMINFO_ID_MAPPED},
- {"Mlocked", MEMINFO_ID_MLOCKED},
- {"SwapFree", MEMINFO_ID_SWAP_FREE},
- {"SwapTotal", MEMINFO_ID_SWAP_TOTAL},
- {"SwapCached", MEMINFO_ID_SWAP_CACHED},
- {"Active", MEMINFO_ID_ACTIVE},
- {"MemFree", MEMINFO_ID_MEM_FREE},
- {"MemTotal", MEMINFO_ID_MEM_TOTAL},
- {"AnonPages", MEMINFO_ID_ANON_PAGES},
- {"PageTables", MEMINFO_ID_PAGE_TABLES},
- {"Cached", MEMINFO_ID_CACHED},
- {"Active(file)", MEMINFO_ID_ACTIVE_FILE},
- {"Inactive", MEMINFO_ID_INACTIVE},
- {"Writeback", MEMINFO_ID_WRITEBACK},
- {"SUnreclaim", MEMINFO_ID_SUNRECLAIM},
- {"Unevictable", MEMINFO_ID_UNEVICTABLE},
- {"Active(anon)", MEMINFO_ID_ACTIVE_ANON},
- {""},
- {"Inactive(anon)", MEMINFO_ID_INACTIVE_ANON},
- {"Dirty", MEMINFO_ID_DIRTY},
- {"CommitLimit", MEMINFO_ID_COMMIT_LIMIT},
- {"LowFree", MEMINFO_ID_LOW_FREE},
- {"LowTotal", MEMINFO_ID_LOW_TOTAL},
- {"Inactive(file)", MEMINFO_ID_INACTIVE_FILE},
- {""},
- {"VmallocUsed", MEMINFO_ID_VMALLOC_USED},
- {"VmallocChunk", MEMINFO_ID_VMALLOC_CHUNK},
- {"HighFree", MEMINFO_ID_HIGH_FREE},
- {"HighTotal", MEMINFO_ID_HIGH_TOTAL},
- {""},
- {"Bounce", MEMINFO_ID_BOUNCE},
- {"Buffers", MEMINFO_ID_BUFFERS},
- {""}, {""}, {""},
- {"KernelStack", MEMINFO_ID_KERNEL_STACK},
- {"VmallocTotal", MEMINFO_ID_VMALLOC_TOTAL},
- {""}, {""}, {""}, {""},
- {"MemAvailable", MEMINFO_ID_MEM_AVAILABLE},
- {""}, {""}, {""}, {""},
- {"Committed_AS", MEMINFO_ID_COMMITTED_AS},
- {""}, {""}, {""}, {""},
- {"WritebackTmp", MEMINFO_ID_WRITEBACK_TMP},
- {""}, {""}, {""}, {""},
- {"SReclaimable", MEMINFO_ID_SRECLAIMABLE},
- {""}, {""}, {""}, {""},
- {"NFS_Unstable", MEMINFO_ID_NFS_UNSTABLE}
- };
-
- if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
- {
- register int key = meminfo_mapping_hash (str, len);
-
- if (key <= MAX_HASH_VALUE && key >= 0)
- {
- register const char *s = wordlist[key].name;
-
- if (*str == *s && !strcmp (str + 1, s + 1))
- return &wordlist[key];
- }
- }
- return 0;
-}
+++ /dev/null
-%{
-#include "procfs.h"
-%}
-meminfo_mapping;
-%language=ANSI-C
-%define slot-name name
-%define hash-function-name meminfo_mapping_hash
-%define lookup-function-name meminfo_mapping_lookup
-%readonly-tables
-%omit-struct-type
-%struct-type
-%includes
-%%
-MemTotal, MEMINFO_ID_MEM_TOTAL
-MemFree, MEMINFO_ID_MEM_FREE
-MemAvailable, MEMINFO_ID_MEM_AVAILABLE
-Buffers, MEMINFO_ID_BUFFERS
-Cached, MEMINFO_ID_CACHED
-SwapCached, MEMINFO_ID_SWAP_CACHED
-Active, MEMINFO_ID_ACTIVE
-Inactive, MEMINFO_ID_INACTIVE
-Active(anon), MEMINFO_ID_ACTIVE_ANON
-Inactive(anon), MEMINFO_ID_INACTIVE_ANON
-Active(file), MEMINFO_ID_ACTIVE_FILE
-Inactive(file), MEMINFO_ID_INACTIVE_FILE
-Unevictable, MEMINFO_ID_UNEVICTABLE
-Mlocked, MEMINFO_ID_MLOCKED
-HighTotal, MEMINFO_ID_HIGH_TOTAL
-HighFree, MEMINFO_ID_HIGH_FREE
-LowTotal, MEMINFO_ID_LOW_TOTAL
-LowFree, MEMINFO_ID_LOW_FREE
-SwapTotal, MEMINFO_ID_SWAP_TOTAL
-SwapFree, MEMINFO_ID_SWAP_FREE
-Dirty, MEMINFO_ID_DIRTY
-Writeback, MEMINFO_ID_WRITEBACK
-AnonPages, MEMINFO_ID_ANON_PAGES
-Mapped, MEMINFO_ID_MAPPED
-Shmem, MEMINFO_ID_SHMEM
-Slab, MEMINFO_ID_SLAB
-SReclaimable, MEMINFO_ID_SRECLAIMABLE
-SUnreclaim, MEMINFO_ID_SUNRECLAIM
-KernelStack, MEMINFO_ID_KERNEL_STACK
-PageTables, MEMINFO_ID_PAGE_TABLES
-NFS_Unstable, MEMINFO_ID_NFS_UNSTABLE
-Bounce, MEMINFO_ID_BOUNCE
-WritebackTmp, MEMINFO_ID_WRITEBACK_TMP
-CommitLimit, MEMINFO_ID_COMMIT_LIMIT
-Committed_AS, MEMINFO_ID_COMMITTED_AS
-VmallocTotal, MEMINFO_ID_VMALLOC_TOTAL
-VmallocUsed, MEMINFO_ID_VMALLOC_USED
-VmallocChunk, MEMINFO_ID_VMALLOC_CHUNK
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/**
- * @file module-data.c
- * @desc Module data features
- **/
-
-#include "macro.h"
-#include "module-data.h"
-#include "trace.h"
-
-static struct shared_modules_data modules_data;
-
-struct shared_modules_data *get_shared_modules_data(void)
-{
- return &modules_data;
-}
-
-void init_modules_arg(struct daemon_arg *darg)
-{
- ret_msg_if(darg == NULL,
- "Init modules argument failed\n");
- modules_data.darg = darg;
-}
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/**
- * @file module-data.h
- * @desc Module data features
- **/
-
-#ifndef __MODULE_DATA_HANDLE_H__
-#define __MODULE_DATA_HANDLE_H__
-
-#include "init.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-struct swap_module_data {
- int swap_state; /* swap SWAP_ON/SWAP_OFF */
-};
-
-struct shared_modules_data {
- struct daemon_arg *darg;
- struct swap_module_data swap_data;
-};
-
-struct shared_modules_data *get_shared_modules_data(void);
-
-void init_modules_arg(struct daemon_arg *darg);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __MODULE_DATA_HANDLE_H__ */
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/**
- * @file module.c
- * @desc Module helper functions
- **/
-
-#include "macro.h"
-#include "module.h"
-#include "resourced.h"
-#include "trace.h"
-#include "dbus-handler.h"
-
-#include <glib.h>
-
-static GSList *modules_list;
-
-void add_module(const struct module_ops *module)
-{
- ret_msg_if(!module, "Invalid module handler\n");
-
- if (module->priority == MODULE_PRIORITY_EARLY)
- modules_list = g_slist_prepend(modules_list, (gpointer)module);
- else
- modules_list = g_slist_append(modules_list, (gpointer)module);
-}
-
-void remove_module(const struct module_ops *module)
-{
- modules_list = g_slist_remove(modules_list, (gpointer)module);
-}
-
-const struct module_ops *find_module(const char *name)
-{
- GSList *iter;
- const struct module_ops *module;
-
- gslist_for_each_item(iter, modules_list) {
- module = (struct module_ops *)iter->data;
- if (!strncmp(module->name, name, strlen(module->name) + 1) &&
- (module->initalized == MODULE_INITIALIZED))
- return module;
- }
- return NULL;
-}
-
-void modules_check_runtime_support(void UNUSED *data)
-{
- GSList *iter, *next;
- const struct module_ops *module;
- int ret;
-
- gslist_for_each_safe(modules_list, iter, next, module) {
- module = (const struct module_ops *)iter->data;
- _D("check runtime support [%s] module\n", module->name);
-
- if (!module->check_runtime_support)
- continue;
-
- ret = module->check_runtime_support((void *)module);
- if (ret != RESOURCED_ERROR_NONE) {
- _I("%s module is not supported in this environment", module->name);
- remove_module(module);
- continue;
- }
- }
-}
-
-static void module_initcall_level(void *data, int priority)
-{
- GSList *iter;
- struct module_ops *module;
- int ret;
-
- gslist_for_each_item(iter, modules_list) {
- module = (struct module_ops *)iter->data;
-
- assert(module);
-
- if (module->priority < priority)
- continue;
-
- if (module->initalized != MODULE_NONINITIALIZED)
- continue;
-
- if (!module->init)
- continue;
-
- ret = module->init(data);
- /* Module disabled on runtime or just failed to start. */
- if (ret < 0) {
- module->initalized = MODULE_DROPPED;
- _I("Fail to initialize [%s] module, dropped.", module->name);
- continue;
- }
-
- module->initalized = MODULE_INITIALIZED;
- }
-}
-
-void modules_init(void *data)
-{
- module_initcall_level(data, MODULE_PRIORITY_HIGH);
-}
-
-void modules_init_late(void *data)
-{
- module_initcall_level(data, MODULE_PRIORITY_NORMAL);
- module_initcall_level(data, MODULE_PRIORITY_LATE);
-}
-
-void modules_exit(void *data)
-{
- GSList *iter;
- struct module_ops *module;
- int ret;
-
- gslist_for_each_item(iter, modules_list) {
- module = (struct module_ops *)iter->data;
- if (module->exit && (module->initalized == MODULE_INITIALIZED)) {
- module->initalized = MODULE_NONINITIALIZED;
- ret = module->exit(data);
- if (ret < 0)
- _E("Fail to deinitialize [%s] module\n", module->name);
- else
- _D("Deinitialize [%s] module\n", module->name);
- }
- }
- g_slist_free(modules_list);
- modules_list = NULL;
-}
-
-void modules_restore(void *data)
-{
- struct module_ops *module;
- GSList *iter;
- int ret;
-
- gslist_for_each_item(iter, modules_list) {
- module = (struct module_ops *)iter->data;
-
- assert(module);
-
- if (module->initalized != MODULE_INITIALIZED)
- continue;
-
- if (!module->restore)
- continue;
-
- ret = module->restore(data);
- if (ret < 0) {
- _E("Fail to restore [%s] module", module->name);
- continue;
- }
-
- _I("Restored [%s] module", module->name);
- }
-}
-
-void modules_dump(FILE *fp, int mode)
-{
- GSList *iter;
- const struct module_ops *module;
-
- gslist_for_each_item(iter, modules_list) {
- module = (struct module_ops *)iter->data;
- if (module->initalized != MODULE_INITIALIZED)
- continue;
-
- _D("dump [%s] module\n", module->name);
- if (module->dump)
- module->dump(fp, mode, module->dump_data);
- }
-}
-
-static void dbus_list_active_modules_handler(GDBusMethodInvocation *invocation, GVariant *params)
-{
- struct module_ops *module;
- GSList *list_iter;
- GVariantBuilder builder, *sub_builder;
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
- sub_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
-
- gslist_for_each_item(list_iter, modules_list) {
- module = (struct module_ops *)list_iter->data;
- if (module->initalized != MODULE_INITIALIZED)
- continue;
-
- g_variant_builder_add(sub_builder, "s", module->name);
- }
- g_variant_builder_add_value(&builder, g_variant_new("as", sub_builder));
- g_variant_builder_unref(sub_builder);
-
- g_dbus_method_invocation_return_value(invocation,
- g_variant_builder_end(&builder));
-}
-
-static const char resourced_module_methods_xml[] =
-"<node>"
-" <interface name ='"RESOURCED_INTERFACE_NAME"'>"
-" <method name='ListActiveModuels'>"
-" <arg type='as' name='ActiveModules' direction='out'/>"
-" </method>"
-" </interface>"
-"</node>";
-
-static struct d_bus_method resourced_module_methods[] = {
- { "ListActiveModuels", dbus_list_active_modules_handler },
- /* Add methods here */
-};
-
-int modules_add_methods(void)
-{
- return d_bus_register_methods(RESOURCED_OBJECT_PATH, resourced_module_methods_xml,
- resourced_module_methods, ARRAY_SIZE(resourced_module_methods));
-}
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/**
- * @file module.h
- * @desc Module helper functions
- **/
-
-#ifndef __MODULE_HANDLE_H__
-#define __MODULE_HANDLE_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/**
- * @brief module_priority is used to initialization order of each
- * modules.
- */
-enum module_priority {
- /**
- * MODULE_PRIORITY_LATE is default priority of modules.
- * These modules are initialized after other modules
- * are initialized.
- */
- MODULE_PRIORITY_LATE = 0,
-
- /**
- * MODULE_PRIORITY_NORMAL modules are initialized after
- * booting is done.
- */
- MODULE_PRIORITY_NORMAL,
-
- /**
- * MODULE_PRIORITY_HIGH modules are initialized
- * as soon as resourced is started.
- */
- MODULE_PRIORITY_HIGH,
-
- /**
- * MODULE_PRIORITY_EARLY modules are initialized
- * before MODULE_PRIORITY_NORMAL modules.
- */
- MODULE_PRIORITY_EARLY,
-};
-
-enum module_state {
- MODULE_NONINITIALIZED,
- MODULE_INITIALIZED,
- MODULE_DROPPED,
-};
-
-/*
- * Each module must have at least those field defined:
- * .priority (default : MODULE_PRIORITY_LATE)
- * .name (name of the module, as string)
- * .init (must return RESOURCED_ERROR_NONE on success)
- * .exit (must return RESOURCED_ERROR_NONE on success)
- * .restore (optional handler to calls on resourced is
- * restarted. must return RESOURCED_ERROR_NONE on success))
- *
- * All rest of callbacks are optional for module to work.
- *
- */
-struct module_ops {
- enum module_priority priority;
- enum module_state initalized;
- const char *name;
- int (*init) (void *data);
- int (*exit) (void *data);
- int (*restore) (void *data);
- int (*check_runtime_support) (void *data);
- int (*control) (void *data);
- int (*status) (void *data);
- int (*dump) (FILE *fp, int mode, void *dump_data);
- void *dump_data;
-};
-
-void add_module(const struct module_ops *module);
-void remove_module(const struct module_ops *module);
-
-void modules_check_runtime_support(void *data);
-void modules_init(void *data);
-void modules_init_late(void *data);
-void modules_exit(void *data);
-void modules_restore(void *data);
-void modules_dump(FILE *fp, int mode);
-int modules_add_methods(void);
-
-const struct module_ops *find_module(const char *name);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __MODULE_HANDLE_H__ */
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file module-data.c
+ * @desc Module data features
+ **/
+
+#include "macro.h"
+#include "module-data.h"
+#include "trace.h"
+
+static struct shared_modules_data modules_data;
+
+struct shared_modules_data *get_shared_modules_data(void)
+{
+ return &modules_data;
+}
+
+void init_modules_arg(struct daemon_arg *darg)
+{
+ ret_msg_if(darg == NULL,
+ "Init modules argument failed\n");
+ modules_data.darg = darg;
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file module-data.h
+ * @desc Module data features
+ **/
+
+#ifndef __MODULE_DATA_HANDLE_H__
+#define __MODULE_DATA_HANDLE_H__
+
+#include "init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct swap_module_data {
+ int swap_state; /* swap SWAP_ON/SWAP_OFF */
+};
+
+struct shared_modules_data {
+ struct daemon_arg *darg;
+ struct swap_module_data swap_data;
+};
+
+struct shared_modules_data *get_shared_modules_data(void);
+
+void init_modules_arg(struct daemon_arg *darg);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MODULE_DATA_HANDLE_H__ */
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file module.c
+ * @desc Module helper functions
+ **/
+
+#include "macro.h"
+#include "module.h"
+#include "resourced.h"
+#include "trace.h"
+#include "dbus-handler.h"
+
+#include <glib.h>
+
+static GSList *modules_list;
+
+void add_module(const struct module_ops *module)
+{
+ ret_msg_if(!module, "Invalid module handler\n");
+
+ if (module->priority == MODULE_PRIORITY_EARLY)
+ modules_list = g_slist_prepend(modules_list, (gpointer)module);
+ else
+ modules_list = g_slist_append(modules_list, (gpointer)module);
+}
+
+void remove_module(const struct module_ops *module)
+{
+ modules_list = g_slist_remove(modules_list, (gpointer)module);
+}
+
+const struct module_ops *find_module(const char *name)
+{
+ GSList *iter;
+ const struct module_ops *module;
+
+ gslist_for_each_item(iter, modules_list) {
+ module = (struct module_ops *)iter->data;
+ if (!strncmp(module->name, name, strlen(module->name) + 1) &&
+ (module->initalized == MODULE_INITIALIZED))
+ return module;
+ }
+ return NULL;
+}
+
+void modules_check_runtime_support(void UNUSED *data)
+{
+ GSList *iter, *next;
+ const struct module_ops *module;
+ int ret;
+
+ gslist_for_each_safe(modules_list, iter, next, module) {
+ module = (const struct module_ops *)iter->data;
+ _D("check runtime support [%s] module\n", module->name);
+
+ if (!module->check_runtime_support)
+ continue;
+
+ ret = module->check_runtime_support((void *)module);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _I("%s module is not supported in this environment", module->name);
+ remove_module(module);
+ continue;
+ }
+ }
+}
+
+static void module_initcall_level(void *data, int priority)
+{
+ GSList *iter;
+ struct module_ops *module;
+ int ret;
+
+ gslist_for_each_item(iter, modules_list) {
+ module = (struct module_ops *)iter->data;
+
+ assert(module);
+
+ if (module->priority < priority)
+ continue;
+
+ if (module->initalized != MODULE_NONINITIALIZED)
+ continue;
+
+ if (!module->init)
+ continue;
+
+ ret = module->init(data);
+ /* Module disabled on runtime or just failed to start. */
+ if (ret < 0) {
+ module->initalized = MODULE_DROPPED;
+ _I("Fail to initialize [%s] module, dropped.", module->name);
+ continue;
+ }
+
+ module->initalized = MODULE_INITIALIZED;
+ }
+}
+
+void modules_init(void *data)
+{
+ module_initcall_level(data, MODULE_PRIORITY_HIGH);
+}
+
+void modules_init_late(void *data)
+{
+ module_initcall_level(data, MODULE_PRIORITY_NORMAL);
+ module_initcall_level(data, MODULE_PRIORITY_LATE);
+}
+
+void modules_exit(void *data)
+{
+ GSList *iter;
+ struct module_ops *module;
+ int ret;
+
+ gslist_for_each_item(iter, modules_list) {
+ module = (struct module_ops *)iter->data;
+ if (module->exit && (module->initalized == MODULE_INITIALIZED)) {
+ module->initalized = MODULE_NONINITIALIZED;
+ ret = module->exit(data);
+ if (ret < 0)
+ _E("Fail to deinitialize [%s] module\n", module->name);
+ else
+ _D("Deinitialize [%s] module\n", module->name);
+ }
+ }
+ g_slist_free(modules_list);
+ modules_list = NULL;
+}
+
+void modules_restore(void *data)
+{
+ struct module_ops *module;
+ GSList *iter;
+ int ret;
+
+ gslist_for_each_item(iter, modules_list) {
+ module = (struct module_ops *)iter->data;
+
+ assert(module);
+
+ if (module->initalized != MODULE_INITIALIZED)
+ continue;
+
+ if (!module->restore)
+ continue;
+
+ ret = module->restore(data);
+ if (ret < 0) {
+ _E("Fail to restore [%s] module", module->name);
+ continue;
+ }
+
+ _I("Restored [%s] module", module->name);
+ }
+}
+
+void modules_dump(FILE *fp, int mode)
+{
+ GSList *iter;
+ const struct module_ops *module;
+
+ gslist_for_each_item(iter, modules_list) {
+ module = (struct module_ops *)iter->data;
+ if (module->initalized != MODULE_INITIALIZED)
+ continue;
+
+ _D("dump [%s] module\n", module->name);
+ if (module->dump)
+ module->dump(fp, mode, module->dump_data);
+ }
+}
+
+static void dbus_list_active_modules_handler(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ struct module_ops *module;
+ GSList *list_iter;
+ GVariantBuilder builder, *sub_builder;
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ sub_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+
+ gslist_for_each_item(list_iter, modules_list) {
+ module = (struct module_ops *)list_iter->data;
+ if (module->initalized != MODULE_INITIALIZED)
+ continue;
+
+ g_variant_builder_add(sub_builder, "s", module->name);
+ }
+ g_variant_builder_add_value(&builder, g_variant_new("as", sub_builder));
+ g_variant_builder_unref(sub_builder);
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_builder_end(&builder));
+}
+
+static const char resourced_module_methods_xml[] =
+"<node>"
+" <interface name ='"RESOURCED_INTERFACE_NAME"'>"
+" <method name='ListActiveModuels'>"
+" <arg type='as' name='ActiveModules' direction='out'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+static struct d_bus_method resourced_module_methods[] = {
+ { "ListActiveModuels", dbus_list_active_modules_handler },
+ /* Add methods here */
+};
+
+int modules_add_methods(void)
+{
+ return d_bus_register_methods(RESOURCED_OBJECT_PATH, resourced_module_methods_xml,
+ resourced_module_methods, ARRAY_SIZE(resourced_module_methods));
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file module.h
+ * @desc Module helper functions
+ **/
+
+#ifndef __MODULE_HANDLE_H__
+#define __MODULE_HANDLE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief module_priority is used to initialization order of each
+ * modules.
+ */
+enum module_priority {
+ /**
+ * MODULE_PRIORITY_LATE is default priority of modules.
+ * These modules are initialized after other modules
+ * are initialized.
+ */
+ MODULE_PRIORITY_LATE = 0,
+
+ /**
+ * MODULE_PRIORITY_NORMAL modules are initialized after
+ * booting is done.
+ */
+ MODULE_PRIORITY_NORMAL,
+
+ /**
+ * MODULE_PRIORITY_HIGH modules are initialized
+ * as soon as resourced is started.
+ */
+ MODULE_PRIORITY_HIGH,
+
+ /**
+ * MODULE_PRIORITY_EARLY modules are initialized
+ * before MODULE_PRIORITY_NORMAL modules.
+ */
+ MODULE_PRIORITY_EARLY,
+};
+
+enum module_state {
+ MODULE_NONINITIALIZED,
+ MODULE_INITIALIZED,
+ MODULE_DROPPED,
+};
+
+/*
+ * Each module must have at least those field defined:
+ * .priority (default : MODULE_PRIORITY_LATE)
+ * .name (name of the module, as string)
+ * .init (must return RESOURCED_ERROR_NONE on success)
+ * .exit (must return RESOURCED_ERROR_NONE on success)
+ * .restore (optional handler to calls on resourced is
+ * restarted. must return RESOURCED_ERROR_NONE on success))
+ *
+ * All rest of callbacks are optional for module to work.
+ *
+ */
+struct module_ops {
+ enum module_priority priority;
+ enum module_state initalized;
+ const char *name;
+ int (*init) (void *data);
+ int (*exit) (void *data);
+ int (*restore) (void *data);
+ int (*check_runtime_support) (void *data);
+ int (*control) (void *data);
+ int (*status) (void *data);
+ int (*dump) (FILE *fp, int mode, void *dump_data);
+ void *dump_data;
+};
+
+void add_module(const struct module_ops *module);
+void remove_module(const struct module_ops *module);
+
+void modules_check_runtime_support(void *data);
+void modules_init(void *data);
+void modules_init_late(void *data);
+void modules_exit(void *data);
+void modules_restore(void *data);
+void modules_dump(FILE *fp, int mode);
+int modules_add_methods(void);
+
+const struct module_ops *find_module(const char *name);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MODULE_HANDLE_H__ */
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/**
- * @file procfs.c
- *
- * @desc communicate with procfs in resourced
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include "resourced.h"
-#include "trace.h"
-#include "macro.h"
-#include "util.h"
-#include "procfs.h"
-#include "proc-common.h"
-#include "memory-cgroup.h"
-#include "module.h"
-#include "file-helper.h"
-#include "swap-common.h"
-#include "smaps.h"
-#include "notifier.h"
-#include "lowmem-handler.h"
-
-#define MEM_SWAP_RATIO 0.5
-
-static struct sys_node_table sys_node_tables[] = {
- { SYS_VM_SHRINK_MEMORY, "/proc/sys/vm/shrink_memory", 1, 1 },
- { SYS_VM_COMPACT_MEMORY, "/proc/sys/vm/compact_memory", 1, 1 },
- { },
-};
-
-int proc_get_cmdline(pid_t pid, char *cmdline, size_t maxcmdline)
-{
- assert(cmdline);
- assert(maxcmdline > 0);
-
- char buf[PROC_BUF_MAX];
- char cmdline_buf[PROC_NAME_MAX];
- char *filename;
- FILE *fp;
-
- if (pid == 0)
- snprintf(buf, sizeof(buf), "/proc/cmdline");
- else
- snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
-
- fp = fopen(buf, "r");
- if (fp == NULL)
- return RESOURCED_ERROR_FAIL;
-
- if (fgets(cmdline_buf, sizeof cmdline_buf, fp) == NULL) {
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- fclose(fp);
-
- filename = strrchr(cmdline_buf, '/');
- if (filename == NULL)
- filename = cmdline_buf;
- else
- filename = filename + 1;
-
- strncpy(cmdline, filename, maxcmdline - 1);
- cmdline[maxcmdline - 1] = '\0';
-
- return RESOURCED_ERROR_NONE;
-}
-
-pid_t find_pid_from_cmdline(char *cmdline)
-{
- pid_t pid = -1, foundpid = -1;
- int ret = 0;
- DIR *dp;
- struct dirent *dentry;
- char appname[PROC_NAME_MAX];
-
- dp = opendir("/proc");
- if (!dp) {
- _E("BACKGRD MANAGE : fail to open /proc");
- return RESOURCED_ERROR_FAIL;
- }
- while ((dentry = readdir(dp))) {
- if (!isdigit(dentry->d_name[0]))
- continue;
-
- pid = atoi(dentry->d_name);
- if (!pid)
- continue;
- ret = proc_get_cmdline(pid, appname, sizeof appname);
- if (ret == RESOURCED_ERROR_NONE) {
- if (!strncmp(cmdline, appname, strlen(appname)+1)) {
- foundpid = pid;
- break;
- }
- }
- }
- closedir(dp);
- return foundpid;
-}
-
-int proc_get_oom_score_adj(int pid, int *oom_score_adj)
-{
- char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
- FILE *fp = NULL;
-
- if (pid <= 0)
- return RESOURCED_ERROR_FAIL;
-
- snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
- fp = fopen(buf, "r");
-
- if (fp == NULL) {
- _E("fopen %s failed", buf);
- return RESOURCED_ERROR_FAIL;
- }
- if (fgets(buf, sizeof(buf), fp) == NULL) {
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- (*oom_score_adj) = atoi(buf);
- fclose(fp);
- return RESOURCED_ERROR_NONE;
-}
-
-int proc_set_oom_score_adj(int pid, int oom_score_adj, struct proc_app_info *pai)
-{
- FILE *fp;
- struct lowmem_control_data lowmem_data;
- char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
-
- snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
- fp = fopen(buf, "r+");
- if (fp == NULL)
- return RESOURCED_ERROR_FAIL;
- if (fgets(buf, sizeof(buf), fp) == NULL) {
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- fprintf(fp, "%d", oom_score_adj);
- fclose(fp);
-
- if (oom_score_adj >= OOMADJ_SU) {
- lowmem_data.control_type = LOWMEM_MOVE_CGROUP;
- lowmem_data.pid = pid;
- lowmem_data.oom_score_adj = oom_score_adj;
- lowmem_data.pai = pai;
- resourced_notify(RESOURCED_NOTIFIER_MEM_CONTROL, &lowmem_data);
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-int proc_get_label(pid_t pid, char *label)
-{
- char buf[PROC_BUF_MAX];
- FILE *fp;
-
- snprintf(buf, sizeof(buf), "/proc/%d/attr/current", pid);
- fp = fopen(buf, "r");
- if (fp == NULL)
- return RESOURCED_ERROR_FAIL;
-
- if (fgets(label, PROC_NAME_MAX-1, fp) == NULL) {
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- fclose(fp);
- return RESOURCED_ERROR_NONE;
-}
-
-int proc_get_mem_status(pid_t pid, unsigned int *vmswap_kb, unsigned int *vmrss_kb)
-{
- char filename[PROC_BUF_MAX];
- _cleanup_fclose_ FILE *fp = NULL;
- unsigned int swap_kb = 0, rss_kb = 0;
-
- snprintf(filename, PROC_BUF_MAX, "/proc/%d/status", pid);
- fp = fopen(filename, "r");
- if (!fp)
- return RESOURCED_ERROR_FAIL;
-
- if (vmrss_kb != NULL) {
- while (fgets(filename, sizeof(filename), fp)) {
- /* Skip the lines, until first match */
- if (!strstart_with(filename, "VmRSS:"))
- continue;
-
- /* Read RSS value and end this loop. */
- if (sscanf(filename, "VmRSS: %u kB", &rss_kb) == 1)
- break;
-
- return RESOURCED_ERROR_NO_DATA;
- }
- *vmrss_kb = rss_kb;
- }
-
- if (vmswap_kb != NULL) {
- /* Interate over rest of Vm* values */
- while (fgets(filename, sizeof(filename), fp)) {
- /* Read VmSwap and return with positive result */
- if (sscanf(filename, "VmSwap: %d kB", &swap_kb) == 1)
- break;
-
- /* End of file before VmSwap read, return with error */
- if (feof(fp))
- return RESOURCED_ERROR_NO_DATA;
- }
- *vmswap_kb = swap_kb;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-int proc_get_uss(pid_t pid, unsigned int *uss)
-{
- _cleanup_smaps_free_ struct smaps *smaps = NULL;
- int ret;
-
- *uss = 0;
-
- /*
- * USS memory usage is number of KB accounted to a process
- * where only private (non-shared) data are accounted.
- *
- * USS provides the value how much memory will be freed after
- * termination of process.
- */
- ret = smaps_get(pid, &smaps,
- (SMAPS_MASK_PRIVATE_CLEAN | SMAPS_MASK_PRIVATE_DIRTY));
-
- if (ret < 0) {
- _E("Error while reading smaps or totmaps for pid %d", pid);
- return RESOURCED_ERROR_FAIL;
- }
-
- *uss += smaps->sum[SMAPS_ID_PRIVATE_CLEAN];
- *uss += smaps->sum[SMAPS_ID_PRIVATE_DIRTY];
-
- return RESOURCED_ERROR_NONE;
-}
-
-int proc_get_zram_usage(pid_t pid, unsigned int *usage_kb)
-{
- int ret;
- struct meminfo mi;
- static unsigned int swap_total_kb = 0;
- unsigned int proc_swap_usage_kb;
- unsigned long long zram_usage_bytes;
-
- /* Read total swap size just once and cache it */
- if (!swap_total_kb) {
- ret = proc_get_meminfo(&mi, MEMINFO_MASK_SWAP_TOTAL);
- if (ret < 0) {
- _E("Failed to get %s: %m",
- meminfo_id_to_string(MEMINFO_ID_SWAP_TOTAL));
- return RESOURCED_ERROR_FAIL;
- }
- swap_total_kb = mi.value[MEMINFO_ID_SWAP_TOTAL];
- }
-
- /* Read usage of Swap (VmSwap) of interested process */
- ret = proc_get_mem_status(pid, &proc_swap_usage_kb, NULL);
- if (ret != RESOURCED_ERROR_NONE)
- return ret;
-
- /* Read current total memory usage of zram device */
- ret = fread_nth_ulonglong(SWAP_ZRAM_SYSFILE"mm_stat", 2, &zram_usage_bytes);
- if (ret == -ENOENT) {
- ret = fread_ulonglong(SWAP_ZRAM_SYSFILE"mem_used_total", &zram_usage_bytes);
- }
-
- if (ret < 0)
- return RESOURCED_ERROR_FAIL;
-
- /*
- * Calculate aproximated value of zram usage for selected process
- * by formula: proc_zram_usage = ( VmSwap x ZramMemoryUsage )/SwapTotal
- */
- *usage_kb = (int)((float)proc_swap_usage_kb * BYTE_TO_KBYTE(zram_usage_bytes) / swap_total_kb);
-
- return RESOURCED_ERROR_NONE;
-}
-
-int proc_get_approx_mem_usage(pid_t pid, unsigned int *usage_kb)
-{
- int ret;
- unsigned long resident_pages = 0, shared_pages = 0;
- char filename[PROC_BUF_MAX];
- _cleanup_fclose_ FILE *fp = NULL;
-
- snprintf(filename, PROC_BUF_MAX, "/proc/%d/statm", pid);
- fp = fopen(filename, "r");
- if (!fp)
- return RESOURCED_ERROR_FAIL;
-
- /*
- * For quick read, open code by putting numbers directly
- * expected format is
- * seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
- * size, resident, shared, text, data);
- */
- ret = fscanf(fp, "%*s %lu %lu %*s %*s %*s %*s\n", &resident_pages, &shared_pages);
- if (ret < 0)
- return RESOURCED_ERROR_FAIL;
-
- if (resident_pages < shared_pages) {
- _E("# resident page should be larger than or equal to # shared page");
- return RESOURCED_ERROR_FAIL;
- }
-
- /*
- * The value resident - shared is mostly similar to Uss.
- */
- *usage_kb = BYTE_TO_KBYTE((unsigned long long)(resident_pages - shared_pages) << PAGE_SHIFT);
- return RESOURCED_ERROR_NONE;
-}
-
-/**
- * @desc get total memory usage from VmSwap and VmRSS.
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_mem_usage(pid_t pid, unsigned int *usage)
-{
- int ret;
- unsigned int vmswap = 0, total = 0;
-
- ret = proc_get_approx_mem_usage(pid, &total);
- if (ret < 0) {
- _E("Failed to get usage : %d", pid);
- return ret;
- }
-
- if (swap_get_state() == SWAP_ON) {
- ret = proc_get_mem_status(pid, &vmswap, NULL);
- if (ret != RESOURCED_ERROR_NONE)
- goto out;
-
- total += vmswap;
- }
-out:
- *usage = total;
- return RESOURCED_ERROR_NONE;
-}
-
-/**
- * @desc get how much ram is used in each application
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_ram_usage(pid_t pid, unsigned int *usage_kb)
-{
- int ret;
- unsigned int vmswap_kb = 0, total_kb = 0;
-
- ret = proc_get_approx_mem_usage(pid, &total_kb);
- if (ret < 0) {
- _E("Failed to get usage : %d", pid);
- return ret;
- }
-
- if (swap_get_state() == SWAP_ON) {
- ret = proc_get_mem_status(pid, &vmswap_kb, NULL);
- if (ret != RESOURCED_ERROR_NONE)
- goto out;
-
- /*
- * If it is necessary to know real ram size about each application,
- * it should consider compression ratio.
- */
- vmswap_kb *= MEM_SWAP_RATIO;
- total_kb += vmswap_kb;
- }
-out:
- *usage_kb = total_kb;
- return RESOURCED_ERROR_NONE;
-}
-
-unsigned int proc_get_mem_available(void)
-{
- struct meminfo mi;
- int ret;
-
- ret = proc_get_meminfo(&mi, MEMINFO_MASK_MEM_AVAILABLE);
- if (ret < 0) {
- _E("Failed to get %s: %m",
- meminfo_id_to_string(MEMINFO_ID_MEM_AVAILABLE));
- return 0;
- }
-
- return KBYTE_TO_MBYTE(mi.value[MEMINFO_ID_MEM_AVAILABLE]);
-}
-
-unsigned int proc_get_swap_free(void)
-{
- struct meminfo mi;
- int ret;
-
- ret = proc_get_meminfo(&mi, MEMINFO_MASK_SWAP_FREE);
- if (ret < 0) {
- _E("Failed to get %s: %m",
- meminfo_id_to_string(MEMINFO_ID_SWAP_FREE));
- return 0;
- }
-
- return mi.value[MEMINFO_ID_SWAP_FREE];
-}
-
-unsigned int proc_get_swap_total(void)
-{
- struct meminfo mi;
- int ret;
-
- ret = proc_get_meminfo(&mi, MEMINFO_MASK_SWAP_TOTAL);
- if (ret < 0) {
- _E("Failed to get %s: %m",
- meminfo_id_to_string(MEMINFO_ID_SWAP_TOTAL));
- return 0;
- }
-
- return mi.value[MEMINFO_ID_SWAP_TOTAL];
-}
-
-int proc_get_cpu_time(pid_t pid, unsigned long *utime,
- unsigned long *stime, unsigned long *starttime)
-{
- char proc_path[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
- _cleanup_fclose_ FILE *fp = NULL;
-
- assert(utime != NULL);
- assert(stime != NULL);
-
- snprintf(proc_path, sizeof(proc_path), PROC_STAT_PATH, pid);
- fp = fopen(proc_path, "r");
- if (fp == NULL)
- return RESOURCED_ERROR_FAIL;
-
- if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s") < 0)
- return RESOURCED_ERROR_FAIL;
-
- if (fscanf(fp, "%lu %lu", utime, stime) < 1)
- return RESOURCED_ERROR_FAIL;
-
- if (fscanf(fp, "%*s %*s %*s %*s %*s %*s") < 0)
- return RESOURCED_ERROR_FAIL;
-
- if (fscanf(fp, "%lu", starttime) < 1)
- return RESOURCED_ERROR_FAIL;
-
- return RESOURCED_ERROR_NONE;
-}
-
-unsigned int proc_get_cpu_number(void)
-{
- char buf[PATH_MAX];
- FILE *fp;
- int cpu = 0;
-
- fp = fopen("/proc/cpuinfo", "r");
-
- if (!fp) {
- _E("/proc/cpuinfo open failed");
- return RESOURCED_ERROR_FAIL;
- }
-
- while (fgets(buf, PATH_MAX, fp) != NULL) {
- if (!strncmp(buf, "processor", 9))
- cpu++;
- }
-
- fclose(fp);
- return cpu;
-}
-
-int proc_get_exepath(pid_t pid, char *buf, int len)
-{
- char path[PROC_BUF_MAX];
- int ret = 0;
-
- snprintf(path, sizeof(path), "/proc/%d/exe", pid);
- ret = readlink(path, buf, len-1);
- if (ret > 0)
- buf[ret] = '\0';
- else
- buf[0] = '\0';
- return RESOURCED_ERROR_NONE;
-}
-
-static int proc_get_data(char *path, char *buf, int len)
-{
- _cleanup_close_ int fd = -1;
- int ret;
-
- fd = open(path, O_RDONLY);
- if (fd < 0)
- return RESOURCED_ERROR_FAIL;
-
- ret = read(fd, buf, len-1);
- if (ret < 0) {
- buf[0] = '\0';
- return RESOURCED_ERROR_FAIL;
- }
- buf[ret] = '\0';
- return RESOURCED_ERROR_NONE;
-}
-
-int proc_get_raw_cmdline(pid_t pid, char *buf, int len)
-{
- char path[PROC_BUF_MAX];
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- return proc_get_data(path, buf, len);
-}
-
-int proc_get_stat(pid_t pid, char *buf, int len)
-{
- char path[PROC_BUF_MAX];
- snprintf(path, sizeof(path), "/proc/%d/stat", pid);
- return proc_get_data(path, buf, len);
-}
-
-int proc_get_status(pid_t pid, char *buf, int len)
-{
- char path[PROC_BUF_MAX];
- snprintf(path, sizeof(path), "/proc/%d/status", pid);
- return proc_get_data(path, buf, len);
-}
-
-int proc_sys_node_trigger(enum sys_node_id sys_node_id)
-{
- FILE *fp = NULL;
-
- if (sys_node_id >= ARRAY_SIZE(sys_node_tables)) {
- _E("sys_node_id[%d] is out of range.\n", sys_node_id);
- return RESOURCED_ERROR_FAIL;
- }
- if (!sys_node_tables[sys_node_id].valid) {
- _E("sys_node_id[%d] is not valid.\n", sys_node_id);
- return RESOURCED_ERROR_FAIL;
- }
-
- /* open and check if the path exists, else return fail */
- fp = fopen(sys_node_tables[sys_node_id].path, "w");
- if (fp == NULL) {
- _E("Failed to open %s: %m\n",
- sys_node_tables[sys_node_id].path);
- sys_node_tables[sys_node_id].valid = 0;
- return RESOURCED_ERROR_FAIL;
- }
- fputc(sys_node_tables[sys_node_id].value, fp);
- fclose(fp);
- return RESOURCED_ERROR_NONE;
-}
-
-static const char* const meminfo_string_lookup[MEMINFO_ID_MAX] = {
- [MEMINFO_ID_MEM_TOTAL] = "MemTotal",
- [MEMINFO_ID_MEM_FREE] = "MemFree",
- [MEMINFO_ID_MEM_AVAILABLE] = "MemAvailable",
- [MEMINFO_ID_BUFFERS] = "Buffers",
- [MEMINFO_ID_CACHED] = "Cached",
- [MEMINFO_ID_SWAP_CACHED] = "SwapCached",
- [MEMINFO_ID_ACTIVE] = "Active",
- [MEMINFO_ID_INACTIVE] = "Inactive",
- [MEMINFO_ID_ACTIVE_ANON] = "Active(anon)",
- [MEMINFO_ID_INACTIVE_ANON] = "Inactive(anon)",
- [MEMINFO_ID_ACTIVE_FILE] = "Active(file)",
- [MEMINFO_ID_INACTIVE_FILE] = "Inactive(file)",
- [MEMINFO_ID_UNEVICTABLE] = "Unevictable",
- [MEMINFO_ID_MLOCKED] = "Mlocked",
- [MEMINFO_ID_HIGH_TOTAL] = "HighTotal",
- [MEMINFO_ID_HIGH_FREE] = "HighFree",
- [MEMINFO_ID_LOW_TOTAL] = "LowTotal",
- [MEMINFO_ID_LOW_FREE] = "LowFree",
- [MEMINFO_ID_SWAP_TOTAL] = "SwapTotal",
- [MEMINFO_ID_SWAP_FREE] = "SwapFree",
- [MEMINFO_ID_DIRTY] = "Dirty",
- [MEMINFO_ID_WRITEBACK] = "Writeback",
- [MEMINFO_ID_ANON_PAGES] = "AnonPages",
- [MEMINFO_ID_MAPPED] = "Mapped",
- [MEMINFO_ID_SHMEM] = "Shmem",
- [MEMINFO_ID_SLAB] = "Slab",
- [MEMINFO_ID_SRECLAIMABLE] = "SReclaimable",
- [MEMINFO_ID_SUNRECLAIM] = "SUnreclaim",
- [MEMINFO_ID_KERNEL_STACK] = "KernelStack",
- [MEMINFO_ID_PAGE_TABLES] = "PageTables",
- [MEMINFO_ID_NFS_UNSTABLE] = "NFS_Unstable",
- [MEMINFO_ID_BOUNCE] = "Bounce",
- [MEMINFO_ID_WRITEBACK_TMP] = "WritebackTmp",
- [MEMINFO_ID_COMMIT_LIMIT] = "CommitLimit",
- [MEMINFO_ID_COMMITTED_AS] = "Committed_AS",
- [MEMINFO_ID_VMALLOC_TOTAL] = "VmallocTotal",
- [MEMINFO_ID_VMALLOC_USED] = "VmallocUsed",
- [MEMINFO_ID_VMALLOC_CHUNK] = "VmallocChunk",
-};
-
-const char *meminfo_id_to_string(enum meminfo_id id)
-{
- assert(id >= 0 && id < MEMINFO_ID_MAX);
-
- return meminfo_string_lookup[id];
-}
-
-int proc_get_meminfo(struct meminfo *mi, unsigned long long mask)
-{
- _cleanup_fclose_ FILE *f = NULL;
- unsigned long long remain_mask = mask;
- char buf[LINE_MAX];
-
- assert(mi);
-
- memset(mi, 0x0, sizeof(struct meminfo));
-
- f = fopen("/proc/meminfo", "r");
- if (!f) {
- _E("Failed to read /proc/meminfo");
- return -errno;
- }
-
- if (remain_mask & MEMINFO_MASK_MEM_AVAILABLE)
- remain_mask |= (MEMINFO_MASK_MEM_FREE |
- MEMINFO_MASK_CACHED);
-
- while (remain_mask) {
- _cleanup_free_ char *k = NULL;
- unsigned int v = 0;
- enum meminfo_id id;
- size_t l;
-
- if (!fgets(buf, sizeof(buf), f)) {
- if (ferror(f))
- return -errno;
- break;
- }
-
- l = strcspn(buf, ":");
- if (!l)
- break;
-
- k = strndup(buf, l);
- if (!k)
- return -errno;
-
- id = meminfo_string_to_id(k);
- if (id < 0 || id >= MEMINFO_ID_MAX)
- continue;
-
- if (!(remain_mask & (1ULL << id)))
- continue;
-
- remain_mask &= ~((1ULL << id));
-
- if (sscanf(buf + l + 1, "%d", &v) != 1)
- break;
-
- mi->value[id] = v;
- }
-
- if (remain_mask & MEMINFO_MASK_MEM_AVAILABLE) {
- mi->value[MEMINFO_ID_MEM_AVAILABLE] =
- mi->value[MEMINFO_ID_MEM_FREE]
- + mi->value[MEMINFO_ID_CACHED];
-
- remain_mask &= ~MEMINFO_MASK_MEM_AVAILABLE;
- }
-
- if (remain_mask) {
- enum meminfo_id i;
-
- for (i = 0; i < MEMINFO_ID_MAX; i++)
- if (remain_mask & (1ULL << i))
- _E("Failed to get meminfo: '%s'",
- meminfo_id_to_string(i));
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int parse_spanned_pages(const char *s, regmatch_t *match,
- unsigned int parse_tag, void *data)
-{
- char *e;
- unsigned long v;
- unsigned long *parse_v = (unsigned long *)data;
-
- v = strtoul(s + match[1].rm_so, &e, 0);
- *parse_v += v;
-
- return 0;
-}
-
-int proc_get_ram_total(unsigned int *total_kb)
-{
- unsigned long total_spanned = 0;
- static unsigned int total_ram_kb = 0;
- int ret;
- const struct parse_arg args[] = {
- PARSE_TAG("spanned[[:blank:]]+([0-9]+)\n",
- parse_spanned_pages, SPANNED),
- PARSE_TAG_EMPTY(),
- };
-
- if (total_ram_kb > 0) {
- *total_kb = total_ram_kb;
- return RESOURCED_ERROR_NONE;
- }
-
- ret = proc_parse_zoneinfo(args, &total_spanned);
- if (ret != RESOURCED_ERROR_NONE)
- return RESOURCED_ERROR_NO_DATA;
-
- total_ram_kb = (unsigned int)BYTE_TO_KBYTE((unsigned long long)total_spanned << PAGE_SHIFT);
- *total_kb = total_ram_kb;
-
- return RESOURCED_ERROR_NONE;
-}
-
-static inline char *proc_skip_blanks(const char *s)
-{
- while (s && (isblank(*s) || !isalnum(*s)))
- ++s;
- return (char*)s;
-}
-
-#define PROC_MAX_REG_MATCH 6
-
-static int proc_find_match(char *s, const struct parse_arg *parse,
- void *data, size_t *parsed)
-{
- regex_t regex;
- regmatch_t match[PROC_MAX_REG_MATCH];
- int result;
-
- if (!s || !(*s != '\0'))
- return -EINVAL;
-
- if (!parse->callback)
- return 0;
-
- *parsed = 0;
-
- result = regcomp(®ex, parse->re_exp, REG_EXTENDED);
- if (!result) {
- result = regexec(®ex, s, ARRAY_SIZE(match), match, 0);
- if (!result) {
- regmatch_t *m = match;
-
- result = parse->callback(s, match, parse->tag, data);
- if (result)
- goto leave;
- while ((m - match) < PROC_MAX_REG_MATCH &&
- m->rm_so >= 0 && m->rm_eo > 0)
- ++m;
-
- *parsed = m > match ? (--m)->rm_eo + 1 : 0;
- }
-leave:
- regfree(®ex);
- }
- return result;
-}
-
-/**
- * @brief Rather basic parser that relies on provided arguments,
- * specifying the actual expression to look for.
- * Note that it does not make any assumptions as to how
- * the input to be parsed is actual formated and what is the
- * layout of the information held within it.
- * - mind it as badly specified arguments might result in a failure
- * to identify potential match or finding a match but not one that
- * has been expected. It is up to the caller to perform
- * the actual formatting of data.
- * Parsing is done per line with possible multiple regexes.
- * @return Returns number of found matches against supplied parse arguments
- */
-static int proc_parse_single(const char *buffer,
- const struct parse_arg *parse_args,
- void *data)
-{
- char *s = (char*)buffer;
- size_t size;
- unsigned int match = 0;
-
- while (s && *s != '\n' && *s != '\0') {
- const struct parse_arg *p = parse_args;
-
- size = 0;
- s = proc_skip_blanks(s);
-
- while (proc_find_match(s, p, data, &size))
- ++p;
-
- if (!size)
- break;
- s += size;
- ++match;
- }
- return match;
-}
-
-/**
- * @brief Simplified procfs parser
- *
- * Reads the procfs entry line by line triggering regex match
- * function for each supplied argument.
- * Note: The set of arguments should end with an empty one.
- *
- * @return returns 0 upon successfully calling the actual parsing
- * procedure at least once, error code otherwise.
- * Note: it is up to the caller to properly handle
- * callbacks triggered upon each match found and to determine
- * if parsing itself actually succeeded.
- */
-int proc_parse_entry(const char *path, const struct parse_arg *parse_args,
- void *data)
-{
- char buf[LINE_MAX];
- _cleanup_fclose_ FILE *f = NULL;
-
- f = fopen(path, "r");
- if (!f)
- return -errno;
-
- while (fgets(buf, sizeof(buf), f))
- proc_parse_single(buf, parse_args, data);
- return ferror(f) ? -errno : 0;
-}
-
-int proc_get_uptime(unsigned long *uptime)
-{
- _cleanup_fclose_ FILE *fp = NULL;
- double stime;
-
- fp = fopen("/proc/uptime", "r");
- if (fp == NULL)
- return RESOURCED_ERROR_FAIL;
-
- if (fscanf(fp, "%lf %*s", &stime) < 0)
- return RESOURCED_ERROR_FAIL;
-
- *uptime = (unsigned long)stime;
- return RESOURCED_ERROR_NONE;
-}
-
-/**
- * @brief print simple memory info with rss and memtotal
- *
- * Reads the procfs about all process id and print RSS usage.
- * Note: If fp is valid, the result is written by desired file.
- * Otherwise, it printed message through dlog.
- */
-void proc_print_meninfo(FILE *fp)
-{
- _cleanup_closedir_ DIR *dir = NULL;
- struct dirent *de;
- pid_t pid, caller;
- char cmdline[PATH_MAX];
- _cleanup_fclose_ FILE *output_file = NULL;
- int oom_score_adj, ret;
- unsigned int rss, swap;
- struct meminfo mi;
- unsigned int free_kb = 0;
- unsigned int total_mem_kb = 0, available_kb = 0, used_kb;
- unsigned int swap_total_kb = 0, swap_free_kb = 0, swap_used_kb;
- unsigned long long zram_used_bytes;
-
- dir = opendir("/proc");
- if (dir == NULL) {
- _E("cannot read directory /proc.");
- return;
- }
-
- LOG_DUMP(fp, " PID RSS SWAP OOM_SCORE COMMAND\n");
-
- caller = getpid();
- while ((de = readdir(dir)) != NULL) {
- pid = atoi(de->d_name);
-
- /* exclude negative value which means string value and kernel thread */
- if (pid < 1 || pid == caller)
- continue;
-
- ret = proc_get_cmdline(pid, cmdline, sizeof cmdline);
- if (ret)
- continue;
-
- ret = proc_get_mem_status(pid, &swap, &rss);
- if (ret)
- continue;
-
- ret = proc_get_oom_score_adj(pid, &oom_score_adj);
- if (ret)
- continue;
-
- LOG_DUMP(fp, "%8d %8u %8u %8d %s\n",
- pid,
- rss,
- swap,
- oom_score_adj,
- cmdline);
-
- } /* end of while */
-
- ret = proc_get_meminfo(&mi,
- (MEMINFO_MASK_MEM_TOTAL |
- MEMINFO_MASK_MEM_FREE |
- MEMINFO_MASK_MEM_AVAILABLE |
- MEMINFO_MASK_CACHED |
- MEMINFO_MASK_SWAP_TOTAL |
- MEMINFO_MASK_SWAP_FREE));
- if (ret < 0) {
- _E("Failed to get meminfo");
- return;
- }
-
- total_mem_kb = mi.value[MEMINFO_ID_MEM_TOTAL];
- free_kb = mi.value[MEMINFO_ID_MEM_FREE];
- available_kb = mi.value[MEMINFO_ID_MEM_AVAILABLE];
- swap_total_kb = mi.value[MEMINFO_ID_SWAP_TOTAL];
- swap_free_kb = mi.value[MEMINFO_ID_SWAP_FREE];
-
- used_kb = total_mem_kb - available_kb;
- swap_used_kb = swap_total_kb - swap_free_kb;
-
- ret = fread_nth_ulonglong(SWAP_ZRAM_SYSFILE"mm_stat", 2, &zram_used_bytes);
- if (ret == -ENOENT) {
- ret = fread_ulonglong(SWAP_ZRAM_SYSFILE"mem_used_total", &zram_used_bytes);
- }
-
- if (ret != RESOURCED_ERROR_NONE)
- zram_used_bytes = 0;
-
- LOG_DUMP(fp, "====================================================================\n");
- LOG_DUMP(fp, "Total RAM size: \t%15d MB( %6d kB)\n",
- KBYTE_TO_MBYTE(total_mem_kb), total_mem_kb);
- LOG_DUMP(fp, "Used (Mem+Reclaimable): %15d MB( %6d kB)\n",
- KBYTE_TO_MBYTE(total_mem_kb - free_kb), total_mem_kb - free_kb);
- LOG_DUMP(fp, "Used (Mem+Swap): \t%15d MB( %6d kB)\n",
- KBYTE_TO_MBYTE(used_kb), used_kb);
- LOG_DUMP(fp, "Used (Mem): \t\t%15d MB( %6d kB)\n",
- KBYTE_TO_MBYTE(used_kb), used_kb);
- LOG_DUMP(fp, "Used (Swap): \t\t%15d MB( %6d kB)\n",
- KBYTE_TO_MBYTE(swap_used_kb), swap_used_kb);
- LOG_DUMP(fp, "Used (Zram block device): %13d MB( %6d kB)\n",
- (int)BYTE_TO_MBYTE(zram_used_bytes), (int)BYTE_TO_KBYTE(zram_used_bytes));
- LOG_DUMP(fp, "Mem Free:\t\t%15d MB( %6d kB)\n",
- KBYTE_TO_MBYTE(free_kb), free_kb);
- LOG_DUMP(fp, "Available (Free+Reclaimable):%10d MB( %6d kB)\n",
- KBYTE_TO_MBYTE(available_kb), available_kb);
- return;
-}
-
-int proc_get_buddyinfo(const char *zone, struct buddyinfo *bi)
-{
- _cleanup_fclose_ FILE *f = NULL;
- char buf[LINE_MAX];
-
- g_assert(zone);
- g_assert(bi);
-
- f = fopen("/proc/buddyinfo", "re");
- if (!f)
- return -errno;
-
- for (;;) {
- int n;
- char zonename[32] = { 0, };
-
- if (!fgets(buf, sizeof(buf), f)) {
- if (ferror(f))
- return -errno;
-
- break;
- }
-
- n = sscanf(buf, "Node %d, zone %31s %d %d %d %d %d %d %d %d %d %d %d",
- &bi->node,
- zonename,
- &bi->page[PAGE_4K],
- &bi->page[PAGE_8K],
- &bi->page[PAGE_16K],
- &bi->page[PAGE_32K],
- &bi->page[PAGE_64K],
- &bi->page[PAGE_128K],
- &bi->page[PAGE_256K],
- &bi->page[PAGE_512K],
- &bi->page[PAGE_1M],
- &bi->page[PAGE_2M],
- &bi->page[PAGE_4M]);
- if (n != 13)
- break;
-
- if (!streq(zone, zonename))
- continue;
-
- return 0;
- }
-
- return -ENODATA;
-}
-
-void proc_swap_free(struct proc_swaps *swap)
-{
- if (!swap)
- return;
-
- free(swap->filename);
- free(swap->type);
- free(swap);
-}
-
-void proc_swaps_free(struct proc_swaps **swaps)
-{
- int i;
-
- if (!swaps)
- return;
-
- for (i = 0; swaps[i]; i++)
- proc_swap_free(swaps[i]);
-
- free(swaps);
-}
-
-int proc_get_swaps(struct proc_swaps ***swaps)
-{
- _cleanup_proc_swaps_free_ struct proc_swaps **ss = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- char buf[LINE_MAX];
- size_t cnt = 0;
-
- assert(swaps);
- assert(!*swaps);
-
- f = fopen("/proc/swaps", "re");
- if (!f)
- return -errno;
-
- for (;;) {
- _cleanup_proc_swap_free_ struct proc_swaps *swap = NULL;
-
- if (!fgets(buf, sizeof(buf), f)) {
- if (ferror(f))
- return -errno;
-
- break;
- }
-
- swap = calloc(sizeof(struct proc_swaps), 1);
- if (!swap)
- return -ENOMEM;
-
- if (sscanf(buf, "%ms %ms %u %u %d",
- &swap->filename,
- &swap->type,
- &swap->size,
- &swap->used,
- &swap->priority) != 5)
- continue;
-
- ss = (struct proc_swaps **)realloc(ss, sizeof(struct proc_swaps *) * (cnt + 2));
- if (!ss)
- return -ENOMEM;
-
- ss[cnt++] = swap;
- ss[cnt] = NULL;
- swap = NULL;
- }
-
- *swaps = ss;
- ss = NULL;
-
- return cnt;
-}
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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 __PROCFS_H__
-#define __PROCFS_H__
-
-#include <resourced.h>
-#include <sys/types.h>
-#include <ctype.h>
-#include <regex.h>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#include "proc-common.h"
-
-#define OOMADJ_SU (0)
-#define OOMADJ_INIT (100)
-#define OOMADJ_FOREGRD_LOCKED (150)
-#define OOMADJ_FOREGRD_UNLOCKED (200)
-#define OOMADJ_BACKGRD_PERCEPTIBLE (230)
-#define OOMADJ_BACKGRD_LOCKED (250)
-#define OOMADJ_FAVORITE (270)
-#define OOMADJ_BACKGRD_UNLOCKED (300)
-#define OOMADJ_RECENTLY_USED (430)
-#define OOMADJ_BACKGRD_OLD (450)
-#define OOMADJ_APP_MAX (990)
-#define OOMADJ_APP_INCREASE (30)
-
-#define OOMADJ_FAVORITE_APP_MAX (OOMADJ_PREVIOUS_BACKGRD - OOMADJ_FAVORITE_APP_INCREASE)
-#define OOMADJ_FAVORITE_APP_INCREASE (1)
-
-/* OOMADJ_SERVICE_DEFAULT is default value for processes PROC_TYPE_SERVICE */
-#define OOMADJ_SERVICE_GAP (10)
-#define OOMADJ_SERVICE_DEFAULT (OOMADJ_BACKGRD_LOCKED - OOMADJ_SERVICE_GAP)
-
-/*
- * OOMADJ_PREVIOUS_DEFAULT is default value for processes that are
- * moved out from foreground cgroup ( >= OOMADJ_BACKGRD_PERCEPTIBLE)
- * but being in a state before background cgroup ( >= OOMADJ_BACKGRD_UNLOCKED).
- * In the middle it is possible to have process in favorite cgroup (== OOMADJ_FAVORITE).
- */
-#define OOMADJ_PREVIOUS_GAP (10)
-#define OOMADJ_PREVIOUS_DEFAULT (OOMADJ_BACKGRD_LOCKED - OOMADJ_PREVIOUS_GAP)
-#define OOMADJ_PREVIOUS_BACKGRD (OOMADJ_BACKGRD_UNLOCKED - OOMADJ_PREVIOUS_GAP)
-
-
-#define PROC_OOM_SCORE_ADJ_PATH "/proc/%d/oom_score_adj"
-#define PROC_STAT_PATH "/proc/%d/stat"
-#define PROC_ZONEINFO_PATH "/proc/zoneinfo"
-#define PROC_PAGETYPEINFO_PATH "/proc/pagetypeinfo"
-#define PROC_BUDDYINFO_PATH "/proc/buddyinfo"
-
-enum meminfo_id {
- MEMINFO_ID_INVALID = -1,
- MEMINFO_ID_MEM_TOTAL = 0,
- MEMINFO_ID_MEM_FREE,
- MEMINFO_ID_MEM_AVAILABLE,
- MEMINFO_ID_BUFFERS,
- MEMINFO_ID_CACHED,
- MEMINFO_ID_SWAP_CACHED,
- MEMINFO_ID_ACTIVE,
- MEMINFO_ID_INACTIVE,
- MEMINFO_ID_ACTIVE_ANON,
- MEMINFO_ID_INACTIVE_ANON,
- MEMINFO_ID_ACTIVE_FILE,
- MEMINFO_ID_INACTIVE_FILE,
- MEMINFO_ID_UNEVICTABLE,
- MEMINFO_ID_MLOCKED,
- MEMINFO_ID_HIGH_TOTAL,
- MEMINFO_ID_HIGH_FREE,
- MEMINFO_ID_LOW_TOTAL,
- MEMINFO_ID_LOW_FREE,
- MEMINFO_ID_SWAP_TOTAL,
- MEMINFO_ID_SWAP_FREE,
- MEMINFO_ID_DIRTY,
- MEMINFO_ID_WRITEBACK,
- MEMINFO_ID_ANON_PAGES,
- MEMINFO_ID_MAPPED,
- MEMINFO_ID_SHMEM,
- MEMINFO_ID_SLAB,
- MEMINFO_ID_SRECLAIMABLE,
- MEMINFO_ID_SUNRECLAIM,
- MEMINFO_ID_KERNEL_STACK,
- MEMINFO_ID_PAGE_TABLES,
- MEMINFO_ID_NFS_UNSTABLE,
- MEMINFO_ID_BOUNCE,
- MEMINFO_ID_WRITEBACK_TMP,
- MEMINFO_ID_COMMIT_LIMIT,
- MEMINFO_ID_COMMITTED_AS,
- MEMINFO_ID_VMALLOC_TOTAL,
- MEMINFO_ID_VMALLOC_USED,
- MEMINFO_ID_VMALLOC_CHUNK,
- MEMINFO_ID_MAX,
-};
-
-#define MEMINFO_MASK_MEM_TOTAL (1ULL << MEMINFO_ID_MEM_TOTAL)
-#define MEMINFO_MASK_MEM_FREE (1ULL << MEMINFO_ID_MEM_FREE)
-#define MEMINFO_MASK_MEM_AVAILABLE (1ULL << MEMINFO_ID_MEM_AVAILABLE)
-#define MEMINFO_MASK_BUFFERS (1ULL << MEMINFO_ID_BUFFERS)
-#define MEMINFO_MASK_CACHED (1ULL << MEMINFO_ID_CACHED)
-#define MEMINFO_MASK_SWAP_CACHED (1ULL << MEMINFO_ID_SWAP_CACHED)
-#define MEMINFO_MASK_ACTIVE (1ULL << MEMINFO_ID_ACTIVE)
-#define MEMINFO_MASK_INACTIVE (1ULL << MEMINFO_ID_INACTIVE)
-#define MEMINFO_MASK_ACTIVE_ANON (1ULL << MEMINFO_ID_ACTIVE_ANON)
-#define MEMINFO_MASK_INACTIVE_ANON (1ULL << MEMINFO_ID_INACTIVE_ANON)
-#define MEMINFO_MASK_ACTIVE_FILE (1ULL << MEMINFO_ID_ACTIVE_FILE)
-#define MEMINFO_MASK_INACTIVE_FILE (1ULL << MEMINFO_ID_INACTIVE_FILE)
-#define MEMINFO_MASK_UNEVICTABLE (1ULL << MEMINFO_ID_UNEVICTABLE)
-#define MEMINFO_MASK_MLOCKED (1ULL << MEMINFO_ID_MLOCKED)
-#define MEMINFO_MASK_HIGH_TOTAL (1ULL << MEMINFO_ID_HIGH_TOTAL)
-#define MEMINFO_MASK_HIGH_FREE (1ULL << MEMINFO_ID_HIGH_FREE)
-#define MEMINFO_MASK_LOW_TOTAL (1ULL << MEMINFO_ID_LOW_TOTAL)
-#define MEMINFO_MASK_LOW_FREE (1ULL << MEMINFO_ID_LOW_FREE)
-#define MEMINFO_MASK_SWAP_TOTAL (1ULL << MEMINFO_ID_SWAP_TOTAL)
-#define MEMINFO_MASK_SWAP_FREE (1ULL << MEMINFO_ID_SWAP_FREE)
-#define MEMINFO_MASK_DIRTY (1ULL << MEMINFO_ID_DIRTY)
-#define MEMINFO_MASK_WRITEBACK (1ULL << MEMINFO_ID_WRITEBACK)
-#define MEMINFO_MASK_ANON_PAGES (1ULL << MEMINFO_ID_ANON_PAGES)
-#define MEMINFO_MASK_MAPPED (1ULL << MEMINFO_ID_MAPPED)
-#define MEMINFO_MASK_SHMEM (1ULL << MEMINFO_ID_SHMEM)
-#define MEMINFO_MASK_SLAB (1ULL << MEMINFO_ID_SLAB)
-#define MEMINFO_MASK_SRECLAIMABLE (1ULL << MEMINFO_ID_SRECLAIMABLE)
-#define MEMINFO_MASK_SUNRECLAIM (1ULL << MEMINFO_ID_SUNRECLAIM)
-#define MEMINFO_MASK_KERNEL_STACK (1ULL << MEMINFO_ID_KERNEL_STACK)
-#define MEMINFO_MASK_PAGE_TABLES (1ULL << MEMINFO_ID_PAGE_TABLES)
-#define MEMINFO_MASK_NFS_UNSTABLE (1ULL << MEMINFO_ID_NFS_UNSTABLE)
-#define MEMINFO_MASK_BOUNCE (1ULL << MEMINFO_ID_BOUNCE)
-#define MEMINFO_MASK_WRITEBACK_TMP (1ULL << MEMINFO_ID_WRITEBACK_TMP)
-#define MEMINFO_MASK_COMMIT_LIMIT (1ULL << MEMINFO_ID_COMMIT_LIMIT)
-#define MEMINFO_MASK_COMMITTED_AS (1ULL << MEMINFO_ID_COMMITTED_AS)
-#define MEMINFO_MASK_VMALLOC_TOTAL (1ULL << MEMINFO_ID_VMALLOC_TOTAL)
-#define MEMINFO_MASK_VMALLOC_USED (1ULL << MEMINFO_ID_VMALLOC_USED)
-#define MEMINFO_MASK_VMALLOC_CHUNK (1ULL << MEMINFO_ID_VMALLOC_CHUNK)
-#define MEMINFO_MASK_ALL ((1ULL << MEMINFO_ID_MAX) - 1)
-
-struct meminfo_mapping {
- const char *name;
- enum meminfo_id id;
-};
-typedef struct meminfo_mapping meminfo_mapping;
-
-const meminfo_mapping *meminfo_mapping_lookup(const char *str, unsigned int len);
-
-static inline enum meminfo_id meminfo_string_to_id(const char *str)
-{
- const struct meminfo_mapping *i;
-
- assert(str);
- i = meminfo_mapping_lookup(str, strlen(str));
- return i ? i->id : MEMINFO_ID_INVALID;
-}
-
-const char *meminfo_id_to_string(enum meminfo_id);
-
-struct meminfo {
- unsigned int value[MEMINFO_ID_MAX];
-};
-
-/**
- * @desc get info corresponding size(kB) from /proc/meminfo
- * @note given meminfo struct is set all zero before filled
- * @return 0 on success, return negative error code on fail.
- */
-int proc_get_meminfo(struct meminfo *mi, unsigned long long mask);
-
-/*
- * This interface is required by proc_sys_node_trigger(...)
- */
-enum sys_node_id {
- SYS_VM_SHRINK_MEMORY,
- SYS_VM_COMPACT_MEMORY,
-};
-
-/*
- * Here,
- * @path is /proc/sys/vm/{shrink,compact}_memory
- * @value is always 1
- * @valid - indicates whether the node is present in kernel or not
- */
-struct sys_node_table {
- enum sys_node_id sys_node_id;
- const char *path;
- int value;
- int valid;
-};
-
-/**
- * @brief procfs entry parser arguments
- * @re_exp regular expression to look for
- * @callback callback function to be called once the arg match is identified
- * @tag unique identifier of the argument
- */
-struct parse_arg {
- const char *re_exp;
- int (*callback)(const char*, regmatch_t *, unsigned int, void *);
- unsigned int tag;
-};
-
-#define PARSE_TAG(exp, fn, id) \
-{ \
- .re_exp = exp, \
- .callback = fn, \
- .tag = PARSE_TAG_##id, \
-}
-
-#define PARSE_TAG_EMPTY() {0,}
-
-enum {
- PARSE_TAG_ZONE = 1,
- PARSE_TAG_PAGE_COUNT,
- PARSE_TAG_WM_MIN,
- PARSE_TAG_WM_LOW,
- PARSE_TAG_WM_HIGH,
- PARSE_TAG_MANAGED,
- PARSE_TAG_SPANNED,
- PARSE_TAG_MAX,
-};
-
-
-/**
- * @desc get command line from /proc/{pid}/cmdline if pid is greater than 0
- * it get /proc/cmdline if pid is 0
- * @return negative value if error
- */
-int proc_get_cmdline(pid_t pid, char *cmdline, size_t maxcmdline);
-
-/**
- * @desc find pid with /proc/{pid}/cmdline
- * it returns first entry when many pids have same cmdline
- * @return negative value if error
- */
-pid_t find_pid_from_cmdline(char *cmdline);
-
-/**
- * @desc get oom score adj value from /proc/{pid}/oom_score_adj
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_oom_score_adj(int pid, int *oom_score_adj);
-
-/**
- * @desc set oom score adj value to /proc/{pid}/oom_score_adj
- * @return negative value if error or pid doesn't exist
- */
-int proc_set_oom_score_adj(int pid, int oom_score_adj, struct proc_app_info *pai);
-
-/**
- * @desc get smack subject label from /proc/{pid}/attr/current
- * this label can indicate package name about child processes
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_label(pid_t pid, char *label);
-
-/**
- * @desc get USS memory usage from /proc/{pid}/smaps file.
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_uss(pid_t pid, unsigned int *uss);
-
-/**
- * @desc get VmRSS and VmSwap from /proc/{pid}/status file.
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_mem_status(pid_t pid, unsigned int *swap, unsigned int *rss);
-
-/**
- * @desc get aproximated usage of Zram for pid
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_zram_usage(pid_t pid, unsigned int *usage);
-
-/**
- * @desc get approximate memory usage from status and statm
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_approx_mem_usage(pid_t pid, unsigned int *usage);
-
-/**
- * @desc get total memory usage from VmSwap and VmRSS.
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_mem_usage(pid_t pid, unsigned int *usage);
-
-/**
- * @desc get how much ram is used in each application
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_ram_usage(pid_t pid, unsigned int *usage);
-
-/**
- * @desc get MemAvaliable from /proc/meminfo or calcuate it by MemFree+Cached
- * @return 0 if the values can't be read or the avaliable memory value
- */
-unsigned int proc_get_mem_available(void);
-
-/**
- * @desc get SwapFree from /proc/meminfo
- * @return 0 if the values can't be read or the free swap memory
- */
-unsigned int proc_get_swap_free(void);
-
-/**
- * @desc get SwapTotal from /proc/meminfo
- * @return 0 if the values can't be read or the total swap size
- */
-unsigned int proc_get_swap_total(void);
-
-/**
- * @desc get number of CPUs from /proc/cpuinfo
- * @return 0 if the number can't be found or number of CPUs
- */
-unsigned int proc_get_cpu_number(void);
-
-/**
- * @desc get utime and stime from /proc/{pid}/stat file.
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_cpu_time(pid_t pid, unsigned long *utime, unsigned long *stime,
- unsigned long *starttime);
-
-/**
- * @desc get command line from /proc/{pid}/cmdline without any truncation
- * @return negative value if error
- */
-int proc_get_raw_cmdline(pid_t pid, char *buf, int len);
-
-/**
- * @desc get symblolic link about /proc/{pid}/exe
- * @return negative value if error
- */
-int proc_get_exepath(pid_t pid, char *buf, int len);
-
-/**
- * @desc get stat from /proc/{pid}/stat
- * @return negative value if error
- */
-int proc_get_stat(pid_t pid, char *buf, int len);
-
-/**
- * @desc get status from /proc/{pid}/status
- * @return negative value if error
- */
-int proc_get_status(pid_t pid, char *buf, int len);
-
-/**
- * @desc invoke shrink_memory or compact_memory vm parameter.
- * @return none
- */
-int proc_sys_node_trigger(enum sys_node_id sys_node_id);
-
-/**
- * @desc get uptime from system time of /proc/uptime
- * @return negative value if error
- */
-int proc_get_uptime(unsigned long *uptime);
-
-/**
- * @desc get total ram size including reserved memory
- * @param[out] total Ram size in kilobytes
- * @return negative value if error
- */
-int proc_get_ram_total(unsigned int *total);
-
-/**
- * @brief print uss and memtotal for showing brief memory information
- */
-void proc_print_meninfo(FILE *fp);
-
-enum {
- PAGE_4K = 0,
- PAGE_8K,
- PAGE_16K,
- PAGE_32K,
- PAGE_64K,
- PAGE_128K,
- PAGE_256K,
- PAGE_512K,
- PAGE_1M,
- PAGE_2M,
- PAGE_4M,
- PAGE_MAX,
-};
-
-struct buddyinfo {
- int node;
- int page[PAGE_MAX];
-};
-
-/**
- * @desc get buddyinfo of specific zone from /proc/buddyinfo
- * @return negative value if error
- */
-int proc_get_buddyinfo(const char *zone, struct buddyinfo *bi);
-
-/**
- * @brief Generic, simplified procfs parser
- *
- * @path path to the procfs entry
- * @parse_args set of arguments specifying regular expressions
- * to be searched for within the procfs entry
- * @data custom data supplied to each parse callback function
- * specified within the parse arguments
- */
-int proc_parse_entry(const char *path, const struct parse_arg *parse_args,
- void *data);
-
-/**
- * @bried /proc/zoneinfo parser
- */
-static inline int proc_parse_zoneinfo(const struct parse_arg *parse_args,
- void *data)
-{
- return proc_parse_entry(PROC_ZONEINFO_PATH, parse_args, data);
-}
-/**
- * @brief /proc/pagetypeinfo parser
- */
-static inline int proc_parse_pagetypeinfo(const struct parse_arg *parse_args,
- void *data)
-{
- return proc_parse_entry(PROC_PAGETYPEINFO_PATH, parse_args, data);
-}
-
-static inline int proc_parse_buddyinfo(const struct parse_arg *parse_args,
- void *data)
-{
- return proc_parse_entry(PROC_BUDDYINFO_PATH, parse_args, data);
-}
-
-struct proc_swaps {
- char *filename;
- char *type;
- unsigned int size;
- unsigned int used;
- int priority;
-};
-
-void proc_swap_free(struct proc_swaps *swap);
-void proc_swaps_free(struct proc_swaps **swaps);
-
-static inline void __cleanup_proc_swap_free_func(struct proc_swaps **swap)
-{
- proc_swap_free(*swap);
-}
-
-#define _cleanup_proc_swap_free_ _cleanup_(__cleanup_proc_swap_free_func)
-
-static inline void __cleanup_proc_swaps_free_func(struct proc_swaps ***swaps)
-{
- proc_swaps_free(*swaps);
-}
-
-#define _cleanup_proc_swaps_free_ _cleanup_(__cleanup_proc_swaps_free_func)
-
-/**
- * @desc get swap info from /proc/swaps
- * @return negative value if errors, positive value means total enties of swap devices
- */
-int proc_get_swaps(struct proc_swaps ***swaps);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /*__PROCFS_H__*/
--- /dev/null
+/* NOTE: this file was dynamically generated by gperf but is included verbatim
+ * (instead of being regenerated) due to various build environment issues */
+
+/* ANSI-C code produced by gperf version 3.0.4 */
+/* Command-line: gperf /home/abuild/rpmbuild/BUILD/resourced-6.0.2/src/common/meminfo-lookup.gperf */
+/* Computed positions: -k'1-2,10' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#include "procfs.h"
+#include <string.h>
+
+#define TOTAL_KEYWORDS 38
+#define MIN_WORD_LENGTH 4
+#define MAX_WORD_LENGTH 14
+#define MIN_HASH_VALUE 4
+#define MAX_HASH_VALUE 67
+/* maximum key range = 64, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+meminfo_mapping_hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 5, 25, 10, 20, 68,
+ 15, 68, 25, 10, 68, 25, 15, 0, 10, 68,
+ 5, 68, 20, 0, 35, 10, 15, 5, 68, 68,
+ 68, 68, 68, 68, 68, 25, 68, 0, 30, 0,
+ 0, 5, 5, 68, 0, 0, 68, 68, 0, 0,
+ 0, 5, 68, 68, 5, 0, 15, 5, 68, 0,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[9]];
+ /*FALLTHROUGH*/
+ case 9:
+ case 8:
+ case 7:
+ case 6:
+ case 5:
+ case 4:
+ case 3:
+ case 2:
+ hval += asso_values[(unsigned char)str[1]];
+ /*FALLTHROUGH*/
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval;
+}
+
+#ifdef __GNUC__
+__inline
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+const meminfo_mapping *
+meminfo_mapping_lookup (register const char *str, register unsigned int len)
+{
+ static const meminfo_mapping wordlist[] =
+ {
+ {""}, {""}, {""}, {""},
+ {"Slab", MEMINFO_ID_SLAB},
+ {"Shmem", MEMINFO_ID_SHMEM},
+ {"Mapped", MEMINFO_ID_MAPPED},
+ {"Mlocked", MEMINFO_ID_MLOCKED},
+ {"SwapFree", MEMINFO_ID_SWAP_FREE},
+ {"SwapTotal", MEMINFO_ID_SWAP_TOTAL},
+ {"SwapCached", MEMINFO_ID_SWAP_CACHED},
+ {"Active", MEMINFO_ID_ACTIVE},
+ {"MemFree", MEMINFO_ID_MEM_FREE},
+ {"MemTotal", MEMINFO_ID_MEM_TOTAL},
+ {"AnonPages", MEMINFO_ID_ANON_PAGES},
+ {"PageTables", MEMINFO_ID_PAGE_TABLES},
+ {"Cached", MEMINFO_ID_CACHED},
+ {"Active(file)", MEMINFO_ID_ACTIVE_FILE},
+ {"Inactive", MEMINFO_ID_INACTIVE},
+ {"Writeback", MEMINFO_ID_WRITEBACK},
+ {"SUnreclaim", MEMINFO_ID_SUNRECLAIM},
+ {"Unevictable", MEMINFO_ID_UNEVICTABLE},
+ {"Active(anon)", MEMINFO_ID_ACTIVE_ANON},
+ {""},
+ {"Inactive(anon)", MEMINFO_ID_INACTIVE_ANON},
+ {"Dirty", MEMINFO_ID_DIRTY},
+ {"CommitLimit", MEMINFO_ID_COMMIT_LIMIT},
+ {"LowFree", MEMINFO_ID_LOW_FREE},
+ {"LowTotal", MEMINFO_ID_LOW_TOTAL},
+ {"Inactive(file)", MEMINFO_ID_INACTIVE_FILE},
+ {""},
+ {"VmallocUsed", MEMINFO_ID_VMALLOC_USED},
+ {"VmallocChunk", MEMINFO_ID_VMALLOC_CHUNK},
+ {"HighFree", MEMINFO_ID_HIGH_FREE},
+ {"HighTotal", MEMINFO_ID_HIGH_TOTAL},
+ {""},
+ {"Bounce", MEMINFO_ID_BOUNCE},
+ {"Buffers", MEMINFO_ID_BUFFERS},
+ {""}, {""}, {""},
+ {"KernelStack", MEMINFO_ID_KERNEL_STACK},
+ {"VmallocTotal", MEMINFO_ID_VMALLOC_TOTAL},
+ {""}, {""}, {""}, {""},
+ {"MemAvailable", MEMINFO_ID_MEM_AVAILABLE},
+ {""}, {""}, {""}, {""},
+ {"Committed_AS", MEMINFO_ID_COMMITTED_AS},
+ {""}, {""}, {""}, {""},
+ {"WritebackTmp", MEMINFO_ID_WRITEBACK_TMP},
+ {""}, {""}, {""}, {""},
+ {"SReclaimable", MEMINFO_ID_SRECLAIMABLE},
+ {""}, {""}, {""}, {""},
+ {"NFS_Unstable", MEMINFO_ID_NFS_UNSTABLE}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = meminfo_mapping_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
--- /dev/null
+%{
+#include "procfs.h"
+%}
+meminfo_mapping;
+%language=ANSI-C
+%define slot-name name
+%define hash-function-name meminfo_mapping_hash
+%define lookup-function-name meminfo_mapping_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+MemTotal, MEMINFO_ID_MEM_TOTAL
+MemFree, MEMINFO_ID_MEM_FREE
+MemAvailable, MEMINFO_ID_MEM_AVAILABLE
+Buffers, MEMINFO_ID_BUFFERS
+Cached, MEMINFO_ID_CACHED
+SwapCached, MEMINFO_ID_SWAP_CACHED
+Active, MEMINFO_ID_ACTIVE
+Inactive, MEMINFO_ID_INACTIVE
+Active(anon), MEMINFO_ID_ACTIVE_ANON
+Inactive(anon), MEMINFO_ID_INACTIVE_ANON
+Active(file), MEMINFO_ID_ACTIVE_FILE
+Inactive(file), MEMINFO_ID_INACTIVE_FILE
+Unevictable, MEMINFO_ID_UNEVICTABLE
+Mlocked, MEMINFO_ID_MLOCKED
+HighTotal, MEMINFO_ID_HIGH_TOTAL
+HighFree, MEMINFO_ID_HIGH_FREE
+LowTotal, MEMINFO_ID_LOW_TOTAL
+LowFree, MEMINFO_ID_LOW_FREE
+SwapTotal, MEMINFO_ID_SWAP_TOTAL
+SwapFree, MEMINFO_ID_SWAP_FREE
+Dirty, MEMINFO_ID_DIRTY
+Writeback, MEMINFO_ID_WRITEBACK
+AnonPages, MEMINFO_ID_ANON_PAGES
+Mapped, MEMINFO_ID_MAPPED
+Shmem, MEMINFO_ID_SHMEM
+Slab, MEMINFO_ID_SLAB
+SReclaimable, MEMINFO_ID_SRECLAIMABLE
+SUnreclaim, MEMINFO_ID_SUNRECLAIM
+KernelStack, MEMINFO_ID_KERNEL_STACK
+PageTables, MEMINFO_ID_PAGE_TABLES
+NFS_Unstable, MEMINFO_ID_NFS_UNSTABLE
+Bounce, MEMINFO_ID_BOUNCE
+WritebackTmp, MEMINFO_ID_WRITEBACK_TMP
+CommitLimit, MEMINFO_ID_COMMIT_LIMIT
+Committed_AS, MEMINFO_ID_COMMITTED_AS
+VmallocTotal, MEMINFO_ID_VMALLOC_TOTAL
+VmallocUsed, MEMINFO_ID_VMALLOC_USED
+VmallocChunk, MEMINFO_ID_VMALLOC_CHUNK
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file procfs.c
+ *
+ * @desc communicate with procfs in resourced
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "resourced.h"
+#include "trace.h"
+#include "macro.h"
+#include "util.h"
+#include "procfs.h"
+#include "proc-common.h"
+#include "memory-cgroup.h"
+#include "module.h"
+#include "file-helper.h"
+#include "swap-common.h"
+#include "smaps.h"
+#include "notifier.h"
+#include "lowmem-handler.h"
+
+#define MEM_SWAP_RATIO 0.5
+
+static struct sys_node_table sys_node_tables[] = {
+ { SYS_VM_SHRINK_MEMORY, "/proc/sys/vm/shrink_memory", 1, 1 },
+ { SYS_VM_COMPACT_MEMORY, "/proc/sys/vm/compact_memory", 1, 1 },
+ { },
+};
+
+int proc_get_cmdline(pid_t pid, char *cmdline, size_t maxcmdline)
+{
+ assert(cmdline);
+ assert(maxcmdline > 0);
+
+ char buf[PROC_BUF_MAX];
+ char cmdline_buf[PROC_NAME_MAX];
+ char *filename;
+ FILE *fp;
+
+ if (pid == 0)
+ snprintf(buf, sizeof(buf), "/proc/cmdline");
+ else
+ snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
+
+ fp = fopen(buf, "r");
+ if (fp == NULL)
+ return RESOURCED_ERROR_FAIL;
+
+ if (fgets(cmdline_buf, sizeof cmdline_buf, fp) == NULL) {
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ fclose(fp);
+
+ filename = strrchr(cmdline_buf, '/');
+ if (filename == NULL)
+ filename = cmdline_buf;
+ else
+ filename = filename + 1;
+
+ strncpy(cmdline, filename, maxcmdline - 1);
+ cmdline[maxcmdline - 1] = '\0';
+
+ return RESOURCED_ERROR_NONE;
+}
+
+pid_t find_pid_from_cmdline(char *cmdline)
+{
+ pid_t pid = -1, foundpid = -1;
+ int ret = 0;
+ DIR *dp;
+ struct dirent *dentry;
+ char appname[PROC_NAME_MAX];
+
+ dp = opendir("/proc");
+ if (!dp) {
+ _E("BACKGRD MANAGE : fail to open /proc");
+ return RESOURCED_ERROR_FAIL;
+ }
+ while ((dentry = readdir(dp))) {
+ if (!isdigit(dentry->d_name[0]))
+ continue;
+
+ pid = atoi(dentry->d_name);
+ if (!pid)
+ continue;
+ ret = proc_get_cmdline(pid, appname, sizeof appname);
+ if (ret == RESOURCED_ERROR_NONE) {
+ if (!strncmp(cmdline, appname, strlen(appname)+1)) {
+ foundpid = pid;
+ break;
+ }
+ }
+ }
+ closedir(dp);
+ return foundpid;
+}
+
+int proc_get_oom_score_adj(int pid, int *oom_score_adj)
+{
+ char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
+ FILE *fp = NULL;
+
+ if (pid <= 0)
+ return RESOURCED_ERROR_FAIL;
+
+ snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
+ fp = fopen(buf, "r");
+
+ if (fp == NULL) {
+ _E("fopen %s failed", buf);
+ return RESOURCED_ERROR_FAIL;
+ }
+ if (fgets(buf, sizeof(buf), fp) == NULL) {
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ (*oom_score_adj) = atoi(buf);
+ fclose(fp);
+ return RESOURCED_ERROR_NONE;
+}
+
+int proc_set_oom_score_adj(int pid, int oom_score_adj, struct proc_app_info *pai)
+{
+ FILE *fp;
+ struct lowmem_control_data lowmem_data;
+ char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
+
+ snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
+ fp = fopen(buf, "r+");
+ if (fp == NULL)
+ return RESOURCED_ERROR_FAIL;
+ if (fgets(buf, sizeof(buf), fp) == NULL) {
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ fprintf(fp, "%d", oom_score_adj);
+ fclose(fp);
+
+ if (oom_score_adj >= OOMADJ_SU) {
+ lowmem_data.control_type = LOWMEM_MOVE_CGROUP;
+ lowmem_data.pid = pid;
+ lowmem_data.oom_score_adj = oom_score_adj;
+ lowmem_data.pai = pai;
+ resourced_notify(RESOURCED_NOTIFIER_MEM_CONTROL, &lowmem_data);
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int proc_get_label(pid_t pid, char *label)
+{
+ char buf[PROC_BUF_MAX];
+ FILE *fp;
+
+ snprintf(buf, sizeof(buf), "/proc/%d/attr/current", pid);
+ fp = fopen(buf, "r");
+ if (fp == NULL)
+ return RESOURCED_ERROR_FAIL;
+
+ if (fgets(label, PROC_NAME_MAX-1, fp) == NULL) {
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ fclose(fp);
+ return RESOURCED_ERROR_NONE;
+}
+
+int proc_get_mem_status(pid_t pid, unsigned int *vmswap_kb, unsigned int *vmrss_kb)
+{
+ char filename[PROC_BUF_MAX];
+ _cleanup_fclose_ FILE *fp = NULL;
+ unsigned int swap_kb = 0, rss_kb = 0;
+
+ snprintf(filename, PROC_BUF_MAX, "/proc/%d/status", pid);
+ fp = fopen(filename, "r");
+ if (!fp)
+ return RESOURCED_ERROR_FAIL;
+
+ if (vmrss_kb != NULL) {
+ while (fgets(filename, sizeof(filename), fp)) {
+ /* Skip the lines, until first match */
+ if (!strstart_with(filename, "VmRSS:"))
+ continue;
+
+ /* Read RSS value and end this loop. */
+ if (sscanf(filename, "VmRSS: %u kB", &rss_kb) == 1)
+ break;
+
+ return RESOURCED_ERROR_NO_DATA;
+ }
+ *vmrss_kb = rss_kb;
+ }
+
+ if (vmswap_kb != NULL) {
+ /* Interate over rest of Vm* values */
+ while (fgets(filename, sizeof(filename), fp)) {
+ /* Read VmSwap and return with positive result */
+ if (sscanf(filename, "VmSwap: %d kB", &swap_kb) == 1)
+ break;
+
+ /* End of file before VmSwap read, return with error */
+ if (feof(fp))
+ return RESOURCED_ERROR_NO_DATA;
+ }
+ *vmswap_kb = swap_kb;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int proc_get_uss(pid_t pid, unsigned int *uss)
+{
+ _cleanup_smaps_free_ struct smaps *smaps = NULL;
+ int ret;
+
+ *uss = 0;
+
+ /*
+ * USS memory usage is number of KB accounted to a process
+ * where only private (non-shared) data are accounted.
+ *
+ * USS provides the value how much memory will be freed after
+ * termination of process.
+ */
+ ret = smaps_get(pid, &smaps,
+ (SMAPS_MASK_PRIVATE_CLEAN | SMAPS_MASK_PRIVATE_DIRTY));
+
+ if (ret < 0) {
+ _E("Error while reading smaps or totmaps for pid %d", pid);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ *uss += smaps->sum[SMAPS_ID_PRIVATE_CLEAN];
+ *uss += smaps->sum[SMAPS_ID_PRIVATE_DIRTY];
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int proc_get_zram_usage(pid_t pid, unsigned int *usage_kb)
+{
+ int ret;
+ struct meminfo mi;
+ static unsigned int swap_total_kb = 0;
+ unsigned int proc_swap_usage_kb;
+ unsigned long long zram_usage_bytes;
+
+ /* Read total swap size just once and cache it */
+ if (!swap_total_kb) {
+ ret = proc_get_meminfo(&mi, MEMINFO_MASK_SWAP_TOTAL);
+ if (ret < 0) {
+ _E("Failed to get %s: %m",
+ meminfo_id_to_string(MEMINFO_ID_SWAP_TOTAL));
+ return RESOURCED_ERROR_FAIL;
+ }
+ swap_total_kb = mi.value[MEMINFO_ID_SWAP_TOTAL];
+ }
+
+ /* Read usage of Swap (VmSwap) of interested process */
+ ret = proc_get_mem_status(pid, &proc_swap_usage_kb, NULL);
+ if (ret != RESOURCED_ERROR_NONE)
+ return ret;
+
+ /* Read current total memory usage of zram device */
+ ret = fread_nth_ulonglong(SWAP_ZRAM_SYSFILE"mm_stat", 2, &zram_usage_bytes);
+ if (ret == -ENOENT) {
+ ret = fread_ulonglong(SWAP_ZRAM_SYSFILE"mem_used_total", &zram_usage_bytes);
+ }
+
+ if (ret < 0)
+ return RESOURCED_ERROR_FAIL;
+
+ /*
+ * Calculate aproximated value of zram usage for selected process
+ * by formula: proc_zram_usage = ( VmSwap x ZramMemoryUsage )/SwapTotal
+ */
+ *usage_kb = (int)((float)proc_swap_usage_kb * BYTE_TO_KBYTE(zram_usage_bytes) / swap_total_kb);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int proc_get_approx_mem_usage(pid_t pid, unsigned int *usage_kb)
+{
+ int ret;
+ unsigned long resident_pages = 0, shared_pages = 0;
+ char filename[PROC_BUF_MAX];
+ _cleanup_fclose_ FILE *fp = NULL;
+
+ snprintf(filename, PROC_BUF_MAX, "/proc/%d/statm", pid);
+ fp = fopen(filename, "r");
+ if (!fp)
+ return RESOURCED_ERROR_FAIL;
+
+ /*
+ * For quick read, open code by putting numbers directly
+ * expected format is
+ * seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
+ * size, resident, shared, text, data);
+ */
+ ret = fscanf(fp, "%*s %lu %lu %*s %*s %*s %*s\n", &resident_pages, &shared_pages);
+ if (ret < 0)
+ return RESOURCED_ERROR_FAIL;
+
+ if (resident_pages < shared_pages) {
+ _E("# resident page should be larger than or equal to # shared page");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ /*
+ * The value resident - shared is mostly similar to Uss.
+ */
+ *usage_kb = BYTE_TO_KBYTE((unsigned long long)(resident_pages - shared_pages) << PAGE_SHIFT);
+ return RESOURCED_ERROR_NONE;
+}
+
+/**
+ * @desc get total memory usage from VmSwap and VmRSS.
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_mem_usage(pid_t pid, unsigned int *usage)
+{
+ int ret;
+ unsigned int vmswap = 0, total = 0;
+
+ ret = proc_get_approx_mem_usage(pid, &total);
+ if (ret < 0) {
+ _E("Failed to get usage : %d", pid);
+ return ret;
+ }
+
+ if (swap_get_state() == SWAP_ON) {
+ ret = proc_get_mem_status(pid, &vmswap, NULL);
+ if (ret != RESOURCED_ERROR_NONE)
+ goto out;
+
+ total += vmswap;
+ }
+out:
+ *usage = total;
+ return RESOURCED_ERROR_NONE;
+}
+
+/**
+ * @desc get how much ram is used in each application
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_ram_usage(pid_t pid, unsigned int *usage_kb)
+{
+ int ret;
+ unsigned int vmswap_kb = 0, total_kb = 0;
+
+ ret = proc_get_approx_mem_usage(pid, &total_kb);
+ if (ret < 0) {
+ _E("Failed to get usage : %d", pid);
+ return ret;
+ }
+
+ if (swap_get_state() == SWAP_ON) {
+ ret = proc_get_mem_status(pid, &vmswap_kb, NULL);
+ if (ret != RESOURCED_ERROR_NONE)
+ goto out;
+
+ /*
+ * If it is necessary to know real ram size about each application,
+ * it should consider compression ratio.
+ */
+ vmswap_kb *= MEM_SWAP_RATIO;
+ total_kb += vmswap_kb;
+ }
+out:
+ *usage_kb = total_kb;
+ return RESOURCED_ERROR_NONE;
+}
+
+unsigned int proc_get_mem_available(void)
+{
+ struct meminfo mi;
+ int ret;
+
+ ret = proc_get_meminfo(&mi, MEMINFO_MASK_MEM_AVAILABLE);
+ if (ret < 0) {
+ _E("Failed to get %s: %m",
+ meminfo_id_to_string(MEMINFO_ID_MEM_AVAILABLE));
+ return 0;
+ }
+
+ return KBYTE_TO_MBYTE(mi.value[MEMINFO_ID_MEM_AVAILABLE]);
+}
+
+unsigned int proc_get_swap_free(void)
+{
+ struct meminfo mi;
+ int ret;
+
+ ret = proc_get_meminfo(&mi, MEMINFO_MASK_SWAP_FREE);
+ if (ret < 0) {
+ _E("Failed to get %s: %m",
+ meminfo_id_to_string(MEMINFO_ID_SWAP_FREE));
+ return 0;
+ }
+
+ return mi.value[MEMINFO_ID_SWAP_FREE];
+}
+
+unsigned int proc_get_swap_total(void)
+{
+ struct meminfo mi;
+ int ret;
+
+ ret = proc_get_meminfo(&mi, MEMINFO_MASK_SWAP_TOTAL);
+ if (ret < 0) {
+ _E("Failed to get %s: %m",
+ meminfo_id_to_string(MEMINFO_ID_SWAP_TOTAL));
+ return 0;
+ }
+
+ return mi.value[MEMINFO_ID_SWAP_TOTAL];
+}
+
+int proc_get_cpu_time(pid_t pid, unsigned long *utime,
+ unsigned long *stime, unsigned long *starttime)
+{
+ char proc_path[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
+ _cleanup_fclose_ FILE *fp = NULL;
+
+ assert(utime != NULL);
+ assert(stime != NULL);
+
+ snprintf(proc_path, sizeof(proc_path), PROC_STAT_PATH, pid);
+ fp = fopen(proc_path, "r");
+ if (fp == NULL)
+ return RESOURCED_ERROR_FAIL;
+
+ if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s") < 0)
+ return RESOURCED_ERROR_FAIL;
+
+ if (fscanf(fp, "%lu %lu", utime, stime) < 1)
+ return RESOURCED_ERROR_FAIL;
+
+ if (fscanf(fp, "%*s %*s %*s %*s %*s %*s") < 0)
+ return RESOURCED_ERROR_FAIL;
+
+ if (fscanf(fp, "%lu", starttime) < 1)
+ return RESOURCED_ERROR_FAIL;
+
+ return RESOURCED_ERROR_NONE;
+}
+
+unsigned int proc_get_cpu_number(void)
+{
+ char buf[PATH_MAX];
+ FILE *fp;
+ int cpu = 0;
+
+ fp = fopen("/proc/cpuinfo", "r");
+
+ if (!fp) {
+ _E("/proc/cpuinfo open failed");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ while (fgets(buf, PATH_MAX, fp) != NULL) {
+ if (!strncmp(buf, "processor", 9))
+ cpu++;
+ }
+
+ fclose(fp);
+ return cpu;
+}
+
+int proc_get_exepath(pid_t pid, char *buf, int len)
+{
+ char path[PROC_BUF_MAX];
+ int ret = 0;
+
+ snprintf(path, sizeof(path), "/proc/%d/exe", pid);
+ ret = readlink(path, buf, len-1);
+ if (ret > 0)
+ buf[ret] = '\0';
+ else
+ buf[0] = '\0';
+ return RESOURCED_ERROR_NONE;
+}
+
+static int proc_get_data(char *path, char *buf, int len)
+{
+ _cleanup_close_ int fd = -1;
+ int ret;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return RESOURCED_ERROR_FAIL;
+
+ ret = read(fd, buf, len-1);
+ if (ret < 0) {
+ buf[0] = '\0';
+ return RESOURCED_ERROR_FAIL;
+ }
+ buf[ret] = '\0';
+ return RESOURCED_ERROR_NONE;
+}
+
+int proc_get_raw_cmdline(pid_t pid, char *buf, int len)
+{
+ char path[PROC_BUF_MAX];
+ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+ return proc_get_data(path, buf, len);
+}
+
+int proc_get_stat(pid_t pid, char *buf, int len)
+{
+ char path[PROC_BUF_MAX];
+ snprintf(path, sizeof(path), "/proc/%d/stat", pid);
+ return proc_get_data(path, buf, len);
+}
+
+int proc_get_status(pid_t pid, char *buf, int len)
+{
+ char path[PROC_BUF_MAX];
+ snprintf(path, sizeof(path), "/proc/%d/status", pid);
+ return proc_get_data(path, buf, len);
+}
+
+int proc_sys_node_trigger(enum sys_node_id sys_node_id)
+{
+ FILE *fp = NULL;
+
+ if (sys_node_id >= ARRAY_SIZE(sys_node_tables)) {
+ _E("sys_node_id[%d] is out of range.\n", sys_node_id);
+ return RESOURCED_ERROR_FAIL;
+ }
+ if (!sys_node_tables[sys_node_id].valid) {
+ _E("sys_node_id[%d] is not valid.\n", sys_node_id);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ /* open and check if the path exists, else return fail */
+ fp = fopen(sys_node_tables[sys_node_id].path, "w");
+ if (fp == NULL) {
+ _E("Failed to open %s: %m\n",
+ sys_node_tables[sys_node_id].path);
+ sys_node_tables[sys_node_id].valid = 0;
+ return RESOURCED_ERROR_FAIL;
+ }
+ fputc(sys_node_tables[sys_node_id].value, fp);
+ fclose(fp);
+ return RESOURCED_ERROR_NONE;
+}
+
+static const char* const meminfo_string_lookup[MEMINFO_ID_MAX] = {
+ [MEMINFO_ID_MEM_TOTAL] = "MemTotal",
+ [MEMINFO_ID_MEM_FREE] = "MemFree",
+ [MEMINFO_ID_MEM_AVAILABLE] = "MemAvailable",
+ [MEMINFO_ID_BUFFERS] = "Buffers",
+ [MEMINFO_ID_CACHED] = "Cached",
+ [MEMINFO_ID_SWAP_CACHED] = "SwapCached",
+ [MEMINFO_ID_ACTIVE] = "Active",
+ [MEMINFO_ID_INACTIVE] = "Inactive",
+ [MEMINFO_ID_ACTIVE_ANON] = "Active(anon)",
+ [MEMINFO_ID_INACTIVE_ANON] = "Inactive(anon)",
+ [MEMINFO_ID_ACTIVE_FILE] = "Active(file)",
+ [MEMINFO_ID_INACTIVE_FILE] = "Inactive(file)",
+ [MEMINFO_ID_UNEVICTABLE] = "Unevictable",
+ [MEMINFO_ID_MLOCKED] = "Mlocked",
+ [MEMINFO_ID_HIGH_TOTAL] = "HighTotal",
+ [MEMINFO_ID_HIGH_FREE] = "HighFree",
+ [MEMINFO_ID_LOW_TOTAL] = "LowTotal",
+ [MEMINFO_ID_LOW_FREE] = "LowFree",
+ [MEMINFO_ID_SWAP_TOTAL] = "SwapTotal",
+ [MEMINFO_ID_SWAP_FREE] = "SwapFree",
+ [MEMINFO_ID_DIRTY] = "Dirty",
+ [MEMINFO_ID_WRITEBACK] = "Writeback",
+ [MEMINFO_ID_ANON_PAGES] = "AnonPages",
+ [MEMINFO_ID_MAPPED] = "Mapped",
+ [MEMINFO_ID_SHMEM] = "Shmem",
+ [MEMINFO_ID_SLAB] = "Slab",
+ [MEMINFO_ID_SRECLAIMABLE] = "SReclaimable",
+ [MEMINFO_ID_SUNRECLAIM] = "SUnreclaim",
+ [MEMINFO_ID_KERNEL_STACK] = "KernelStack",
+ [MEMINFO_ID_PAGE_TABLES] = "PageTables",
+ [MEMINFO_ID_NFS_UNSTABLE] = "NFS_Unstable",
+ [MEMINFO_ID_BOUNCE] = "Bounce",
+ [MEMINFO_ID_WRITEBACK_TMP] = "WritebackTmp",
+ [MEMINFO_ID_COMMIT_LIMIT] = "CommitLimit",
+ [MEMINFO_ID_COMMITTED_AS] = "Committed_AS",
+ [MEMINFO_ID_VMALLOC_TOTAL] = "VmallocTotal",
+ [MEMINFO_ID_VMALLOC_USED] = "VmallocUsed",
+ [MEMINFO_ID_VMALLOC_CHUNK] = "VmallocChunk",
+};
+
+const char *meminfo_id_to_string(enum meminfo_id id)
+{
+ assert(id >= 0 && id < MEMINFO_ID_MAX);
+
+ return meminfo_string_lookup[id];
+}
+
+int proc_get_meminfo(struct meminfo *mi, unsigned long long mask)
+{
+ _cleanup_fclose_ FILE *f = NULL;
+ unsigned long long remain_mask = mask;
+ char buf[LINE_MAX];
+
+ assert(mi);
+
+ memset(mi, 0x0, sizeof(struct meminfo));
+
+ f = fopen("/proc/meminfo", "r");
+ if (!f) {
+ _E("Failed to read /proc/meminfo");
+ return -errno;
+ }
+
+ if (remain_mask & MEMINFO_MASK_MEM_AVAILABLE)
+ remain_mask |= (MEMINFO_MASK_MEM_FREE |
+ MEMINFO_MASK_CACHED);
+
+ while (remain_mask) {
+ _cleanup_free_ char *k = NULL;
+ unsigned int v = 0;
+ enum meminfo_id id;
+ size_t l;
+
+ if (!fgets(buf, sizeof(buf), f)) {
+ if (ferror(f))
+ return -errno;
+ break;
+ }
+
+ l = strcspn(buf, ":");
+ if (!l)
+ break;
+
+ k = strndup(buf, l);
+ if (!k)
+ return -errno;
+
+ id = meminfo_string_to_id(k);
+ if (id < 0 || id >= MEMINFO_ID_MAX)
+ continue;
+
+ if (!(remain_mask & (1ULL << id)))
+ continue;
+
+ remain_mask &= ~((1ULL << id));
+
+ if (sscanf(buf + l + 1, "%d", &v) != 1)
+ break;
+
+ mi->value[id] = v;
+ }
+
+ if (remain_mask & MEMINFO_MASK_MEM_AVAILABLE) {
+ mi->value[MEMINFO_ID_MEM_AVAILABLE] =
+ mi->value[MEMINFO_ID_MEM_FREE]
+ + mi->value[MEMINFO_ID_CACHED];
+
+ remain_mask &= ~MEMINFO_MASK_MEM_AVAILABLE;
+ }
+
+ if (remain_mask) {
+ enum meminfo_id i;
+
+ for (i = 0; i < MEMINFO_ID_MAX; i++)
+ if (remain_mask & (1ULL << i))
+ _E("Failed to get meminfo: '%s'",
+ meminfo_id_to_string(i));
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int parse_spanned_pages(const char *s, regmatch_t *match,
+ unsigned int parse_tag, void *data)
+{
+ char *e;
+ unsigned long v;
+ unsigned long *parse_v = (unsigned long *)data;
+
+ v = strtoul(s + match[1].rm_so, &e, 0);
+ *parse_v += v;
+
+ return 0;
+}
+
+int proc_get_ram_total(unsigned int *total_kb)
+{
+ unsigned long total_spanned = 0;
+ static unsigned int total_ram_kb = 0;
+ int ret;
+ const struct parse_arg args[] = {
+ PARSE_TAG("spanned[[:blank:]]+([0-9]+)\n",
+ parse_spanned_pages, SPANNED),
+ PARSE_TAG_EMPTY(),
+ };
+
+ if (total_ram_kb > 0) {
+ *total_kb = total_ram_kb;
+ return RESOURCED_ERROR_NONE;
+ }
+
+ ret = proc_parse_zoneinfo(args, &total_spanned);
+ if (ret != RESOURCED_ERROR_NONE)
+ return RESOURCED_ERROR_NO_DATA;
+
+ total_ram_kb = (unsigned int)BYTE_TO_KBYTE((unsigned long long)total_spanned << PAGE_SHIFT);
+ *total_kb = total_ram_kb;
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static inline char *proc_skip_blanks(const char *s)
+{
+ while (s && (isblank(*s) || !isalnum(*s)))
+ ++s;
+ return (char*)s;
+}
+
+#define PROC_MAX_REG_MATCH 6
+
+static int proc_find_match(char *s, const struct parse_arg *parse,
+ void *data, size_t *parsed)
+{
+ regex_t regex;
+ regmatch_t match[PROC_MAX_REG_MATCH];
+ int result;
+
+ if (!s || !(*s != '\0'))
+ return -EINVAL;
+
+ if (!parse->callback)
+ return 0;
+
+ *parsed = 0;
+
+ result = regcomp(®ex, parse->re_exp, REG_EXTENDED);
+ if (!result) {
+ result = regexec(®ex, s, ARRAY_SIZE(match), match, 0);
+ if (!result) {
+ regmatch_t *m = match;
+
+ result = parse->callback(s, match, parse->tag, data);
+ if (result)
+ goto leave;
+ while ((m - match) < PROC_MAX_REG_MATCH &&
+ m->rm_so >= 0 && m->rm_eo > 0)
+ ++m;
+
+ *parsed = m > match ? (--m)->rm_eo + 1 : 0;
+ }
+leave:
+ regfree(®ex);
+ }
+ return result;
+}
+
+/**
+ * @brief Rather basic parser that relies on provided arguments,
+ * specifying the actual expression to look for.
+ * Note that it does not make any assumptions as to how
+ * the input to be parsed is actual formated and what is the
+ * layout of the information held within it.
+ * - mind it as badly specified arguments might result in a failure
+ * to identify potential match or finding a match but not one that
+ * has been expected. It is up to the caller to perform
+ * the actual formatting of data.
+ * Parsing is done per line with possible multiple regexes.
+ * @return Returns number of found matches against supplied parse arguments
+ */
+static int proc_parse_single(const char *buffer,
+ const struct parse_arg *parse_args,
+ void *data)
+{
+ char *s = (char*)buffer;
+ size_t size;
+ unsigned int match = 0;
+
+ while (s && *s != '\n' && *s != '\0') {
+ const struct parse_arg *p = parse_args;
+
+ size = 0;
+ s = proc_skip_blanks(s);
+
+ while (proc_find_match(s, p, data, &size))
+ ++p;
+
+ if (!size)
+ break;
+ s += size;
+ ++match;
+ }
+ return match;
+}
+
+/**
+ * @brief Simplified procfs parser
+ *
+ * Reads the procfs entry line by line triggering regex match
+ * function for each supplied argument.
+ * Note: The set of arguments should end with an empty one.
+ *
+ * @return returns 0 upon successfully calling the actual parsing
+ * procedure at least once, error code otherwise.
+ * Note: it is up to the caller to properly handle
+ * callbacks triggered upon each match found and to determine
+ * if parsing itself actually succeeded.
+ */
+int proc_parse_entry(const char *path, const struct parse_arg *parse_args,
+ void *data)
+{
+ char buf[LINE_MAX];
+ _cleanup_fclose_ FILE *f = NULL;
+
+ f = fopen(path, "r");
+ if (!f)
+ return -errno;
+
+ while (fgets(buf, sizeof(buf), f))
+ proc_parse_single(buf, parse_args, data);
+ return ferror(f) ? -errno : 0;
+}
+
+int proc_get_uptime(unsigned long *uptime)
+{
+ _cleanup_fclose_ FILE *fp = NULL;
+ double stime;
+
+ fp = fopen("/proc/uptime", "r");
+ if (fp == NULL)
+ return RESOURCED_ERROR_FAIL;
+
+ if (fscanf(fp, "%lf %*s", &stime) < 0)
+ return RESOURCED_ERROR_FAIL;
+
+ *uptime = (unsigned long)stime;
+ return RESOURCED_ERROR_NONE;
+}
+
+/**
+ * @brief print simple memory info with rss and memtotal
+ *
+ * Reads the procfs about all process id and print RSS usage.
+ * Note: If fp is valid, the result is written by desired file.
+ * Otherwise, it printed message through dlog.
+ */
+void proc_print_meninfo(FILE *fp)
+{
+ _cleanup_closedir_ DIR *dir = NULL;
+ struct dirent *de;
+ pid_t pid, caller;
+ char cmdline[PATH_MAX];
+ _cleanup_fclose_ FILE *output_file = NULL;
+ int oom_score_adj, ret;
+ unsigned int rss, swap;
+ struct meminfo mi;
+ unsigned int free_kb = 0;
+ unsigned int total_mem_kb = 0, available_kb = 0, used_kb;
+ unsigned int swap_total_kb = 0, swap_free_kb = 0, swap_used_kb;
+ unsigned long long zram_used_bytes;
+
+ dir = opendir("/proc");
+ if (dir == NULL) {
+ _E("cannot read directory /proc.");
+ return;
+ }
+
+ LOG_DUMP(fp, " PID RSS SWAP OOM_SCORE COMMAND\n");
+
+ caller = getpid();
+ while ((de = readdir(dir)) != NULL) {
+ pid = atoi(de->d_name);
+
+ /* exclude negative value which means string value and kernel thread */
+ if (pid < 1 || pid == caller)
+ continue;
+
+ ret = proc_get_cmdline(pid, cmdline, sizeof cmdline);
+ if (ret)
+ continue;
+
+ ret = proc_get_mem_status(pid, &swap, &rss);
+ if (ret)
+ continue;
+
+ ret = proc_get_oom_score_adj(pid, &oom_score_adj);
+ if (ret)
+ continue;
+
+ LOG_DUMP(fp, "%8d %8u %8u %8d %s\n",
+ pid,
+ rss,
+ swap,
+ oom_score_adj,
+ cmdline);
+
+ } /* end of while */
+
+ ret = proc_get_meminfo(&mi,
+ (MEMINFO_MASK_MEM_TOTAL |
+ MEMINFO_MASK_MEM_FREE |
+ MEMINFO_MASK_MEM_AVAILABLE |
+ MEMINFO_MASK_CACHED |
+ MEMINFO_MASK_SWAP_TOTAL |
+ MEMINFO_MASK_SWAP_FREE));
+ if (ret < 0) {
+ _E("Failed to get meminfo");
+ return;
+ }
+
+ total_mem_kb = mi.value[MEMINFO_ID_MEM_TOTAL];
+ free_kb = mi.value[MEMINFO_ID_MEM_FREE];
+ available_kb = mi.value[MEMINFO_ID_MEM_AVAILABLE];
+ swap_total_kb = mi.value[MEMINFO_ID_SWAP_TOTAL];
+ swap_free_kb = mi.value[MEMINFO_ID_SWAP_FREE];
+
+ used_kb = total_mem_kb - available_kb;
+ swap_used_kb = swap_total_kb - swap_free_kb;
+
+ ret = fread_nth_ulonglong(SWAP_ZRAM_SYSFILE"mm_stat", 2, &zram_used_bytes);
+ if (ret == -ENOENT) {
+ ret = fread_ulonglong(SWAP_ZRAM_SYSFILE"mem_used_total", &zram_used_bytes);
+ }
+
+ if (ret != RESOURCED_ERROR_NONE)
+ zram_used_bytes = 0;
+
+ LOG_DUMP(fp, "====================================================================\n");
+ LOG_DUMP(fp, "Total RAM size: \t%15d MB( %6d kB)\n",
+ KBYTE_TO_MBYTE(total_mem_kb), total_mem_kb);
+ LOG_DUMP(fp, "Used (Mem+Reclaimable): %15d MB( %6d kB)\n",
+ KBYTE_TO_MBYTE(total_mem_kb - free_kb), total_mem_kb - free_kb);
+ LOG_DUMP(fp, "Used (Mem+Swap): \t%15d MB( %6d kB)\n",
+ KBYTE_TO_MBYTE(used_kb), used_kb);
+ LOG_DUMP(fp, "Used (Mem): \t\t%15d MB( %6d kB)\n",
+ KBYTE_TO_MBYTE(used_kb), used_kb);
+ LOG_DUMP(fp, "Used (Swap): \t\t%15d MB( %6d kB)\n",
+ KBYTE_TO_MBYTE(swap_used_kb), swap_used_kb);
+ LOG_DUMP(fp, "Used (Zram block device): %13d MB( %6d kB)\n",
+ (int)BYTE_TO_MBYTE(zram_used_bytes), (int)BYTE_TO_KBYTE(zram_used_bytes));
+ LOG_DUMP(fp, "Mem Free:\t\t%15d MB( %6d kB)\n",
+ KBYTE_TO_MBYTE(free_kb), free_kb);
+ LOG_DUMP(fp, "Available (Free+Reclaimable):%10d MB( %6d kB)\n",
+ KBYTE_TO_MBYTE(available_kb), available_kb);
+ return;
+}
+
+int proc_get_buddyinfo(const char *zone, struct buddyinfo *bi)
+{
+ _cleanup_fclose_ FILE *f = NULL;
+ char buf[LINE_MAX];
+
+ g_assert(zone);
+ g_assert(bi);
+
+ f = fopen("/proc/buddyinfo", "re");
+ if (!f)
+ return -errno;
+
+ for (;;) {
+ int n;
+ char zonename[32] = { 0, };
+
+ if (!fgets(buf, sizeof(buf), f)) {
+ if (ferror(f))
+ return -errno;
+
+ break;
+ }
+
+ n = sscanf(buf, "Node %d, zone %31s %d %d %d %d %d %d %d %d %d %d %d",
+ &bi->node,
+ zonename,
+ &bi->page[PAGE_4K],
+ &bi->page[PAGE_8K],
+ &bi->page[PAGE_16K],
+ &bi->page[PAGE_32K],
+ &bi->page[PAGE_64K],
+ &bi->page[PAGE_128K],
+ &bi->page[PAGE_256K],
+ &bi->page[PAGE_512K],
+ &bi->page[PAGE_1M],
+ &bi->page[PAGE_2M],
+ &bi->page[PAGE_4M]);
+ if (n != 13)
+ break;
+
+ if (!streq(zone, zonename))
+ continue;
+
+ return 0;
+ }
+
+ return -ENODATA;
+}
+
+void proc_swap_free(struct proc_swaps *swap)
+{
+ if (!swap)
+ return;
+
+ free(swap->filename);
+ free(swap->type);
+ free(swap);
+}
+
+void proc_swaps_free(struct proc_swaps **swaps)
+{
+ int i;
+
+ if (!swaps)
+ return;
+
+ for (i = 0; swaps[i]; i++)
+ proc_swap_free(swaps[i]);
+
+ free(swaps);
+}
+
+int proc_get_swaps(struct proc_swaps ***swaps)
+{
+ _cleanup_proc_swaps_free_ struct proc_swaps **ss = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ char buf[LINE_MAX];
+ size_t cnt = 0;
+
+ assert(swaps);
+ assert(!*swaps);
+
+ f = fopen("/proc/swaps", "re");
+ if (!f)
+ return -errno;
+
+ for (;;) {
+ _cleanup_proc_swap_free_ struct proc_swaps *swap = NULL;
+
+ if (!fgets(buf, sizeof(buf), f)) {
+ if (ferror(f))
+ return -errno;
+
+ break;
+ }
+
+ swap = calloc(sizeof(struct proc_swaps), 1);
+ if (!swap)
+ return -ENOMEM;
+
+ if (sscanf(buf, "%ms %ms %u %u %d",
+ &swap->filename,
+ &swap->type,
+ &swap->size,
+ &swap->used,
+ &swap->priority) != 5)
+ continue;
+
+ ss = (struct proc_swaps **)realloc(ss, sizeof(struct proc_swaps *) * (cnt + 2));
+ if (!ss)
+ return -ENOMEM;
+
+ ss[cnt++] = swap;
+ ss[cnt] = NULL;
+ swap = NULL;
+ }
+
+ *swaps = ss;
+ ss = NULL;
+
+ return cnt;
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 __PROCFS_H__
+#define __PROCFS_H__
+
+#include <resourced.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <regex.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "proc-common.h"
+
+#define OOMADJ_SU (0)
+#define OOMADJ_INIT (100)
+#define OOMADJ_FOREGRD_LOCKED (150)
+#define OOMADJ_FOREGRD_UNLOCKED (200)
+#define OOMADJ_BACKGRD_PERCEPTIBLE (230)
+#define OOMADJ_BACKGRD_LOCKED (250)
+#define OOMADJ_FAVORITE (270)
+#define OOMADJ_BACKGRD_UNLOCKED (300)
+#define OOMADJ_RECENTLY_USED (430)
+#define OOMADJ_BACKGRD_OLD (450)
+#define OOMADJ_APP_MAX (990)
+#define OOMADJ_APP_INCREASE (30)
+
+#define OOMADJ_FAVORITE_APP_MAX (OOMADJ_PREVIOUS_BACKGRD - OOMADJ_FAVORITE_APP_INCREASE)
+#define OOMADJ_FAVORITE_APP_INCREASE (1)
+
+/* OOMADJ_SERVICE_DEFAULT is default value for processes PROC_TYPE_SERVICE */
+#define OOMADJ_SERVICE_GAP (10)
+#define OOMADJ_SERVICE_DEFAULT (OOMADJ_BACKGRD_LOCKED - OOMADJ_SERVICE_GAP)
+
+/*
+ * OOMADJ_PREVIOUS_DEFAULT is default value for processes that are
+ * moved out from foreground cgroup ( >= OOMADJ_BACKGRD_PERCEPTIBLE)
+ * but being in a state before background cgroup ( >= OOMADJ_BACKGRD_UNLOCKED).
+ * In the middle it is possible to have process in favorite cgroup (== OOMADJ_FAVORITE).
+ */
+#define OOMADJ_PREVIOUS_GAP (10)
+#define OOMADJ_PREVIOUS_DEFAULT (OOMADJ_BACKGRD_LOCKED - OOMADJ_PREVIOUS_GAP)
+#define OOMADJ_PREVIOUS_BACKGRD (OOMADJ_BACKGRD_UNLOCKED - OOMADJ_PREVIOUS_GAP)
+
+
+#define PROC_OOM_SCORE_ADJ_PATH "/proc/%d/oom_score_adj"
+#define PROC_STAT_PATH "/proc/%d/stat"
+#define PROC_ZONEINFO_PATH "/proc/zoneinfo"
+#define PROC_PAGETYPEINFO_PATH "/proc/pagetypeinfo"
+#define PROC_BUDDYINFO_PATH "/proc/buddyinfo"
+
+enum meminfo_id {
+ MEMINFO_ID_INVALID = -1,
+ MEMINFO_ID_MEM_TOTAL = 0,
+ MEMINFO_ID_MEM_FREE,
+ MEMINFO_ID_MEM_AVAILABLE,
+ MEMINFO_ID_BUFFERS,
+ MEMINFO_ID_CACHED,
+ MEMINFO_ID_SWAP_CACHED,
+ MEMINFO_ID_ACTIVE,
+ MEMINFO_ID_INACTIVE,
+ MEMINFO_ID_ACTIVE_ANON,
+ MEMINFO_ID_INACTIVE_ANON,
+ MEMINFO_ID_ACTIVE_FILE,
+ MEMINFO_ID_INACTIVE_FILE,
+ MEMINFO_ID_UNEVICTABLE,
+ MEMINFO_ID_MLOCKED,
+ MEMINFO_ID_HIGH_TOTAL,
+ MEMINFO_ID_HIGH_FREE,
+ MEMINFO_ID_LOW_TOTAL,
+ MEMINFO_ID_LOW_FREE,
+ MEMINFO_ID_SWAP_TOTAL,
+ MEMINFO_ID_SWAP_FREE,
+ MEMINFO_ID_DIRTY,
+ MEMINFO_ID_WRITEBACK,
+ MEMINFO_ID_ANON_PAGES,
+ MEMINFO_ID_MAPPED,
+ MEMINFO_ID_SHMEM,
+ MEMINFO_ID_SLAB,
+ MEMINFO_ID_SRECLAIMABLE,
+ MEMINFO_ID_SUNRECLAIM,
+ MEMINFO_ID_KERNEL_STACK,
+ MEMINFO_ID_PAGE_TABLES,
+ MEMINFO_ID_NFS_UNSTABLE,
+ MEMINFO_ID_BOUNCE,
+ MEMINFO_ID_WRITEBACK_TMP,
+ MEMINFO_ID_COMMIT_LIMIT,
+ MEMINFO_ID_COMMITTED_AS,
+ MEMINFO_ID_VMALLOC_TOTAL,
+ MEMINFO_ID_VMALLOC_USED,
+ MEMINFO_ID_VMALLOC_CHUNK,
+ MEMINFO_ID_MAX,
+};
+
+#define MEMINFO_MASK_MEM_TOTAL (1ULL << MEMINFO_ID_MEM_TOTAL)
+#define MEMINFO_MASK_MEM_FREE (1ULL << MEMINFO_ID_MEM_FREE)
+#define MEMINFO_MASK_MEM_AVAILABLE (1ULL << MEMINFO_ID_MEM_AVAILABLE)
+#define MEMINFO_MASK_BUFFERS (1ULL << MEMINFO_ID_BUFFERS)
+#define MEMINFO_MASK_CACHED (1ULL << MEMINFO_ID_CACHED)
+#define MEMINFO_MASK_SWAP_CACHED (1ULL << MEMINFO_ID_SWAP_CACHED)
+#define MEMINFO_MASK_ACTIVE (1ULL << MEMINFO_ID_ACTIVE)
+#define MEMINFO_MASK_INACTIVE (1ULL << MEMINFO_ID_INACTIVE)
+#define MEMINFO_MASK_ACTIVE_ANON (1ULL << MEMINFO_ID_ACTIVE_ANON)
+#define MEMINFO_MASK_INACTIVE_ANON (1ULL << MEMINFO_ID_INACTIVE_ANON)
+#define MEMINFO_MASK_ACTIVE_FILE (1ULL << MEMINFO_ID_ACTIVE_FILE)
+#define MEMINFO_MASK_INACTIVE_FILE (1ULL << MEMINFO_ID_INACTIVE_FILE)
+#define MEMINFO_MASK_UNEVICTABLE (1ULL << MEMINFO_ID_UNEVICTABLE)
+#define MEMINFO_MASK_MLOCKED (1ULL << MEMINFO_ID_MLOCKED)
+#define MEMINFO_MASK_HIGH_TOTAL (1ULL << MEMINFO_ID_HIGH_TOTAL)
+#define MEMINFO_MASK_HIGH_FREE (1ULL << MEMINFO_ID_HIGH_FREE)
+#define MEMINFO_MASK_LOW_TOTAL (1ULL << MEMINFO_ID_LOW_TOTAL)
+#define MEMINFO_MASK_LOW_FREE (1ULL << MEMINFO_ID_LOW_FREE)
+#define MEMINFO_MASK_SWAP_TOTAL (1ULL << MEMINFO_ID_SWAP_TOTAL)
+#define MEMINFO_MASK_SWAP_FREE (1ULL << MEMINFO_ID_SWAP_FREE)
+#define MEMINFO_MASK_DIRTY (1ULL << MEMINFO_ID_DIRTY)
+#define MEMINFO_MASK_WRITEBACK (1ULL << MEMINFO_ID_WRITEBACK)
+#define MEMINFO_MASK_ANON_PAGES (1ULL << MEMINFO_ID_ANON_PAGES)
+#define MEMINFO_MASK_MAPPED (1ULL << MEMINFO_ID_MAPPED)
+#define MEMINFO_MASK_SHMEM (1ULL << MEMINFO_ID_SHMEM)
+#define MEMINFO_MASK_SLAB (1ULL << MEMINFO_ID_SLAB)
+#define MEMINFO_MASK_SRECLAIMABLE (1ULL << MEMINFO_ID_SRECLAIMABLE)
+#define MEMINFO_MASK_SUNRECLAIM (1ULL << MEMINFO_ID_SUNRECLAIM)
+#define MEMINFO_MASK_KERNEL_STACK (1ULL << MEMINFO_ID_KERNEL_STACK)
+#define MEMINFO_MASK_PAGE_TABLES (1ULL << MEMINFO_ID_PAGE_TABLES)
+#define MEMINFO_MASK_NFS_UNSTABLE (1ULL << MEMINFO_ID_NFS_UNSTABLE)
+#define MEMINFO_MASK_BOUNCE (1ULL << MEMINFO_ID_BOUNCE)
+#define MEMINFO_MASK_WRITEBACK_TMP (1ULL << MEMINFO_ID_WRITEBACK_TMP)
+#define MEMINFO_MASK_COMMIT_LIMIT (1ULL << MEMINFO_ID_COMMIT_LIMIT)
+#define MEMINFO_MASK_COMMITTED_AS (1ULL << MEMINFO_ID_COMMITTED_AS)
+#define MEMINFO_MASK_VMALLOC_TOTAL (1ULL << MEMINFO_ID_VMALLOC_TOTAL)
+#define MEMINFO_MASK_VMALLOC_USED (1ULL << MEMINFO_ID_VMALLOC_USED)
+#define MEMINFO_MASK_VMALLOC_CHUNK (1ULL << MEMINFO_ID_VMALLOC_CHUNK)
+#define MEMINFO_MASK_ALL ((1ULL << MEMINFO_ID_MAX) - 1)
+
+struct meminfo_mapping {
+ const char *name;
+ enum meminfo_id id;
+};
+typedef struct meminfo_mapping meminfo_mapping;
+
+const meminfo_mapping *meminfo_mapping_lookup(const char *str, unsigned int len);
+
+static inline enum meminfo_id meminfo_string_to_id(const char *str)
+{
+ const struct meminfo_mapping *i;
+
+ assert(str);
+ i = meminfo_mapping_lookup(str, strlen(str));
+ return i ? i->id : MEMINFO_ID_INVALID;
+}
+
+const char *meminfo_id_to_string(enum meminfo_id);
+
+struct meminfo {
+ unsigned int value[MEMINFO_ID_MAX];
+};
+
+/**
+ * @desc get info corresponding size(kB) from /proc/meminfo
+ * @note given meminfo struct is set all zero before filled
+ * @return 0 on success, return negative error code on fail.
+ */
+int proc_get_meminfo(struct meminfo *mi, unsigned long long mask);
+
+/*
+ * This interface is required by proc_sys_node_trigger(...)
+ */
+enum sys_node_id {
+ SYS_VM_SHRINK_MEMORY,
+ SYS_VM_COMPACT_MEMORY,
+};
+
+/*
+ * Here,
+ * @path is /proc/sys/vm/{shrink,compact}_memory
+ * @value is always 1
+ * @valid - indicates whether the node is present in kernel or not
+ */
+struct sys_node_table {
+ enum sys_node_id sys_node_id;
+ const char *path;
+ int value;
+ int valid;
+};
+
+/**
+ * @brief procfs entry parser arguments
+ * @re_exp regular expression to look for
+ * @callback callback function to be called once the arg match is identified
+ * @tag unique identifier of the argument
+ */
+struct parse_arg {
+ const char *re_exp;
+ int (*callback)(const char*, regmatch_t *, unsigned int, void *);
+ unsigned int tag;
+};
+
+#define PARSE_TAG(exp, fn, id) \
+{ \
+ .re_exp = exp, \
+ .callback = fn, \
+ .tag = PARSE_TAG_##id, \
+}
+
+#define PARSE_TAG_EMPTY() {0,}
+
+enum {
+ PARSE_TAG_ZONE = 1,
+ PARSE_TAG_PAGE_COUNT,
+ PARSE_TAG_WM_MIN,
+ PARSE_TAG_WM_LOW,
+ PARSE_TAG_WM_HIGH,
+ PARSE_TAG_MANAGED,
+ PARSE_TAG_SPANNED,
+ PARSE_TAG_MAX,
+};
+
+
+/**
+ * @desc get command line from /proc/{pid}/cmdline if pid is greater than 0
+ * it get /proc/cmdline if pid is 0
+ * @return negative value if error
+ */
+int proc_get_cmdline(pid_t pid, char *cmdline, size_t maxcmdline);
+
+/**
+ * @desc find pid with /proc/{pid}/cmdline
+ * it returns first entry when many pids have same cmdline
+ * @return negative value if error
+ */
+pid_t find_pid_from_cmdline(char *cmdline);
+
+/**
+ * @desc get oom score adj value from /proc/{pid}/oom_score_adj
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_oom_score_adj(int pid, int *oom_score_adj);
+
+/**
+ * @desc set oom score adj value to /proc/{pid}/oom_score_adj
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_set_oom_score_adj(int pid, int oom_score_adj, struct proc_app_info *pai);
+
+/**
+ * @desc get smack subject label from /proc/{pid}/attr/current
+ * this label can indicate package name about child processes
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_label(pid_t pid, char *label);
+
+/**
+ * @desc get USS memory usage from /proc/{pid}/smaps file.
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_uss(pid_t pid, unsigned int *uss);
+
+/**
+ * @desc get VmRSS and VmSwap from /proc/{pid}/status file.
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_mem_status(pid_t pid, unsigned int *swap, unsigned int *rss);
+
+/**
+ * @desc get aproximated usage of Zram for pid
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_zram_usage(pid_t pid, unsigned int *usage);
+
+/**
+ * @desc get approximate memory usage from status and statm
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_approx_mem_usage(pid_t pid, unsigned int *usage);
+
+/**
+ * @desc get total memory usage from VmSwap and VmRSS.
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_mem_usage(pid_t pid, unsigned int *usage);
+
+/**
+ * @desc get how much ram is used in each application
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_ram_usage(pid_t pid, unsigned int *usage);
+
+/**
+ * @desc get MemAvaliable from /proc/meminfo or calcuate it by MemFree+Cached
+ * @return 0 if the values can't be read or the avaliable memory value
+ */
+unsigned int proc_get_mem_available(void);
+
+/**
+ * @desc get SwapFree from /proc/meminfo
+ * @return 0 if the values can't be read or the free swap memory
+ */
+unsigned int proc_get_swap_free(void);
+
+/**
+ * @desc get SwapTotal from /proc/meminfo
+ * @return 0 if the values can't be read or the total swap size
+ */
+unsigned int proc_get_swap_total(void);
+
+/**
+ * @desc get number of CPUs from /proc/cpuinfo
+ * @return 0 if the number can't be found or number of CPUs
+ */
+unsigned int proc_get_cpu_number(void);
+
+/**
+ * @desc get utime and stime from /proc/{pid}/stat file.
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_cpu_time(pid_t pid, unsigned long *utime, unsigned long *stime,
+ unsigned long *starttime);
+
+/**
+ * @desc get command line from /proc/{pid}/cmdline without any truncation
+ * @return negative value if error
+ */
+int proc_get_raw_cmdline(pid_t pid, char *buf, int len);
+
+/**
+ * @desc get symblolic link about /proc/{pid}/exe
+ * @return negative value if error
+ */
+int proc_get_exepath(pid_t pid, char *buf, int len);
+
+/**
+ * @desc get stat from /proc/{pid}/stat
+ * @return negative value if error
+ */
+int proc_get_stat(pid_t pid, char *buf, int len);
+
+/**
+ * @desc get status from /proc/{pid}/status
+ * @return negative value if error
+ */
+int proc_get_status(pid_t pid, char *buf, int len);
+
+/**
+ * @desc invoke shrink_memory or compact_memory vm parameter.
+ * @return none
+ */
+int proc_sys_node_trigger(enum sys_node_id sys_node_id);
+
+/**
+ * @desc get uptime from system time of /proc/uptime
+ * @return negative value if error
+ */
+int proc_get_uptime(unsigned long *uptime);
+
+/**
+ * @desc get total ram size including reserved memory
+ * @param[out] total Ram size in kilobytes
+ * @return negative value if error
+ */
+int proc_get_ram_total(unsigned int *total);
+
+/**
+ * @brief print uss and memtotal for showing brief memory information
+ */
+void proc_print_meninfo(FILE *fp);
+
+enum {
+ PAGE_4K = 0,
+ PAGE_8K,
+ PAGE_16K,
+ PAGE_32K,
+ PAGE_64K,
+ PAGE_128K,
+ PAGE_256K,
+ PAGE_512K,
+ PAGE_1M,
+ PAGE_2M,
+ PAGE_4M,
+ PAGE_MAX,
+};
+
+struct buddyinfo {
+ int node;
+ int page[PAGE_MAX];
+};
+
+/**
+ * @desc get buddyinfo of specific zone from /proc/buddyinfo
+ * @return negative value if error
+ */
+int proc_get_buddyinfo(const char *zone, struct buddyinfo *bi);
+
+/**
+ * @brief Generic, simplified procfs parser
+ *
+ * @path path to the procfs entry
+ * @parse_args set of arguments specifying regular expressions
+ * to be searched for within the procfs entry
+ * @data custom data supplied to each parse callback function
+ * specified within the parse arguments
+ */
+int proc_parse_entry(const char *path, const struct parse_arg *parse_args,
+ void *data);
+
+/**
+ * @bried /proc/zoneinfo parser
+ */
+static inline int proc_parse_zoneinfo(const struct parse_arg *parse_args,
+ void *data)
+{
+ return proc_parse_entry(PROC_ZONEINFO_PATH, parse_args, data);
+}
+/**
+ * @brief /proc/pagetypeinfo parser
+ */
+static inline int proc_parse_pagetypeinfo(const struct parse_arg *parse_args,
+ void *data)
+{
+ return proc_parse_entry(PROC_PAGETYPEINFO_PATH, parse_args, data);
+}
+
+static inline int proc_parse_buddyinfo(const struct parse_arg *parse_args,
+ void *data)
+{
+ return proc_parse_entry(PROC_BUDDYINFO_PATH, parse_args, data);
+}
+
+struct proc_swaps {
+ char *filename;
+ char *type;
+ unsigned int size;
+ unsigned int used;
+ int priority;
+};
+
+void proc_swap_free(struct proc_swaps *swap);
+void proc_swaps_free(struct proc_swaps **swaps);
+
+static inline void __cleanup_proc_swap_free_func(struct proc_swaps **swap)
+{
+ proc_swap_free(*swap);
+}
+
+#define _cleanup_proc_swap_free_ _cleanup_(__cleanup_proc_swap_free_func)
+
+static inline void __cleanup_proc_swaps_free_func(struct proc_swaps ***swaps)
+{
+ proc_swaps_free(*swaps);
+}
+
+#define _cleanup_proc_swaps_free_ _cleanup_(__cleanup_proc_swaps_free_func)
+
+/**
+ * @desc get swap info from /proc/swaps
+ * @return negative value if errors, positive value means total enties of swap devices
+ */
+int proc_get_swaps(struct proc_swaps ***swaps);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__PROCFS_H__*/
--- /dev/null
+/* NOTE: this file was dynamically generated by gperf but is included verbatim (instead of
+ * being regenerated) due to various build environment issues */
+
+/* ANSI-C code produced by gperf version 3.0.4 */
+/* Command-line: gperf /home/abuild/rpmbuild/BUILD/resourced-6.0.2/src/common/smaps-lookup.gperf */
+/* Computed positions: -k'1,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#include "smaps.h"
+#include <string.h>
+
+#define TOTAL_KEYWORDS 15
+#define MIN_WORD_LENGTH 3
+#define MAX_WORD_LENGTH 14
+#define MIN_HASH_VALUE 3
+#define MAX_HASH_VALUE 24
+/* maximum key range = 22, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+smap_mapping_hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 10, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 5, 0, 0, 25, 25,
+ 0, 25, 5, 0, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 0, 5, 25, 25, 25, 25, 25, 25, 25, 25,
+ 5, 25, 0, 25, 25, 0, 25, 25, 25, 25,
+ 25, 0, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25
+ };
+ return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]];
+}
+
+#ifdef __GNUC__
+__inline
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+const smap_mapping *
+smap_mapping_lookup (register const char *str, register unsigned int len)
+{
+ static const smap_mapping wordlist[] =
+ {
+ {""}, {""}, {""},
+ {"Pss", SMAPS_ID_PSS},
+ {"Swap", SMAPS_ID_SWAP},
+ {"PSwap", SMAPS_ID_PSWAP},
+ {"Locked", SMAPS_ID_LOCKED},
+ {""},
+ {"Rss", SMAPS_ID_RSS},
+ {"Size", SMAPS_ID_SIZE},
+ {""}, {""},
+ {"Shared_Dirty", SMAPS_ID_SHARED_DIRTY},
+ {"Private_Dirty", SMAPS_ID_PRIVATE_DIRTY}, // patrollin' tryna catch me private dirty
+ {""},
+ {"Referenced", SMAPS_ID_REFERENCED},
+ {"MMUPageSize", SMAPS_ID_MMU_PAGE_SIZE},
+ {"Shared_Clean", SMAPS_ID_SHARED_CLEAN},
+ {"Private_Clean", SMAPS_ID_PRIVATE_CLEAN},
+ {"Anonymous", SMAPS_ID_ANONYMOUS},
+ {""}, {""}, {""},
+ {"AnonHugePages", SMAPS_ID_ANON_HUGE_PAGES},
+ {"KernelPageSize", SMAPS_ID_KERNEL_PAGE_SIZE}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = smap_mapping_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
--- /dev/null
+%{
+#include "smaps.h"
+%}
+smap_mapping;
+%language=ANSI-C
+%define slot-name name
+%define hash-function-name smap_mapping_hash
+%define lookup-function-name smap_mapping_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+AnonHugePages, SMAPS_ID_ANON_HUGE_PAGES
+Anonymous, SMAPS_ID_ANONYMOUS
+KernelPageSize, SMAPS_ID_KERNEL_PAGE_SIZE
+Locked, SMAPS_ID_LOCKED
+MMUPageSize, SMAPS_ID_MMU_PAGE_SIZE
+PSwap, SMAPS_ID_PSWAP
+Private_Clean, SMAPS_ID_PRIVATE_CLEAN
+Private_Dirty, SMAPS_ID_PRIVATE_DIRTY
+Pss, SMAPS_ID_PSS
+Referenced, SMAPS_ID_REFERENCED
+Rss, SMAPS_ID_RSS
+Shared_Clean, SMAPS_ID_SHARED_CLEAN
+Shared_Dirty, SMAPS_ID_SHARED_DIRTY
+Size, SMAPS_ID_SIZE
+Swap, SMAPS_ID_SWAP
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * @file smaps.c
+ * @desc get smaps info of process
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "util.h"
+#include "smaps.h"
+#include "trace.h"
+
+static int have_totmaps = 0;
+
+static bool totmaps_available(void)
+{
+ if (have_totmaps == 2)
+ have_totmaps = (access("/proc/1/totmaps", R_OK) == 0);
+
+ return have_totmaps;
+}
+
+static void smap_free(struct smap *map)
+{
+ if (!map)
+ return;
+
+ if (map->mode)
+ free(map->mode);
+
+ if (map->name)
+ free(map->name);
+
+ free(map);
+}
+
+void smaps_free(struct smaps *maps)
+{
+ int i;
+
+ if (!maps)
+ return;
+
+ for (i = 0; i < maps->n_map; i++)
+ smap_free(maps->maps[i]);
+
+ free(maps->maps);
+ free(maps);
+}
+
+static int add_smap_to_smaps(struct smaps *maps, struct smap *map)
+{
+ int i;
+
+ assert(maps);
+ assert(map);
+
+ maps->n_map++;
+
+ maps->maps = (struct smap **)realloc(
+ maps->maps,
+ sizeof(struct smap *) * maps->n_map);
+ if (!maps->maps)
+ return -ENOMEM;
+
+ maps->maps[maps->n_map - 1] = map;
+
+ for (i = 0; i < SMAPS_ID_MAX; i++)
+ maps->sum[i] += map->value[i];
+
+ return 0;
+}
+
+int smaps_get(pid_t pid, struct smaps **maps, enum smap_mask mask)
+{
+ _cleanup_free_ char *path = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ struct smaps *m = NULL;
+ char buf[LINE_MAX];
+ bool get_line = true, totmaps;
+ int r;
+ struct smap *map;
+
+ assert(maps);
+
+ totmaps = totmaps_available();
+ if (totmaps && (mask & ~SMAPS_MASK_TOTMAPS) == 0) {
+ r = asprintf(&path, "/proc/%d/totmaps", pid);
+ } else {
+ totmaps = false;
+ r = asprintf(&path, "/proc/%d/smaps", pid);
+ }
+
+ if (r < 0)
+ return -ENOMEM;
+
+ f = fopen(path, "re");
+ if (!f)
+ return -errno;
+
+ m = new0(struct smaps, 1);
+ if (!m)
+ return -ENOMEM;
+
+ for (;;) {
+ map = NULL;
+ int n;
+ size_t l;
+ enum smap_id id;
+
+ if (get_line && !fgets(buf, sizeof(buf), f)) {
+ if (ferror(f)) {
+ r = -errno;
+ goto on_error;
+ }
+ break;
+ }
+ get_line = true;
+
+ /*
+ * If totmaps are available and the caller doesn't
+ * need fields exclusive to smaps, we use them here.
+ * Reading totmaps is on average 20 times faster than
+ * reading smaps.
+ */
+ if (totmaps) {
+ unsigned int v = 0;
+
+ l = strcspn(buf, ":");
+ if (l >= sizeof(buf) - 2 || !buf[l])
+ goto totmaps_error;
+ buf[l] = 0;
+
+ id = smap_string_to_id(buf);
+ if (id < 0 || id >= SMAPS_ID_MAX)
+ continue;
+
+ if (sscanf(buf + l + 1, "%d kB", &v) != 1)
+ goto totmaps_error;
+
+ m->sum[id] = v;
+ continue;
+
+totmaps_error:
+ _E("Unknown totmaps format, expected: '%%s : %%d kB'");
+ r = -EIO;
+ have_totmaps = 0; // don't ever read totmaps again
+ goto on_error;
+ }
+
+ map = new0(struct smap, 1);
+ if (!map) {
+ r = -errno;
+ goto on_error;
+ }
+
+ n = sscanf(buf, "%x-%x %ms %*s %*s %*s %ms",
+ &map->start, &map->end, &map->mode, &map->name);
+
+ if (n == 3 && !map->name)
+ map->name = strndup("[anon]", strlen("[anon]"));
+ else if (n != 4) {
+ r = -EINVAL;
+ goto on_error;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *k = NULL;
+ unsigned int v = 0;
+
+ if (!fgets(buf, sizeof(buf), f)) {
+ if (ferror(f)) {
+ r = -errno;
+ goto on_error;
+ }
+ break;
+ }
+
+ if ((*buf >= '0' && *buf <= '9') ||
+ (*buf >= 'a' && *buf <= 'f')) {
+ get_line = false;
+ break;
+ }
+
+ l = strcspn(buf, ":");
+ if (l >= sizeof(buf) - 2 || !buf[l])
+ goto on_error;
+
+ if (!l)
+ break;
+
+ k = strndup(buf, l);
+ if (!k) {
+ r = -ENOMEM;
+ goto on_error;
+ }
+
+ id = smap_string_to_id(k);
+ if (id < 0 || id >= SMAPS_ID_MAX)
+ continue;
+
+ if (!(mask & (1 << id)))
+ continue;
+
+ if (sscanf(buf + l + 1, "%d kB", &v) != 1)
+ break;
+
+ map->value[id] = v;
+ }
+
+ r = add_smap_to_smaps(m, map);
+ if (r < 0)
+ goto on_error;
+ }
+
+ *maps = m;
+
+ return 0;
+
+on_error:
+ smap_free(map);
+ smaps_free(m);
+ return r;
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+/*
+ * @file smaps.h
+ * @desc /proc/{PID}/smaps info loopup util
+ */
+
+#ifndef _RESOURCED_SMAPS_H_
+#define _RESOURCED_SMAPS_H_
+
+#include <assert.h>
+#include <string.h>
+
+#include "util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+enum smap_id {
+ SMAPS_ID_INVALID = -1,
+ SMAPS_ID_ANON_HUGE_PAGES = 0,
+ SMAPS_ID_ANONYMOUS,
+ SMAPS_ID_KERNEL_PAGE_SIZE,
+ SMAPS_ID_LOCKED,
+ SMAPS_ID_MMU_PAGE_SIZE,
+ SMAPS_ID_PSWAP,
+ SMAPS_ID_PRIVATE_CLEAN,
+ SMAPS_ID_PRIVATE_DIRTY,
+ SMAPS_ID_PSS,
+ SMAPS_ID_REFERENCED,
+ SMAPS_ID_RSS,
+ SMAPS_ID_SHARED_CLEAN,
+ SMAPS_ID_SHARED_DIRTY,
+ SMAPS_ID_SIZE,
+ SMAPS_ID_SWAP,
+ SMAPS_ID_MAX,
+};
+
+enum smap_mask {
+ SMAPS_MASK_ANON_HUGE_PAGES = 1 << SMAPS_ID_ANON_HUGE_PAGES,
+ SMAPS_MASK_ANONYMOUS = 1 << SMAPS_ID_ANONYMOUS,
+ SMAPS_MASK_KERNEL_PAGE_SIZE = 1 << SMAPS_ID_KERNEL_PAGE_SIZE,
+ SMAPS_MASK_LOCKED = 1 << SMAPS_ID_LOCKED,
+ SMAPS_MASK_MMU_PAGE_SIZE = 1 << SMAPS_ID_MMU_PAGE_SIZE,
+ SMAPS_MASK_PSWAP = 1 << SMAPS_ID_PSWAP,
+ SMAPS_MASK_PRIVATE_CLEAN = 1 << SMAPS_ID_PRIVATE_CLEAN,
+ SMAPS_MASK_PRIVATE_DIRTY = 1 << SMAPS_ID_PRIVATE_DIRTY,
+ SMAPS_MASK_PSS = 1 << SMAPS_ID_PSS,
+ SMAPS_MASK_REFERENCED = 1 << SMAPS_ID_REFERENCED,
+ SMAPS_MASK_RSS = 1 << SMAPS_ID_RSS,
+ SMAPS_MASK_SHARED_CLEAN = 1 << SMAPS_ID_SHARED_CLEAN,
+ SMAPS_MASK_SHARED_DIRTY = 1 << SMAPS_ID_SHARED_DIRTY,
+ SMAPS_MASK_SIZE = 1 << SMAPS_ID_SIZE,
+ SMAPS_MASK_SWAP = 1 << SMAPS_ID_SWAP,
+ SMAPS_MASK_ALL = (1 << SMAPS_ID_MAX) - 1,
+ SMAPS_MASK_TOTMAPS = SMAPS_MASK_RSS | SMAPS_MASK_PSS
+ | SMAPS_MASK_SHARED_CLEAN | SMAPS_MASK_SHARED_DIRTY
+ | SMAPS_MASK_PRIVATE_CLEAN | SMAPS_MASK_PRIVATE_DIRTY
+ | SMAPS_MASK_REFERENCED | SMAPS_MASK_ANONYMOUS
+ | SMAPS_MASK_ANON_HUGE_PAGES | SMAPS_MASK_SWAP
+};
+
+struct smap_mapping {
+ const char* name;
+ enum smap_id id;
+};
+typedef struct smap_mapping smap_mapping;
+
+const smap_mapping *smap_mapping_lookup(const char *str, unsigned int len);
+
+static inline enum smap_id smap_string_to_id(const char *str)
+{
+ const struct smap_mapping *m;
+
+ assert(str);
+ m = smap_mapping_lookup(str,
+ strlen(str));
+ return m ? m->id : SMAPS_ID_INVALID;
+}
+
+struct smap {
+ unsigned int start;
+ unsigned int end;
+ char *mode;
+ char *name;
+ unsigned int value[SMAPS_ID_MAX];
+};
+
+struct smaps {
+ unsigned int sum[SMAPS_ID_MAX];
+ int n_map;
+ struct smap **maps;
+};
+
+void smaps_free(struct smaps *maps);
+int smaps_get(pid_t pid, struct smaps **maps, enum smap_mask mask);
+
+static inline void smaps_freep(struct smaps **maps)
+{
+ if (*maps)
+ smaps_free(*maps);
+}
+
+#define _cleanup_smaps_free_ _cleanup_(smaps_freep)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RESOURCED_SMAPS_H_ */
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/**
- * @file safe-kill.c
- *
- * @desc check if process is dumping core before sending a signal
- *
- * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include "safe-kill.h"
-#include "trace.h"
-#include "util.h"
-#include "macro.h"
-#include <signal.h>
-#include <stdio.h>
-#include <limits.h>
-#include <stdbool.h>
-
-EXPORT_TEST bool is_process_coredumping(pid_t pid)
-{
- char buf[LINE_MAX];
- _cleanup_fclose_ FILE *fp = NULL;
- int val = 0;
-
- snprintf(buf, sizeof buf, "/proc/%d/status", pid);
- fp = fopen(buf, "r");
- if (!fp)
- return false;
-
- while (fgets(buf, sizeof(buf), fp)) {
- /* Skip the lines, until first match */
- if (!strstart_with(buf, "CoreDumping:"))
- continue;
-
- if (sscanf(buf, "CoreDumping: %d", &val) == 1)
- break;
-
- return false;
- }
-
- return (val == 1);
-}
-
-int safe_kill(pid_t pid, int sig)
-{
- /* Pass signals other than SIGKILL, as other signals are not delivered to
- * a process that's dumping a core anyway, and SIGKILL is the only one that
- * can potentially break that process.
- * Alternatively, with SIGKILL check if process is coredumping.
- */
- if (sig != SIGKILL || !is_process_coredumping(pid)) {
- _D("safe-kill: delivering signal %d to process %d immediately", sig, pid);
- return kill(pid, sig);
- }
-
- _I("safe-kill: process %d is coredumping - signal SIGKILL not sent", pid);
- return 0;
-}
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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 SAFE_KILL_H
-#define SAFE_KILL_H
-
-#include <sys/types.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-int safe_kill(pid_t pid, int sig);
-
-#ifdef _UNIT_TEST
-bool is_process_coredumping(pid_t pid);
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* SAFE_KILL_H */
+++ /dev/null
-/* NOTE: this file was dynamically generated by gperf but is included verbatim (instead of
- * being regenerated) due to various build environment issues */
-
-/* ANSI-C code produced by gperf version 3.0.4 */
-/* Command-line: gperf /home/abuild/rpmbuild/BUILD/resourced-6.0.2/src/common/smaps-lookup.gperf */
-/* Computed positions: -k'1,$' */
-
-#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
- && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
- && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
- && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
- && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
- && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
- && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
- && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
- && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
- && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
- && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
- && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
- && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
- && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
- && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
- && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
- && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
- && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
- && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
- && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
- && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
- && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
- && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
-/* The character set is not based on ISO-646. */
-#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
-#endif
-
-#include "smaps.h"
-#include <string.h>
-
-#define TOTAL_KEYWORDS 15
-#define MIN_WORD_LENGTH 3
-#define MAX_WORD_LENGTH 14
-#define MIN_HASH_VALUE 3
-#define MAX_HASH_VALUE 24
-/* maximum key range = 22, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-static unsigned int
-smap_mapping_hash (register const char *str, register unsigned int len)
-{
- static const unsigned char asso_values[] =
- {
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 10, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 5, 0, 0, 25, 25,
- 0, 25, 5, 0, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 0, 5, 25, 25, 25, 25, 25, 25, 25, 25,
- 5, 25, 0, 25, 25, 0, 25, 25, 25, 25,
- 25, 0, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25
- };
- return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]];
-}
-
-#ifdef __GNUC__
-__inline
-#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
-__attribute__ ((__gnu_inline__))
-#endif
-#endif
-const smap_mapping *
-smap_mapping_lookup (register const char *str, register unsigned int len)
-{
- static const smap_mapping wordlist[] =
- {
- {""}, {""}, {""},
- {"Pss", SMAPS_ID_PSS},
- {"Swap", SMAPS_ID_SWAP},
- {"PSwap", SMAPS_ID_PSWAP},
- {"Locked", SMAPS_ID_LOCKED},
- {""},
- {"Rss", SMAPS_ID_RSS},
- {"Size", SMAPS_ID_SIZE},
- {""}, {""},
- {"Shared_Dirty", SMAPS_ID_SHARED_DIRTY},
- {"Private_Dirty", SMAPS_ID_PRIVATE_DIRTY}, // patrollin' tryna catch me private dirty
- {""},
- {"Referenced", SMAPS_ID_REFERENCED},
- {"MMUPageSize", SMAPS_ID_MMU_PAGE_SIZE},
- {"Shared_Clean", SMAPS_ID_SHARED_CLEAN},
- {"Private_Clean", SMAPS_ID_PRIVATE_CLEAN},
- {"Anonymous", SMAPS_ID_ANONYMOUS},
- {""}, {""}, {""},
- {"AnonHugePages", SMAPS_ID_ANON_HUGE_PAGES},
- {"KernelPageSize", SMAPS_ID_KERNEL_PAGE_SIZE}
- };
-
- if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
- {
- register int key = smap_mapping_hash (str, len);
-
- if (key <= MAX_HASH_VALUE && key >= 0)
- {
- register const char *s = wordlist[key].name;
-
- if (*str == *s && !strcmp (str + 1, s + 1))
- return &wordlist[key];
- }
- }
- return 0;
-}
+++ /dev/null
-%{
-#include "smaps.h"
-%}
-smap_mapping;
-%language=ANSI-C
-%define slot-name name
-%define hash-function-name smap_mapping_hash
-%define lookup-function-name smap_mapping_lookup
-%readonly-tables
-%omit-struct-type
-%struct-type
-%includes
-%%
-AnonHugePages, SMAPS_ID_ANON_HUGE_PAGES
-Anonymous, SMAPS_ID_ANONYMOUS
-KernelPageSize, SMAPS_ID_KERNEL_PAGE_SIZE
-Locked, SMAPS_ID_LOCKED
-MMUPageSize, SMAPS_ID_MMU_PAGE_SIZE
-PSwap, SMAPS_ID_PSWAP
-Private_Clean, SMAPS_ID_PRIVATE_CLEAN
-Private_Dirty, SMAPS_ID_PRIVATE_DIRTY
-Pss, SMAPS_ID_PSS
-Referenced, SMAPS_ID_REFERENCED
-Rss, SMAPS_ID_RSS
-Shared_Clean, SMAPS_ID_SHARED_CLEAN
-Shared_Dirty, SMAPS_ID_SHARED_DIRTY
-Size, SMAPS_ID_SIZE
-Swap, SMAPS_ID_SWAP
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/*
- * @file smaps.c
- * @desc get smaps info of process
- */
-
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-
-#include "util.h"
-#include "smaps.h"
-#include "trace.h"
-
-static int have_totmaps = 0;
-
-static bool totmaps_available(void)
-{
- if (have_totmaps == 2)
- have_totmaps = (access("/proc/1/totmaps", R_OK) == 0);
-
- return have_totmaps;
-}
-
-static void smap_free(struct smap *map)
-{
- if (!map)
- return;
-
- if (map->mode)
- free(map->mode);
-
- if (map->name)
- free(map->name);
-
- free(map);
-}
-
-void smaps_free(struct smaps *maps)
-{
- int i;
-
- if (!maps)
- return;
-
- for (i = 0; i < maps->n_map; i++)
- smap_free(maps->maps[i]);
-
- free(maps->maps);
- free(maps);
-}
-
-static int add_smap_to_smaps(struct smaps *maps, struct smap *map)
-{
- int i;
-
- assert(maps);
- assert(map);
-
- maps->n_map++;
-
- maps->maps = (struct smap **)realloc(
- maps->maps,
- sizeof(struct smap *) * maps->n_map);
- if (!maps->maps)
- return -ENOMEM;
-
- maps->maps[maps->n_map - 1] = map;
-
- for (i = 0; i < SMAPS_ID_MAX; i++)
- maps->sum[i] += map->value[i];
-
- return 0;
-}
-
-int smaps_get(pid_t pid, struct smaps **maps, enum smap_mask mask)
-{
- _cleanup_free_ char *path = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- struct smaps *m = NULL;
- char buf[LINE_MAX];
- bool get_line = true, totmaps;
- int r;
- struct smap *map;
-
- assert(maps);
-
- totmaps = totmaps_available();
- if (totmaps && (mask & ~SMAPS_MASK_TOTMAPS) == 0) {
- r = asprintf(&path, "/proc/%d/totmaps", pid);
- } else {
- totmaps = false;
- r = asprintf(&path, "/proc/%d/smaps", pid);
- }
-
- if (r < 0)
- return -ENOMEM;
-
- f = fopen(path, "re");
- if (!f)
- return -errno;
-
- m = new0(struct smaps, 1);
- if (!m)
- return -ENOMEM;
-
- for (;;) {
- map = NULL;
- int n;
- size_t l;
- enum smap_id id;
-
- if (get_line && !fgets(buf, sizeof(buf), f)) {
- if (ferror(f)) {
- r = -errno;
- goto on_error;
- }
- break;
- }
- get_line = true;
-
- /*
- * If totmaps are available and the caller doesn't
- * need fields exclusive to smaps, we use them here.
- * Reading totmaps is on average 20 times faster than
- * reading smaps.
- */
- if (totmaps) {
- unsigned int v = 0;
-
- l = strcspn(buf, ":");
- if (l >= sizeof(buf) - 2 || !buf[l])
- goto totmaps_error;
- buf[l] = 0;
-
- id = smap_string_to_id(buf);
- if (id < 0 || id >= SMAPS_ID_MAX)
- continue;
-
- if (sscanf(buf + l + 1, "%d kB", &v) != 1)
- goto totmaps_error;
-
- m->sum[id] = v;
- continue;
-
-totmaps_error:
- _E("Unknown totmaps format, expected: '%%s : %%d kB'");
- r = -EIO;
- have_totmaps = 0; // don't ever read totmaps again
- goto on_error;
- }
-
- map = new0(struct smap, 1);
- if (!map) {
- r = -errno;
- goto on_error;
- }
-
- n = sscanf(buf, "%x-%x %ms %*s %*s %*s %ms",
- &map->start, &map->end, &map->mode, &map->name);
-
- if (n == 3 && !map->name)
- map->name = strndup("[anon]", strlen("[anon]"));
- else if (n != 4) {
- r = -EINVAL;
- goto on_error;
- }
-
- for (;;) {
- _cleanup_free_ char *k = NULL;
- unsigned int v = 0;
-
- if (!fgets(buf, sizeof(buf), f)) {
- if (ferror(f)) {
- r = -errno;
- goto on_error;
- }
- break;
- }
-
- if ((*buf >= '0' && *buf <= '9') ||
- (*buf >= 'a' && *buf <= 'f')) {
- get_line = false;
- break;
- }
-
- l = strcspn(buf, ":");
- if (l >= sizeof(buf) - 2 || !buf[l])
- goto on_error;
-
- if (!l)
- break;
-
- k = strndup(buf, l);
- if (!k) {
- r = -ENOMEM;
- goto on_error;
- }
-
- id = smap_string_to_id(k);
- if (id < 0 || id >= SMAPS_ID_MAX)
- continue;
-
- if (!(mask & (1 << id)))
- continue;
-
- if (sscanf(buf + l + 1, "%d kB", &v) != 1)
- break;
-
- map->value[id] = v;
- }
-
- r = add_smap_to_smaps(m, map);
- if (r < 0)
- goto on_error;
- }
-
- *maps = m;
-
- return 0;
-
-on_error:
- smap_free(map);
- smaps_free(m);
- return r;
-}
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
-*/
-
-/*
- * @file smaps.h
- * @desc /proc/{PID}/smaps info loopup util
- */
-
-#ifndef _RESOURCED_SMAPS_H_
-#define _RESOURCED_SMAPS_H_
-
-#include <assert.h>
-#include <string.h>
-
-#include "util.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-enum smap_id {
- SMAPS_ID_INVALID = -1,
- SMAPS_ID_ANON_HUGE_PAGES = 0,
- SMAPS_ID_ANONYMOUS,
- SMAPS_ID_KERNEL_PAGE_SIZE,
- SMAPS_ID_LOCKED,
- SMAPS_ID_MMU_PAGE_SIZE,
- SMAPS_ID_PSWAP,
- SMAPS_ID_PRIVATE_CLEAN,
- SMAPS_ID_PRIVATE_DIRTY,
- SMAPS_ID_PSS,
- SMAPS_ID_REFERENCED,
- SMAPS_ID_RSS,
- SMAPS_ID_SHARED_CLEAN,
- SMAPS_ID_SHARED_DIRTY,
- SMAPS_ID_SIZE,
- SMAPS_ID_SWAP,
- SMAPS_ID_MAX,
-};
-
-enum smap_mask {
- SMAPS_MASK_ANON_HUGE_PAGES = 1 << SMAPS_ID_ANON_HUGE_PAGES,
- SMAPS_MASK_ANONYMOUS = 1 << SMAPS_ID_ANONYMOUS,
- SMAPS_MASK_KERNEL_PAGE_SIZE = 1 << SMAPS_ID_KERNEL_PAGE_SIZE,
- SMAPS_MASK_LOCKED = 1 << SMAPS_ID_LOCKED,
- SMAPS_MASK_MMU_PAGE_SIZE = 1 << SMAPS_ID_MMU_PAGE_SIZE,
- SMAPS_MASK_PSWAP = 1 << SMAPS_ID_PSWAP,
- SMAPS_MASK_PRIVATE_CLEAN = 1 << SMAPS_ID_PRIVATE_CLEAN,
- SMAPS_MASK_PRIVATE_DIRTY = 1 << SMAPS_ID_PRIVATE_DIRTY,
- SMAPS_MASK_PSS = 1 << SMAPS_ID_PSS,
- SMAPS_MASK_REFERENCED = 1 << SMAPS_ID_REFERENCED,
- SMAPS_MASK_RSS = 1 << SMAPS_ID_RSS,
- SMAPS_MASK_SHARED_CLEAN = 1 << SMAPS_ID_SHARED_CLEAN,
- SMAPS_MASK_SHARED_DIRTY = 1 << SMAPS_ID_SHARED_DIRTY,
- SMAPS_MASK_SIZE = 1 << SMAPS_ID_SIZE,
- SMAPS_MASK_SWAP = 1 << SMAPS_ID_SWAP,
- SMAPS_MASK_ALL = (1 << SMAPS_ID_MAX) - 1,
- SMAPS_MASK_TOTMAPS = SMAPS_MASK_RSS | SMAPS_MASK_PSS
- | SMAPS_MASK_SHARED_CLEAN | SMAPS_MASK_SHARED_DIRTY
- | SMAPS_MASK_PRIVATE_CLEAN | SMAPS_MASK_PRIVATE_DIRTY
- | SMAPS_MASK_REFERENCED | SMAPS_MASK_ANONYMOUS
- | SMAPS_MASK_ANON_HUGE_PAGES | SMAPS_MASK_SWAP
-};
-
-struct smap_mapping {
- const char* name;
- enum smap_id id;
-};
-typedef struct smap_mapping smap_mapping;
-
-const smap_mapping *smap_mapping_lookup(const char *str, unsigned int len);
-
-static inline enum smap_id smap_string_to_id(const char *str)
-{
- const struct smap_mapping *m;
-
- assert(str);
- m = smap_mapping_lookup(str,
- strlen(str));
- return m ? m->id : SMAPS_ID_INVALID;
-}
-
-struct smap {
- unsigned int start;
- unsigned int end;
- char *mode;
- char *name;
- unsigned int value[SMAPS_ID_MAX];
-};
-
-struct smaps {
- unsigned int sum[SMAPS_ID_MAX];
- int n_map;
- struct smap **maps;
-};
-
-void smaps_free(struct smaps *maps);
-int smaps_get(pid_t pid, struct smaps **maps, enum smap_mask mask);
-
-static inline void smaps_freep(struct smaps **maps)
-{
- if (*maps)
- smaps_free(*maps);
-}
-
-#define _cleanup_smaps_free_ _cleanup_(smaps_freep)
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _RESOURCED_SMAPS_H_ */
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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 "macro.h"
-#include "swap-common.h"
-#include "trace.h"
-
-static struct swap_conf *swap_conf = NULL;
-
-static enum swap_state swap_state = SWAP_OFF;
-
-struct swap_conf *get_swap_conf(void)
-{
- if (!swap_conf) {
- swap_conf = (struct swap_conf *)calloc(1, sizeof (struct swap_conf));
- if (!swap_conf) {
- _E("Failed to alloc memory for cpu configuration");
- return NULL;
- }
- else {
- swap_conf->enable = false;
- swap_conf->boot_reclaim_enable = false;
- swap_conf->swap_type = SWAP_TYPE_NONE;
- swap_conf->swappiness[MEMCG_THROTTLING] = MEMORY_INIT_SWAPPINESS;
- }
- }
-
- return swap_conf;
-}
-
-
-void free_swap_conf(void)
-{
- if (swap_conf)
- free(swap_conf);
-}
-
-enum swap_state swap_get_state(void)
-{
- return swap_state;
-}
-
-/* Following function is supposed to be used by swap module only.
- *
- * Implemented in common part for the purpose of integration with
- * dynamically loaded "swap" plugin.
- *
- * From available options it seems cleaner to export getter/setter
- * like the one below (with a bit of swap-internal logic).
- * Other option would be keeping set function in swap module, but
- * that would require us to reference and alter then-global swap_state
- * variable (in common part) from swap shared object.
- */
-void swap_set_state(enum swap_state state)
-{
- if ((state != SWAP_ON) && (state != SWAP_OFF))
- return;
-
- swap_state = state;
-}
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
- */
-
-/**
- * @file swap-common.h
- * @desc swap common process
- **/
-
-#ifndef __SWAP_COMMON_H__
-#define __SWAP_COMMON_H__
-
-#include <stdio.h>
-#include "resourced.h"
-#include "memory-cgroup.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define SWAP_ZRAM_SYSFILE "/sys/block/zram0/"
-#define SWAP_FILE_NAME "/opt/usr/.swapfile"
-#define SWAP_CONF_FILE RD_CONFIG_FILE(optimizer)
-
-#define MEMORY_INIT_SWAPPINESS 200
-
-enum swap_state {
- SWAP_ARG_START = -1,
- SWAP_OFF,
- SWAP_ON,
- SWAP_ARG_END,
-};
-
-enum swap_type {
- SWAP_TYPE_NONE = 0x0,
- SWAP_TYPE_ZRAM = 0x1,
- SWAP_TYPE_FILE = 0x2,
- SWAP_TYPE_ZSWAP = 0x4,
- SWAP_TYPE_MAX,
-};
-
-struct swap_status_msg {
- char path[MAX_PATH_LENGTH];
-};
-
-enum swap_compact_reason {
- SWAP_COMPACT_MEM_LEVEL_CRITICAL,
- SWAP_COMPACT_MEM_LEVEL_OOM,
- SWAP_COMPACT_SWAP_FULL,
- SWAP_COMPACT_RESASON_MAX,
-};
-
-/*
- * Each swap modoule can have priority.
- * The swap list of kernel has low-to-high order
- * while swap ordering is high-to-low.
- * So, if a swap module has lower priority, it should be intialized eariler.
- * On the top of that, SWAP_PRI_DISABLE will be used
- * not to support multiple swap devices.
- */
-enum swap_priority {
- SWAP_PRI_DISABLE = -255,
- SWAP_PRI_LOW = -1,
- SWAP_PRI_DEFAULT = 0,
- SWAP_PRI_HIGH = 1,
-};
-
-struct swap_module_ops {
- char *name;
- enum swap_type type;
- char *path;
- int priority;
- unsigned int k_size;
- int (*init)(void *data);
- int (*exit) (void *data);
- int (*activate)(void *data);
- int (*reclaim)(void *data);
- int (*conf)(void *data);
-};
-
-struct zram_conf {
- char algorithm[MAX_TYPE_LENGTH - 1];
- float ratio;
-};
-
-struct zswap_conf {
- float pool_ratio;
- char pool_type[MAX_TYPE_LENGTH -1];
-};
-
-struct swap_conf {
- bool enable;
- bool boot_reclaim_enable;
- enum swap_type swap_type;
- int swappiness[MEMCG_END];
- struct zram_conf zram;
- struct zswap_conf zswap;
-};
-
-struct swap_conf *get_swap_conf(void);
-void free_swap_conf(void);
-
-enum swap_state swap_get_state(void);
-void swap_set_state(enum swap_state state);
-
-int swap_set_file(char *file, struct swap_module_ops *swap, char *crypt_type);
-int do_mkswap(const char *device);
-int do_dd(char *input, char *output, unsigned int size, unsigned int count);
-
-bool swap_is_on(const char *name);
-
-void swap_add(const struct swap_module_ops *swap);
-void swap_remove(const struct swap_module_ops *swap);
-
-#define SWAP_MODULE_REGISTER(swap) \
-static void __attribute__ ((constructor)) swap_module_register(void) \
-{ \
- swap_add(swap); \
-} \
-static void __attribute__ ((destructor)) swap_module_unregister(void) \
-{ \
- swap_remove(swap); \
-}
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __SWAP_COMMON_H__ */
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
-*/
-
-/*
- * @file proc-priority.c
- * @desc set specific priority to predefined application
-*/
-
-#include <glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "lowmem-handler.h"
-#include "cpu-cgroup.h"
-#include "config-parser.h"
-#include "const.h"
-#include "module.h"
-#include "notifier.h"
-#include "proc-common.h"
-#include "proc-main.h"
-#include "procfs.h"
-#include "resourced.h"
-#include "trace.h"
-#include "cpu-common.h"
-
-static GHashTable *fixed_app_list;
-static GHashTable *fixed_service_list;
-static GHashTable *fixed_process_list;
-
-void fixed_app_and_service_list_init(void)
-{
- fixed_app_list = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free);
- fixed_service_list = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free);
- fixed_process_list = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free);
- g_assert(fixed_app_list && fixed_service_list && fixed_process_list);
-}
-
-void fixed_app_and_service_list_exit(void)
-{
- if (fixed_app_list)
- g_hash_table_destroy(fixed_app_list);
- if (fixed_service_list)
- g_hash_table_destroy(fixed_service_list);
- if (fixed_process_list)
- g_hash_table_destroy(fixed_process_list);
-}
-
-void fixed_app_list_insert(struct proc_conf_info *pci)
-{
- g_hash_table_insert(fixed_app_list, (gpointer)pci->name, (gpointer)pci);
-}
-
-void fixed_service_list_insert(struct proc_conf_info *pci)
-{
- g_hash_table_insert(fixed_service_list, (gpointer)pci->name, (gpointer)pci);
-}
-
-void fixed_process_list_insert(struct proc_conf_info *pci)
-{
- g_hash_table_insert(fixed_process_list, (gpointer)pci->name, (gpointer)pci);
-}
-
-GHashTable* fixed_app_list_get(void)
-{
- return fixed_app_list;
-}
-
-GHashTable* fixed_service_list_get(void)
-{
- return fixed_service_list;
-}
-
-GHashTable* fixed_process_list_get(void)
-{
- return fixed_process_list;
-}
-
-struct proc_conf_info* fixed_app_and_service_exist_check(const char *name, enum proc_type proc_type)
-{
- if (proc_type != APP_TYPE && proc_type != SERVICE_TYPE && proc_type != PROCESS_TYPE) {
- _E("Unknown type (we support only app, service, and process types)");
- return NULL;
- }
-
- if (proc_type == APP_TYPE) {
- if (g_hash_table_size(fixed_app_list) == 0)
- return NULL;
-
- return (struct proc_conf_info *)g_hash_table_lookup(fixed_app_list, name);
- }
- else if (proc_type == SERVICE_TYPE) {
- if (g_hash_table_size(fixed_service_list) == 0)
- return NULL;
-
- return (struct proc_conf_info *)g_hash_table_lookup(fixed_service_list, name);
- }
- else {
- if (g_hash_table_size(fixed_process_list) == 0)
- return NULL;
-
- return (struct proc_conf_info *)g_hash_table_lookup(fixed_process_list, name);
- }
-}
-
-enum proc_action fixed_app_and_service_watchdog_action(const char *name, enum proc_type proc_type)
-{
- struct proc_conf_info *pci;
-
- pci = fixed_app_and_service_exist_check(name, proc_type);
- if (pci) {
- return pci->watchdog_action;
- }
- else {
- return PROC_ACTION_KILL;
- }
-}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+/*
+ * @file proc-priority.c
+ * @desc set specific priority to predefined application
+*/
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lowmem-handler.h"
+#include "cpu-cgroup.h"
+#include "config-parser.h"
+#include "const.h"
+#include "module.h"
+#include "notifier.h"
+#include "proc-common.h"
+#include "proc-main.h"
+#include "procfs.h"
+#include "resourced.h"
+#include "trace.h"
+#include "cpu-common.h"
+
+static GHashTable *fixed_app_list;
+static GHashTable *fixed_service_list;
+static GHashTable *fixed_process_list;
+
+void fixed_app_and_service_list_init(void)
+{
+ fixed_app_list = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free);
+ fixed_service_list = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free);
+ fixed_process_list = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free);
+ g_assert(fixed_app_list && fixed_service_list && fixed_process_list);
+}
+
+void fixed_app_and_service_list_exit(void)
+{
+ if (fixed_app_list)
+ g_hash_table_destroy(fixed_app_list);
+ if (fixed_service_list)
+ g_hash_table_destroy(fixed_service_list);
+ if (fixed_process_list)
+ g_hash_table_destroy(fixed_process_list);
+}
+
+void fixed_app_list_insert(struct proc_conf_info *pci)
+{
+ g_hash_table_insert(fixed_app_list, (gpointer)pci->name, (gpointer)pci);
+}
+
+void fixed_service_list_insert(struct proc_conf_info *pci)
+{
+ g_hash_table_insert(fixed_service_list, (gpointer)pci->name, (gpointer)pci);
+}
+
+void fixed_process_list_insert(struct proc_conf_info *pci)
+{
+ g_hash_table_insert(fixed_process_list, (gpointer)pci->name, (gpointer)pci);
+}
+
+GHashTable* fixed_app_list_get(void)
+{
+ return fixed_app_list;
+}
+
+GHashTable* fixed_service_list_get(void)
+{
+ return fixed_service_list;
+}
+
+GHashTable* fixed_process_list_get(void)
+{
+ return fixed_process_list;
+}
+
+struct proc_conf_info* fixed_app_and_service_exist_check(const char *name, enum proc_type proc_type)
+{
+ if (proc_type != APP_TYPE && proc_type != SERVICE_TYPE && proc_type != PROCESS_TYPE) {
+ _E("Unknown type (we support only app, service, and process types)");
+ return NULL;
+ }
+
+ if (proc_type == APP_TYPE) {
+ if (g_hash_table_size(fixed_app_list) == 0)
+ return NULL;
+
+ return (struct proc_conf_info *)g_hash_table_lookup(fixed_app_list, name);
+ }
+ else if (proc_type == SERVICE_TYPE) {
+ if (g_hash_table_size(fixed_service_list) == 0)
+ return NULL;
+
+ return (struct proc_conf_info *)g_hash_table_lookup(fixed_service_list, name);
+ }
+ else {
+ if (g_hash_table_size(fixed_process_list) == 0)
+ return NULL;
+
+ return (struct proc_conf_info *)g_hash_table_lookup(fixed_process_list, name);
+ }
+}
+
+enum proc_action fixed_app_and_service_watchdog_action(const char *name, enum proc_type proc_type)
+{
+ struct proc_conf_info *pci;
+
+ pci = fixed_app_and_service_exist_check(name, proc_type);
+ if (pci) {
+ return pci->watchdog_action;
+ }
+ else {
+ return PROC_ACTION_KILL;
+ }
+}
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+/**
+ * @file cpu.c
+ *
+ * @desc cpu module
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+#include <dirent.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include "notifier.h"
+#include "procfs.h"
+#include "proc-common.h"
+#include "macro.h"
+#include "module.h"
+#include "module-data.h"
+#include "resourced.h"
+#include "trace.h"
+#include "vconf.h"
+#include "util.h"
+#include "cgroup.h"
+#include "config-parser.h"
+#include "const.h"
+#include "file-helper.h"
+#include "cpu-cgroup.h"
+
+#define CPU_CONF_FILE RD_CONFIG_FILE(limiter)
+#define CPU_CONF_SECTION "CPU"
+#define CPU_CONF_PREDEFINE "PREDEFINE"
+#define CPU_CONF_BOOTING "BOOTING_PREDEFINE"
+#define CPU_CONF_WRT "WRT_PREDEFINE"
+#define CPU_CONF_LAZY "LAZY_PREDEFINE"
+#define MAX_PREDEFINED_TASKS 10
+#define CPU_TIMER_INTERVAL 30
+#define CPU_BACKGROUND_PRI 1
+#define CPU_CONTROL_PRI 10
+
+bool throttling_success = false;
+bool skip_bandwidth = false;
+bool skip_share = false;
+struct sched_attr throttling_attr;
+struct sched_attr normal_attr;
+
+static int move_process_to_throttling_group(pid_t pid, struct proc_app_info *pai)
+{
+ GSList *iter = NULL;
+ pid_t child_pid;
+
+ if (!throttling_success)
+ return RESOURCED_ERROR_NONE;
+
+ if (pai) {
+ if (pai->app_cpu_nice_update_exclude)
+ goto cpu_cgroup_move;
+
+ sched_setattr_of_all_tasks(pai->main_pid, &throttling_attr, 0);
+ if (pai->childs) {
+ gslist_for_each_item(iter, pai->childs) {
+ child_pid = GPOINTER_TO_PID(iter->data);
+ sched_setattr_of_all_tasks(child_pid, &throttling_attr, 0);
+ }
+ }
+ }
+ else {
+ sched_setattr_of_all_tasks(pid, &throttling_attr, 0);
+ }
+
+cpu_cgroup_move:
+ if (!skip_share || !skip_bandwidth)
+ return cpu_move_cgroup_foreach(pid, pai, CPUCG_THROTTLING_PATH);
+ else
+ return RESOURCED_ERROR_NONE;
+}
+
+static int move_out_process_from_throttling_group(pid_t pid, struct proc_app_info *pai)
+{
+ GSList *iter = NULL;
+ pid_t child_pid;
+
+ if (!throttling_success)
+ return RESOURCED_ERROR_NONE;
+
+ if (pai) {
+ if (pai->app_cpu_nice_update_exclude)
+ goto cpu_cgroup_move;
+
+ sched_setattr_of_all_tasks(pai->main_pid, &normal_attr, 0);
+ if (pai->childs) {
+ gslist_for_each_item(iter, pai->childs) {
+ child_pid = GPOINTER_TO_PID(iter->data);
+ sched_setattr_of_all_tasks(child_pid, &normal_attr, 0);
+ }
+ }
+ }
+ else {
+ sched_setattr_of_all_tasks(pid, &normal_attr, 0);
+ }
+
+cpu_cgroup_move:
+ if (!skip_share || !skip_bandwidth)
+ return cpu_move_cgroup_foreach(pid, pai, CPUCG_PATH);
+ else
+ return RESOURCED_ERROR_NONE;
+}
+
+static int cpu_foreground_state(void *data)
+{
+ int ret;
+ struct proc_status *ps = (struct proc_status *)data;
+
+ assert(ps);
+ _D("app foreground: pid = %d", ps->pid);
+ ret = move_out_process_from_throttling_group(ps->pid, ps->pai);
+ if (ret < 0)
+ _E("Failed to throttle cpu resource of %s%s process (%d)",
+ ps->pai ? "App " : "System service",
+ ps->pai ? ps->pai->appid : "", ps->pid);
+ return RESOURCED_ERROR_NONE;
+}
+
+static int cpu_background_state(void *data)
+{
+ int ret;
+ struct proc_status *ps = (struct proc_status *)data;
+ assert(ps);
+
+ _D("app background: pid = %d", ps->pid);
+ ret = move_process_to_throttling_group(ps->pid, ps->pai);
+ if (ret < 0)
+ _E("Failed to throttle cpu resource of %s%s process (%d)",
+ ps->pai ? "App " : "System service",
+ ps->pai ? ps->pai->appid : "", ps->pid);
+ return RESOURCED_ERROR_NONE;
+}
+
+static void load_cpu_throttling_config(void)
+{
+ int ret;
+ int cpu_nice;
+ long long cpu_runtime_us;
+ unsigned long long cpu_period_us;
+ unsigned long long cpu_share;
+ enum cpu_sched_type cpu_sched_type;
+
+ struct cpu_throttling_conf *cpu_throttling_conf = get_cpu_throttling_conf();
+ if (cpu_throttling_conf == NULL) {
+ _E("[CPU-THROTTLING] cpu sched configuration structure should not be NULL");
+ return;
+ }
+
+ if (!cpu_throttling_conf->enable) {
+ _I("[CPU-THROTTLING] cpu throttling is disabled");
+ goto free_cpu_throttling_conf;
+ }
+
+ cpu_nice = cpu_throttling_conf->cpu_sched_info.cpu_nice;
+ cpu_sched_type = cpu_throttling_conf->cpu_sched_info.cpu_sched_type;
+ cpu_share = cpu_throttling_conf->cpu_cgroup_info.cpu_share;
+ cpu_period_us = cpu_throttling_conf->cpu_cgroup_info.cfs_period_us;
+ cpu_runtime_us = cpu_throttling_conf->cpu_cgroup_info.cfs_runtime_us;
+
+ if (cpu_share == 0) {
+ _E("[CPU-THROTTLING] cpu share cannot be 0");
+ cpu_share = CPU_THROTTLING_SHARE;
+ skip_share = true;
+ }
+
+ if (cpu_period_us == 0 || cpu_runtime_us == 0 ||
+ cpu_period_us < cpu_runtime_us) {
+ _E("[CPU-THROTTLING] cpu period (%llu) and runtime (%lld) is out of scope",
+ cpu_period_us, cpu_runtime_us);
+ skip_bandwidth = true;
+ }
+
+ if (cpu_sched_type < CPU_SCHED_IDLE || cpu_sched_type > CPU_SCHED_OTHER) {
+ _E("[CPU-THROTTLING] cpu scheduler type is unknown or realtime");
+ cpu_sched_type = CPU_SCHED_IDLE;
+ }
+
+ if (cpu_sched_type != CPU_SCHED_IDLE &&
+ (cpu_nice < CPU_MIN_NICE || cpu_nice > CPU_MAX_NICE)) {
+ _W("[CPU-THROTTLING] cpu nice is out of scope");
+ cpu_nice = CPU_MAX_NICE; /* the worst nice value */
+ }
+
+ /* Make a cpu throttling directory at the cpu cgroup */
+ if (!skip_share || !skip_bandwidth) {
+ ret = cpucg_make_full_subdir(CPUCG_PATH);
+ if (ret < 0) {
+ _E("Failed to initialize cpu cgroup for throttling\n");
+ goto free_cpu_throttling_conf;
+ }
+
+ /* Initialize cpu throttling cgroup */
+ cgroup_write_node_ulonglong(CPUCG_THROTTLING_PATH, CPUCG_SHARE, cpu_share);
+ cgroup_write_node_longlong(CPUCG_THROTTLING_PATH, CPUCG_CONTROL_BANDWIDTH,
+ cpu_runtime_us);
+ cgroup_write_node_ulonglong(CPUCG_THROTTLING_PATH, CPUCG_CONTROL_FULL_BANDWIDTH,
+ cpu_period_us);
+ }
+
+ /* Initialize type and nice of cpu throttling scheduler */
+ memset(&normal_attr, 0, sizeof(struct sched_attr));
+ normal_attr.size = sizeof(struct sched_attr);
+ normal_attr.sched_nice = CPU_DEFAULT_NICE;
+ normal_attr.sched_policy = SCHED_OTHER;
+
+ memset(&throttling_attr, 0, sizeof(struct sched_attr));
+ throttling_attr.size = sizeof(struct sched_attr);
+ throttling_attr.sched_nice = cpu_nice;
+ switch (cpu_sched_type) {
+ case CPU_SCHED_IDLE:
+ throttling_attr.sched_policy = SCHED_IDLE;
+ break;
+ case CPU_SCHED_BATCH:
+ throttling_attr.sched_policy = SCHED_BATCH;
+ break;
+ case CPU_SCHED_OTHER:
+ throttling_attr.sched_policy = SCHED_OTHER;
+ break;
+ default:
+ if (!skip_share || !skip_bandwidth)
+ rmdir(CPUCG_THROTTLING_PATH);
+ goto free_cpu_throttling_conf;
+ }
+
+ throttling_success = true;
+
+ _I("[CPU-THROTTLING] throttling policy = %s",
+ throttling_attr.sched_policy == SCHED_IDLE ? "SCHED_IDLE" :
+ throttling_attr.sched_policy == SCHED_BATCH ? "SCHED_BATCH" :
+ throttling_attr.sched_policy == SCHED_OTHER ? "SCHED_OTHER" : "wrong scheduler type");
+ _I("[CPU-THROTTLING] throttling nice = %d", throttling_attr.sched_nice);
+
+free_cpu_throttling_conf:
+ free_cpu_throttling_conf();
+}
+
+static int resourced_cpu_init(void *data)
+{
+ _D("resourced cpu init start");
+ load_cpu_throttling_config();
+
+ register_notifier(RESOURCED_NOTIFIER_APP_RESUME, cpu_foreground_state);
+ register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, cpu_foreground_state);
+ register_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, cpu_foreground_state);
+ register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, cpu_background_state);
+ register_notifier(RESOURCED_NOTIFIER_THROTTLING_RESOURCE, cpu_background_state);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int resourced_cpu_finalize(void *data)
+{
+ unregister_notifier(RESOURCED_NOTIFIER_APP_RESUME, cpu_foreground_state);
+ unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, cpu_foreground_state);
+ unregister_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, cpu_foreground_state);
+ unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, cpu_background_state);
+ unregister_notifier(RESOURCED_NOTIFIER_THROTTLING_RESOURCE, cpu_background_state);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static struct module_ops cpu_modules_ops = {
+ .priority = MODULE_PRIORITY_NORMAL,
+ .name = "cpu-throttling",
+ .init = resourced_cpu_init,
+ .exit = resourced_cpu_finalize,
+};
+
+MODULE_REGISTER(&cpu_modules_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- */
-
-/**
- * @file cpu.c
- *
- * @desc cpu module
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-#include <dirent.h>
-#include <errno.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/syscall.h>
-#include "notifier.h"
-#include "procfs.h"
-#include "proc-common.h"
-#include "macro.h"
-#include "module.h"
-#include "module-data.h"
-#include "resourced.h"
-#include "trace.h"
-#include "vconf.h"
-#include "util.h"
-#include "cgroup.h"
-#include "config-parser.h"
-#include "const.h"
-#include "file-helper.h"
-#include "cpu-cgroup.h"
-
-#define CPU_CONF_FILE RD_CONFIG_FILE(limiter)
-#define CPU_CONF_SECTION "CPU"
-#define CPU_CONF_PREDEFINE "PREDEFINE"
-#define CPU_CONF_BOOTING "BOOTING_PREDEFINE"
-#define CPU_CONF_WRT "WRT_PREDEFINE"
-#define CPU_CONF_LAZY "LAZY_PREDEFINE"
-#define MAX_PREDEFINED_TASKS 10
-#define CPU_TIMER_INTERVAL 30
-#define CPU_BACKGROUND_PRI 1
-#define CPU_CONTROL_PRI 10
-
-bool throttling_success = false;
-bool skip_bandwidth = false;
-bool skip_share = false;
-struct sched_attr throttling_attr;
-struct sched_attr normal_attr;
-
-static int move_process_to_throttling_group(pid_t pid, struct proc_app_info *pai)
-{
- GSList *iter = NULL;
- pid_t child_pid;
-
- if (!throttling_success)
- return RESOURCED_ERROR_NONE;
-
- if (pai) {
- if (pai->app_cpu_nice_update_exclude)
- goto cpu_cgroup_move;
-
- sched_setattr_of_all_tasks(pai->main_pid, &throttling_attr, 0);
- if (pai->childs) {
- gslist_for_each_item(iter, pai->childs) {
- child_pid = GPOINTER_TO_PID(iter->data);
- sched_setattr_of_all_tasks(child_pid, &throttling_attr, 0);
- }
- }
- }
- else {
- sched_setattr_of_all_tasks(pid, &throttling_attr, 0);
- }
-
-cpu_cgroup_move:
- if (!skip_share || !skip_bandwidth)
- return cpu_move_cgroup_foreach(pid, pai, CPUCG_THROTTLING_PATH);
- else
- return RESOURCED_ERROR_NONE;
-}
-
-static int move_out_process_from_throttling_group(pid_t pid, struct proc_app_info *pai)
-{
- GSList *iter = NULL;
- pid_t child_pid;
-
- if (!throttling_success)
- return RESOURCED_ERROR_NONE;
-
- if (pai) {
- if (pai->app_cpu_nice_update_exclude)
- goto cpu_cgroup_move;
-
- sched_setattr_of_all_tasks(pai->main_pid, &normal_attr, 0);
- if (pai->childs) {
- gslist_for_each_item(iter, pai->childs) {
- child_pid = GPOINTER_TO_PID(iter->data);
- sched_setattr_of_all_tasks(child_pid, &normal_attr, 0);
- }
- }
- }
- else {
- sched_setattr_of_all_tasks(pid, &normal_attr, 0);
- }
-
-cpu_cgroup_move:
- if (!skip_share || !skip_bandwidth)
- return cpu_move_cgroup_foreach(pid, pai, CPUCG_PATH);
- else
- return RESOURCED_ERROR_NONE;
-}
-
-static int cpu_foreground_state(void *data)
-{
- int ret;
- struct proc_status *ps = (struct proc_status *)data;
-
- assert(ps);
- _D("app foreground: pid = %d", ps->pid);
- ret = move_out_process_from_throttling_group(ps->pid, ps->pai);
- if (ret < 0)
- _E("Failed to throttle cpu resource of %s%s process (%d)",
- ps->pai ? "App " : "System service",
- ps->pai ? ps->pai->appid : "", ps->pid);
- return RESOURCED_ERROR_NONE;
-}
-
-static int cpu_background_state(void *data)
-{
- int ret;
- struct proc_status *ps = (struct proc_status *)data;
- assert(ps);
-
- _D("app background: pid = %d", ps->pid);
- ret = move_process_to_throttling_group(ps->pid, ps->pai);
- if (ret < 0)
- _E("Failed to throttle cpu resource of %s%s process (%d)",
- ps->pai ? "App " : "System service",
- ps->pai ? ps->pai->appid : "", ps->pid);
- return RESOURCED_ERROR_NONE;
-}
-
-static void load_cpu_throttling_config(void)
-{
- int ret;
- int cpu_nice;
- long long cpu_runtime_us;
- unsigned long long cpu_period_us;
- unsigned long long cpu_share;
- enum cpu_sched_type cpu_sched_type;
-
- struct cpu_throttling_conf *cpu_throttling_conf = get_cpu_throttling_conf();
- if (cpu_throttling_conf == NULL) {
- _E("[CPU-THROTTLING] cpu sched configuration structure should not be NULL");
- return;
- }
-
- if (!cpu_throttling_conf->enable) {
- _I("[CPU-THROTTLING] cpu throttling is disabled");
- goto free_cpu_throttling_conf;
- }
-
- cpu_nice = cpu_throttling_conf->cpu_sched_info.cpu_nice;
- cpu_sched_type = cpu_throttling_conf->cpu_sched_info.cpu_sched_type;
- cpu_share = cpu_throttling_conf->cpu_cgroup_info.cpu_share;
- cpu_period_us = cpu_throttling_conf->cpu_cgroup_info.cfs_period_us;
- cpu_runtime_us = cpu_throttling_conf->cpu_cgroup_info.cfs_runtime_us;
-
- if (cpu_share == 0) {
- _E("[CPU-THROTTLING] cpu share cannot be 0");
- cpu_share = CPU_THROTTLING_SHARE;
- skip_share = true;
- }
-
- if (cpu_period_us == 0 || cpu_runtime_us == 0 ||
- cpu_period_us < cpu_runtime_us) {
- _E("[CPU-THROTTLING] cpu period (%llu) and runtime (%lld) is out of scope",
- cpu_period_us, cpu_runtime_us);
- skip_bandwidth = true;
- }
-
- if (cpu_sched_type < CPU_SCHED_IDLE || cpu_sched_type > CPU_SCHED_OTHER) {
- _E("[CPU-THROTTLING] cpu scheduler type is unknown or realtime");
- cpu_sched_type = CPU_SCHED_IDLE;
- }
-
- if (cpu_sched_type != CPU_SCHED_IDLE &&
- (cpu_nice < CPU_MIN_NICE || cpu_nice > CPU_MAX_NICE)) {
- _W("[CPU-THROTTLING] cpu nice is out of scope");
- cpu_nice = CPU_MAX_NICE; /* the worst nice value */
- }
-
- /* Make a cpu throttling directory at the cpu cgroup */
- if (!skip_share || !skip_bandwidth) {
- ret = cpucg_make_full_subdir(CPUCG_PATH);
- if (ret < 0) {
- _E("Failed to initialize cpu cgroup for throttling\n");
- goto free_cpu_throttling_conf;
- }
-
- /* Initialize cpu throttling cgroup */
- cgroup_write_node_ulonglong(CPUCG_THROTTLING_PATH, CPUCG_SHARE, cpu_share);
- cgroup_write_node_longlong(CPUCG_THROTTLING_PATH, CPUCG_CONTROL_BANDWIDTH,
- cpu_runtime_us);
- cgroup_write_node_ulonglong(CPUCG_THROTTLING_PATH, CPUCG_CONTROL_FULL_BANDWIDTH,
- cpu_period_us);
- }
-
- /* Initialize type and nice of cpu throttling scheduler */
- memset(&normal_attr, 0, sizeof(struct sched_attr));
- normal_attr.size = sizeof(struct sched_attr);
- normal_attr.sched_nice = CPU_DEFAULT_NICE;
- normal_attr.sched_policy = SCHED_OTHER;
-
- memset(&throttling_attr, 0, sizeof(struct sched_attr));
- throttling_attr.size = sizeof(struct sched_attr);
- throttling_attr.sched_nice = cpu_nice;
- switch (cpu_sched_type) {
- case CPU_SCHED_IDLE:
- throttling_attr.sched_policy = SCHED_IDLE;
- break;
- case CPU_SCHED_BATCH:
- throttling_attr.sched_policy = SCHED_BATCH;
- break;
- case CPU_SCHED_OTHER:
- throttling_attr.sched_policy = SCHED_OTHER;
- break;
- default:
- if (!skip_share || !skip_bandwidth)
- rmdir(CPUCG_THROTTLING_PATH);
- goto free_cpu_throttling_conf;
- }
-
- throttling_success = true;
-
- _I("[CPU-THROTTLING] throttling policy = %s",
- throttling_attr.sched_policy == SCHED_IDLE ? "SCHED_IDLE" :
- throttling_attr.sched_policy == SCHED_BATCH ? "SCHED_BATCH" :
- throttling_attr.sched_policy == SCHED_OTHER ? "SCHED_OTHER" : "wrong scheduler type");
- _I("[CPU-THROTTLING] throttling nice = %d", throttling_attr.sched_nice);
-
-free_cpu_throttling_conf:
- free_cpu_throttling_conf();
-}
-
-static int resourced_cpu_init(void *data)
-{
- _D("resourced cpu init start");
- load_cpu_throttling_config();
-
- register_notifier(RESOURCED_NOTIFIER_APP_RESUME, cpu_foreground_state);
- register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, cpu_foreground_state);
- register_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, cpu_foreground_state);
- register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, cpu_background_state);
- register_notifier(RESOURCED_NOTIFIER_THROTTLING_RESOURCE, cpu_background_state);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int resourced_cpu_finalize(void *data)
-{
- unregister_notifier(RESOURCED_NOTIFIER_APP_RESUME, cpu_foreground_state);
- unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, cpu_foreground_state);
- unregister_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, cpu_foreground_state);
- unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, cpu_background_state);
- unregister_notifier(RESOURCED_NOTIFIER_THROTTLING_RESOURCE, cpu_background_state);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static struct module_ops cpu_modules_ops = {
- .priority = MODULE_PRIORITY_NORMAL,
- .name = "cpu-throttling",
- .init = resourced_cpu_init,
- .exit = resourced_cpu_finalize,
-};
-
-MODULE_REGISTER(&cpu_modules_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- */
-
-/*
- * @file heart-abnormal.c
- *
- * @desc heart abnormal module
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <sys/time.h>
-
-#include "proc-common.h"
-#include "notifier.h"
-#include "resourced.h"
-#include "dbus-handler.h"
-#include "heart.h"
-#include "logging.h"
-#include "heart-common.h"
-#include "trace.h"
-#include "module.h"
-#include "macro.h"
-
-#define ABNORMAL_NAME "abnormal"
-#define ABNORMAL_DATA_MAX 1024
-#define ABNORMAL_CHECK_NUM 10
-
-#define TIMESTAMP_LEN 16
-#define MILLISEC 1000
-#define TIME_MAX_LEN 64
-#define SLUG_TYPE_MALFUN 6
-#define NOPID 0
-
-enum abnormal_type {
- FC = 0,
- ANR = 1,
- ABNORMAL_TYPE_MAX,
-};
-
-struct heart_abnormal_table {
- char appid[MAX_APPID_LENGTH];
- char pkgid[MAX_PKGNAME_LENGTH];
- time_t time;
- int count[ABNORMAL_TYPE_MAX];
-};
-
-static GHashTable *heart_abnormal_list;
-static pthread_mutex_t heart_abnormal_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void heart_abnormal_fill_array(struct logging_table_form *entry, void *data)
-{
- int ret, i;
- unsigned int type;
- struct heart_abnormal_table *table = NULL;
- GHashTable *list = (GHashTable *)data;
-
- if (sscanf((char *)entry->data, "%*s %*s %u ", &type) < 0) {
- _E("sscanf failed, %m");
- return;
- }
-
- if (type >= ABNORMAL_TYPE_MAX) {
- _E("wrong abnormal type, %u", type);
- return;
- }
- ret = pthread_mutex_lock(&heart_abnormal_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return;
- }
- table = g_hash_table_lookup(list, entry->appid);
- if (!table) {
- table = malloc(sizeof(struct heart_abnormal_table));
- if (!table) {
- _E("malloc failed");
- goto unlock_exit;
- }
-
- if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", entry->appid) < 0) {
- _E("snprintf failed");
- free(table);
- goto unlock_exit;
- }
-
- if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", entry->pkgid) < 0) {
- _E("snprintf failed");
- free(table);
- goto unlock_exit;
- }
- table->time = entry->time;
-
- for (i = 0; i < ABNORMAL_TYPE_MAX; i++)
- table->count[i] = 0;
-
- table->count[type] = 0;
- g_hash_table_insert(list, (gpointer)table->appid, (gpointer)table);
- }
- table->count[type]++;
-
-unlock_exit:
- ret = pthread_mutex_unlock(&heart_abnormal_mutex);
- if (ret)
- _E("pthread_mutex_unlock() failed, %d", ret);
-}
-
-static void heart_abnormal_launch_popup(char *appid, int count)
-{
- _W("A malfunction popup is supposed to be created here, but system-popup "
- "doesn't actually expose a MalfunctionNotifierLaunch DBus method and "
- "this legacy functionality is deprecated.");
-
-#if 0
- /* Dead code (see above); it has been disabled instead of outright removed
- * because I've seen too many braindead repository copy-pastes annihilating
- * git history to trust people to be able to find this code in case their
- * legacy system suddenly stops working and I don't want to deal with the
- * flak I could be getting for it. In a year or two (unless somebody patches
- * system-popup to add MalfurionNotifierLaunch or some other good reason
- * appears) it would be good to get rid of this code though. */
-
- int ret;
- char num[10];
- char _appid[MAX_APPID_LENGTH];
- GVariant *param;
-
- /* Launch malfunction system popup */
- snprintf(num, 10, "%d", count);
- snprintf(_appid, MAX_APPID_LENGTH, "%s", appid);
- _D("appid %s, count %d", appid, count);
-
- param = g_variant_new("(ssssss)", "_SYSPOPUP_CONTENT_",
- "malfunction_notifier",
- "_ERRORS_",
- num,
- "_APPID_",
- _appid)
-
- ret = d_bus_call_method_async_gvariant("org.tizen.system.popup",
- "/Org/Tizen/System/Popup/System",
- "org.tizen.system.popup.System",
- "MalfunctionNotifierLaunch", param);
- if (ret < 0)
- _E("Failed to launch MalfunctionNotifier");
- else
- _I("MalfunctionNotifierLaunch Success");
-#endif
-}
-
-static int heart_abnormal_report_malfunction(char *name)
-{
- int ret = -1;
- char timestr[TIMESTAMP_LEN] = {0,};
- int milli;
- char msgid[TIME_MAX_LEN + sizeof '+' + MAX_DEC_SIZE(milli)] = {0,};
- char ts[TIME_MAX_LEN] = {0,};
- struct timeval time_of_day;
- time_t unix_time = time(NULL);
- struct tm loc_tm;
-
- if (gettimeofday(&time_of_day, NULL)) {
- _E("gettimeofday failed");
- return ret;
- }
- if (!localtime_r(&time_of_day.tv_sec, &loc_tm)) {
- _E("localtime_r failed");
- return ret;
- }
-
- snprintf(timestr, sizeof(timestr), "%.10ld", unix_time);
- milli = time_of_day.tv_usec / MILLISEC;
- strftime(ts, TIME_MAX_LEN, "%Y.%m.%d-%H:%M:%S", &loc_tm);
- snprintf(msgid, sizeof(msgid), "%s+%d", ts, milli);
-
- ret = d_bus_call_method_async_gvariant("org.tizen.system.crash", "/Org/Tizen/System/Crash/Crash", "org.tizen.system.crash.Crash",
- "sluggish_dump",
- g_variant_new("(iisss)", SLUG_TYPE_MALFUN, NOPID, name, timestr, msgid));
-
- if (ret < 0)
- _E("Malfunction reporting to sluggish tool failed");
- return ret;
-}
-
-static void heart_abnormal_process_crashed(GVariant *params)
-{
- int ret, notify, count;
- gpointer key, value;
- time_t curtime, starttime;
- GHashTableIter hiter;
- char *process_name = NULL, *exepath = NULL, *appid = NULL, *pkgid = NULL;
- char info[ABNORMAL_DATA_MAX];
- struct heart_abnormal_table *table = NULL;
-
- do_expr_unless_g_variant_get_typechecked(return, params, "(&s&s&s&ssiia{sv})", &process_name, &exepath, &appid, &pkgid,
- NULL, NULL, NULL, NULL);
- if (!process_name || !exepath || !appid || !pkgid) {
- _E("Failed: dbus_message_get_args()");
- return;
- }
- curtime = time(NULL);
- starttime = curtime - 604800;
- if (starttime < 0)
- starttime = 0;
-
- if (g_hash_table_size(heart_abnormal_list))
- g_hash_table_remove_all(heart_abnormal_list);
-
- logging_read_foreach(ABNORMAL_NAME, appid, NULL, starttime, curtime,
- heart_abnormal_fill_array, heart_abnormal_list);
-
- g_hash_table_iter_init(&hiter, heart_abnormal_list);
-
- count = 0;
- while (g_hash_table_iter_next(&hiter, &key, &value)) {
- table = (struct heart_abnormal_table *)value;
- if (!table)
- break;
- count += table->count[FC];
- }
-
- notify = 0;
- if (count > ABNORMAL_CHECK_NUM) {
- heart_abnormal_launch_popup(appid, count);
- notify = 1;
- heart_abnormal_report_malfunction(appid);
- }
-
- g_hash_table_remove_all(heart_abnormal_list);
-
- snprintf(info, sizeof(info), "%s %s %d %d ", process_name, exepath, notify, FC);
- _D("info : %s %d", info, count);
- ret = logging_write(PID_FOR_ROOT, ABNORMAL_NAME, appid, pkgid, time(NULL), info);
- if (ret != RESOURCED_ERROR_NONE)
- _E("Failed to logging_write %s", info);
-}
-
-static int heart_abnormal_anr(void *data)
-{
- int ret;
- char info[ABNORMAL_DATA_MAX];
- struct proc_status *ps = (struct proc_status *)data;
- char *appid, *pkgid;
-
- ret = proc_get_id_info(ps, &appid, &pkgid);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to proc_get_id_info");
- return ret;
- }
- snprintf(info, sizeof(info), "%d ANR %d ", ps->pid, ANR);
- _D("info : %s", info);
- ret = logging_write(PID_FOR_ROOT, ABNORMAL_NAME, appid, pkgid, time(NULL), info);
- if (ret != RESOURCED_ERROR_NONE)
- _E("Failed to logging_write %s", info);
- return ret;
-}
-
-static void heart_abnormal_free_value(gpointer value)
-{
- struct heart_abnormal_table *table =
- (struct heart_abnormal_table *)value;
-
- if (!table)
- return;
-
- free(table);
-}
-
-static void dbus_heart_get_abnormal_data(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int type = -1, period = -1;
- int ret, count, i;
- time_t starttime;
- char *appid;
- gpointer key, value;
- GHashTableIter hiter;
- struct heart_abnormal_table *table = NULL;
- GVariantBuilder builder, *sub_builder;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(ii)", &type, &period);
- if (type < 0 || ABNORMAL_TYPE_MAX < type || period < 0) {
- _E("Wrong message arguments! %d", type);
- goto failure;
- }
- starttime = time(NULL);
- switch (period) {
- case DATA_LATEST:
- starttime = 0;
- break;
- case DATA_3HOUR:
- starttime -= 10800;
- break;
- case DATA_6HOUR:
- starttime -= 21600;
- break;
- case DATA_12HOUR:
- starttime -= 43200;
- break;
- case DATA_1DAY:
- starttime -= 86400;
- break;
- case DATA_1WEEK:
- starttime -= 604800;
- break;
- default:
- _E("Wrong message arguments! %d", period);
- goto failure;
- }
-
- if (starttime < 0)
- starttime = 0;
-
- if (g_hash_table_size(heart_abnormal_list))
- g_hash_table_remove_all(heart_abnormal_list);
-
- logging_read_foreach(ABNORMAL_NAME, NULL, NULL, starttime, time(NULL),
- heart_abnormal_fill_array, heart_abnormal_list);
-
- ret = pthread_mutex_lock(&heart_abnormal_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- goto failure;
- }
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
- sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(si)"));
-
- g_hash_table_iter_init(&hiter, heart_abnormal_list);
- while (g_hash_table_iter_next(&hiter, &key, &value)) {
- table = (struct heart_abnormal_table *)value;
- if (!table)
- break;
- count = 0;
- appid = table->appid;
-
- if (type == ABNORMAL_TYPE_MAX) {
- for (i = 0; i < ABNORMAL_TYPE_MAX; i++)
- count += table->count[i];
- } else
- count += table->count[type];
-
- if (!count)
- continue;
-
- g_variant_builder_add(sub_builder, "(si)", appid, count);
- }
- g_variant_builder_add_value(&builder, g_variant_new("a(si)", sub_builder));
- g_variant_builder_unref(sub_builder);
-
- ret = pthread_mutex_unlock(&heart_abnormal_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- goto failure;
- }
- g_hash_table_remove_all(heart_abnormal_list);
-
- g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static const char dbus_methods_xml[] =
-" <method name='GetAbnormalData'>"
-" <arg type='i' name='Type' direction='in'/>"
-" <arg type='i' name='Period' direction='in'/>"
-" <arg type='a(si)' name='CountPerApp' direction='out'/>"
-" </method>";
-
-static struct d_bus_method dbus_methods[] = {
- { "GetAbnormalData", dbus_heart_get_abnormal_data },
-};
-
-static int heart_abnormal_init(void *data)
-{
- int ret;
-
- ret = logging_module_init(ABNORMAL_NAME, ONE_WEEK, HALF_HOUR, NULL, 0, SYSTEM_DEFAULT);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("logging module init failed");
- return RESOURCED_ERROR_FAIL;
- }
-
- heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
-
- ret = d_bus_register_signal(CRASH_PATH_CRASH,
- CRASH_INTERFACE_CRASH, PROCESS_CRASHED,
- heart_abnormal_process_crashed, NULL);
- if (ret < 0)
- _E("Failed to add a capacity status signal handler");
- heart_abnormal_list = g_hash_table_new_full(
- g_str_hash,
- g_str_equal,
- NULL,
- heart_abnormal_free_value);
-
- register_notifier(RESOURCED_NOTIFIER_APP_ANR, heart_abnormal_anr);
- _D("heart abnormal init finished");
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_abnormal_exit(void *data)
-{
- if (heart_abnormal_list)
- g_hash_table_destroy(heart_abnormal_list);
- logging_module_exit();
- unregister_notifier(RESOURCED_NOTIFIER_APP_ANR, heart_abnormal_anr);
- _D("heart abnormal exit");
- return RESOURCED_ERROR_NONE;
-}
-
-static const struct heart_module_ops heart_abnormal_ops = {
- .name = "ABNORMAL",
- .init = heart_abnormal_init,
- .exit = heart_abnormal_exit,
-};
-HEART_MODULE_REGISTER(&heart_abnormal_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- */
-
-/*
- * @file heart-battery.c
- *
- * @desc heart battery module
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <sqlite3.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <math.h>
-#include <device/display.h>
-#include <device/callback.h>
-#include <system_info.h>
-
-#include "proc-common.h"
-#include "notifier.h"
-#include "resourced.h"
-#include "dbus-handler.h"
-#include "heart.h"
-#include "logging.h"
-#include "heart-common.h"
-#include "config-parser.h"
-#include "trace.h"
-#include "vconf.h"
-#include "module.h"
-#include "macro.h"
-#include "util.h"
-#include "file-helper.h"
-
-#define TIZEN_SYSTEM_APPID "org.tizen.system"
-#define TIZEN_SYSTEM_BATTERY_APPID "org.tizen.system.battery.capacity"
-#define BATTERY_NAME "battery"
-#define BATTERY_DATA_MAX 1024
-#define BATTERY_CAPACITY_MAX 512
-#define BATTERY_LINE_MAX 128
-#define BATTERY_CLEAN_MAX 100
-#define BATTERY_HISTORY_DAY_MAX 7
-#define BATTERY_HISTORY_RESET_MAX 5
-#define BATTERY_HISTORY_RESET_CURRENT (BATTERY_HISTORY_RESET_MAX - 1)
-#define BATTERY_HISTORY_COUNT_MAX 1000
-#define HEART_BATTERY_UPDATE_INTERVAL HALF_HOUR
-#define HEART_BATTERY_SAVE_INTERVAL HALF_HOUR
-#define HEART_BATTERY_CAPACITY_DATA_FILE HEART_FILE_PATH"/.battery_capacity.dat"
-#define HEART_BATTERY_CONF_SECTION "BATTERY_POWER_MODE"
-#define GET_CHARGER_STATUS "ChargerStatus"
-#define GET_BATTERY_CAPACITY "GetPercent"
-#define CALCULATE_DAY_BASE_TIME(x) ((x / DAY_TO_SEC(1)) * (DAY_TO_SEC(1)))
-#define REMAIN_CAPACITY(x) (100 - x)
-#define BATTERY_PREDICTION_DATA_MIN 5
-#define BATTERY_USAGE_LEARNING -1
-#define CUMUL_WEIGHT (0.8)
-#define TREND_WEIGHT (1 - CUMUL_WEIGHT)
-#define DISCHARGE_BASE_RATE (0.2)
-
-/*
- * BATTERY_PREDICTION_LATEST_COUNT must be >= BATTERY_PREDICTION_DATA_MIN
- */
-#define BATTERY_PREDICTION_LATEST_COUNT 5
-/*
- * BATTERY_PREDICTION_PERIOD possible values:
- * DATA_LATEST, DATA_3HOUR, DATA_6HOUR, DATA_12HOUR, DATA_1DAY
- */
-#define BATTERY_PREDICTION_PERIOD DATA_3HOUR
-
-#define BATTERY_USED_TIME "BATTERY_USED_TIME"
-#define BATTERY_STATUS "BATTERY_STATUS"
-#define BATTERY_RESET_USAGE "BATTERY_RESET_USAGE"
-#define BATTERY_WEEK_DAY_USAGE "BATTERY_WEEK_DAY_USAGE"
-#define BATTERY_LEVEL_USAGE "BATTERY_LEVEL_USAGE"
-#define BATTERY_PREDICTION "BATTERY_PREDICTION"
-
-#define INDEX_WINDOW_SIZE 10 /*data storing index*/
-#define BATTERY_LEVEL_GAP 5 /*previous 5 battery data*/
-#define LONG_TIME_WEIGHT (0.7) /*weightage given for longer time discharge*/
-#define SHORT_TIME_WEIGHT (1-LONG_TIME_WEIGHT) /*weightage given for short time discharge*/
-#define NEW_PIVOT_WEIGHTAGE(x) (x * 0.10) /* x/10th part */
-#define OLD_PIVOT_WEIGHTAGE(x) (1.0 - NEW_PIVOT_WEIGHTAGE(x))
-#define MIN_DISCHARGE_PERIOD 40
-#define LOW_CAPACITY 2
-#define MIN_TIME_FOR_LVL_CHANGE 50
-#define BATT_CHG_FLUSH_DATA 10
-
-/*
- * Below 6 values are the co-efficient of the polynomial. These are devired from
- * OCV and and battery percentage level based on experiment
- */
-#define OCV_SOC_POLY_COEF_1 (3402.664)
-#define OCV_SOC_POLY_COEF_2 (42.031)
-#define OCV_SOC_POLY_COEF_3 (-1.76745)
-#define OCV_SOC_POLY_COEF_4 (0.034798)
-#define OCV_SOC_POLY_COEF_5 (-0.00030516)
-#define OCV_SOC_POLY_COEF_6 (0.0000010116)
-#define UPS_FACTOR (2.88)
-#define DOUBLE_ZERO (0.000000)
-#define FULL_CAPACITY 100
-/* BATTERY_C_RATE is defined as the rate of which battery capacity is changing
- * If total battery capacity is XmAh, then in one second battery capacity change
- * will be considered as 90
- */
-#define BATTERY_C_RATE 90
-#define SEC_TO_MIN(x) ((x + 30)/60) /* 30 secs buffer to round off */
-#define CAL_MIN(x, y) ((x < y) ? x : y)
-#define BATTERY_WINDOW_INDEX(x) (((x) + INDEX_WINDOW_SIZE) % INDEX_WINDOW_SIZE)
-#define HEART_BATTERY_DATA_FILE HEART_FILE_PATH"/.battery_data.dat"
-#define HEART_BATTERY_PIVOT_INFO HEART_FILE_PATH"/.battery_pivot_data.dat"
-#define VCONFKEY_HEART_BATTERY_DEVICE_MODE "db/setting/psmode"
-#define VCONFKEY_SETAPPL_MANAGE_BATTERY_TRIGGER_TIME "db/setting/manage_battery_trigger_time"
-
-/*
- * Remaining Useful Life prediction logic
- */
-#define RUL_DATA_FILE HEART_FILE_PATH"/.rul_data.dat"
-#define RUL_CHARGING_CYCLES_FILE HEART_FILE_PATH"/.charging_cycles.dat"
-#define RUL_MIN_CAPACITY_DIFF 50
-#define RUL_DISPLAY_ON_CUTOFF_RATIO 0.1f
-#define RUL_DATA_SIZE 32
-
-enum {
- TA = 0, /* prediction based on total data average */
- PCB = 1, /* prediction with physiological behaviors */
- WEEK = 2, /* prediction based on weekly data */
- COUNT = 3, /* prediction based on last BATTERY_PREDICTION_COUNT number of items */
- PERIOD = 4, /* prediction based on data from last BATTERY_PREDICTION_PERIOD time */
- MAX_STRATEGY = 5,
-};
-
-enum {
- POWER_NORMAL_MODE = 0,
- POWER_SAVING_MODE = 1,
- ULTRA_SAVING_MODE = 2,
- POWER_MODE_MAX = 3,
-};
-
-enum {
- BATTERY_LEVEL_LOW = 0, /* 15 ~ 0 */
- BATTERY_LEVEL_MID = 1, /* 49 ~ 16 */
- BATTERY_LEVEL_HIGH = 2, /* 50 ~ 100 */
- BATTERY_LEVEL_MAX = 3,
-};
-
-enum {
- DEFAULT_MIN = 0,
- DEFAULT_AVG = 1,
- DEFAULT_MAX = 2,
- DEFAULT_VALUE_MAX = 3,
-};
-
-/* Structure to calculate percentage time LCD on during charging */
-struct rul_lcd_data {
- display_state_e state;
- long on_time;
- long on_start_time;
- long on_stop_time;
-};
-
-/* Structure to store RUL related charging info */
-struct rul_info {
- long charging_start_time;
- long charging_stop_time;
- float raw_capacity; /* capacity (mAh) accumulation during charging */
- int soc_start; /* SoC(%) value when charging starts */
- int soc_stop; /* SoC(%) value when charging stops */
- int charging_cycles; /* Number of charging cycles */
- int curr_soc; /* Current SoC %, compare with prev_soc to determine if charging */
- int prev_soc; /* Previous value of SoC % */
- struct rul_lcd_data lcd_data; /* LCD related data */
-};
-
-struct battery_used {
- time_t used_time_sec; /* seconds on battery */
- time_t last_update_time;
- int last_charger_status;
-};
-
-struct battery_usage {
- time_t start_time; /* timestamp when event started */
- long sec_per_cap[MAX_CHARGER_STATE]; /* seconds per capacity level change */
- long cap_counter[MAX_CHARGER_STATE]; /* number of capacity level changes */
-};
-
-struct battery_prediction {
- long sec_per_cap[MAX_STRATEGY]; /* seconds per capacity level change */
- long cap_counter[MAX_STRATEGY]; /* number of capacity level changes */
- long time_pred_min[MAX_STRATEGY]; /* time prediction in minutes */
-};
-
-struct battery_pivot_info {
- long start_time_dischg; /* store the time from when discharge started */
- int pvt_data_ind; /* index to keep track of total_dischg_time value */
- int start_cap_dischg; /* capacity from when discharge started */
- int total_dischg_time[INDEX_WINDOW_SIZE]; /* total discharge period */
- time_t last_clock_tick; /* last tick stored */
-};
-
-struct battery_status {
- /* current battery status */
- enum charger_status_type curr_charger_status;
- int curr_capacity;
-
- enum discharge_rate_level_type discharge_rate_level;
- /* current runtime statistics */
- long curr_run_time_sec[MAX_CHARGER_STATE]; /* seconds since reset */
- long curr_cap_counter[MAX_CHARGER_STATE]; /* capacity level changes */
-
- long last_wall_time[INDEX_WINDOW_SIZE]; /* previous battery level discharge time */
- /* previous battery level change time in charging mode */
- long last_wall_time_chg;
- /* charging data index*/
- int index_chg;
- /* store last 5 battery level change time diff */
- int last_wall_time_chg_diff[BATTERY_LEVEL_GAP];
- /* indicates whether do we have enough data to estimate the battery time */
- int data_available;
- int curr_index; /* store current index value */
- int last_capacity; /* last battery capacity value */
- int last_capacity_chg; /* last battery capacity value in charge mode */
- int remaining_time; /* previous remaining time */
- int remaining_time_chg; /* previous remaining time in charging mode */
- int remaining_time_ups; /* previous remaining time in UPS */
- double last_volt_intg[INDEX_WINDOW_SIZE]; /* store previous calculated voltage integral(energy) value */
- double last_pwr_bchg; /* store the battery power available just before charging start */
-
- /* wall clock time stamp when last event happened in seconds */
- time_t last_event_wall_time;
- time_t last_clock_tick;
-
- /*
- * reset mark is set when battery is charged in over 90% and
- * charger was disconnected from the device.
- * We consider then the device as "charged"
- *
- * The possible values are 0 and 1 they're swapped to opposite on change.
- */
- int reset_mark;
- time_t reset_mark_timestamp;
-
- /* usage time from last reset_mark change*/
- struct battery_usage batt_reset_usage[BATTERY_HISTORY_RESET_MAX];
-
- /* usage time by week day */
- struct battery_usage week_day_usage[BATTERY_HISTORY_DAY_MAX];
-
- /* usage time by user behavior & battery level */
- struct battery_usage batt_lvl_usage[BATTERY_LEVEL_MAX];
-
- /* calculated battery prediction */
- struct battery_prediction prediction[MAX_CHARGER_STATE];
-
- /* battery pivot information */
- struct battery_pivot_info pvt;
-};
-
-static int default_sec_per_cap[MAX_CHARGER_STATE][DEFAULT_VALUE_MAX] = {
- { 70, 670, 3600 }, /* DISCHARGING MIN: 70s, AVG: 670s, MAX: 1 hour */
- { 30, 80, 3600 } /* CHARGING MIN: 30s, AVG: 80s, MAX: 1 hour */
-};
-
-static double default_mode_spc[POWER_MODE_MAX] = {
- 670, /* POWER_NORMAL_MODE */
- 750, /* POWER_SAVING_MODE */
- 1947 /* ULTRA_SAVING_MODE */
-};
-
-static double default_mode_factor[POWER_MODE_MAX] = {
- 1, /* POWER_NORMAL_MODE */
- 1.1, /* POWER_SAVING_MODE */
- 2.88 /* ULTRA_SAVING_MODE */
-};
-
-struct heart_power_profile {
- float wifi_on;
- float wifi_active;
- float wifi_scan;
-};
-
-static struct heart_power_profile power_profile;
-#ifdef NETWORK_SUPPORT
-static struct heart_calc_time calc_time;
-#endif
-static struct battery_used batt_used;
-static struct battery_status batt_stat;
-static GSList *capacity_history_list = NULL;
-static pthread_mutex_t heart_battery_mutex = PTHREAD_MUTEX_INITIALIZER;
-static time_t last_file_commit_time;
-static int battery_learning_mode;
-
-static int ocv_degree; /* Degree of the OCV and SOC polynomial */
-static double *intg; /* Co-efficients of the OCV and SOC polynomial */
-static double pivot_nor; /* time pivot for normal mode */
-static double pivot_ups; /* time pivot for UPS mode */
-static double volt_intg_full; /* 100% battery voltage integral(engery) value */
-static bool data_avail_chg = false; /* 5 readings in charging mode */
- /*
- * variable to hold the current device mode(NORMAL, PS & UPS)
- */
-static int device_mode = POWER_NORMAL_MODE;
-
-static int heart_battery_direct_get_capacity(void);
-
-/*
- * Given the 'SOC', remaining energy of the cell can be predicted. New battery
- * remaining time estimation logic will calculating the remaining energy as
- * 'curr_volt_intg'.
- *
- * Based on estimated average power(P), a time estimate can be calcluated.
- * Power can be estimated based on constant SOC interval Ps and constant
- * time interval Pt.
- *
- * At high usage Ps will be short term average power and Pt will be long term
- * average power.
- *
- * At low usage Ps will be long term average power and Pt will be short term
- * average power.
- *
- * The new logic will calculate the average power 'batt_pwr' from Ps and Pt.
- *
- * Under-relaxation is a popular and effective technique of stabilizing prediction.
- * The predicted time is stabilized around a pivot, which is calculated from the
- * high-usage time and low-usage time
- *
- * The new logic will calculated 'pivot_nor' and 'pivot_ups' for normal and UPS
- * mode respectively
- *
- * Finally, using current available energy(curr_volt_intg), average power(batt_pwr)
- * and pivot time (pivot_nor or pivot_ups) this new logic will estimate the Battery
- * Remaining Time for normal mode and UPS mode
- */
-/*
- * new battery remaining time estimation logic
- */
-static int logic_v2;
-/*
- * Total time taken in minutes when device is discharging at fastest rate
- */
-static int discharge_fast;
-/*
- * Total time taken in minutes when device is discharging at slowest rate
- */
-static int discharge_slow;
-/*
- * Avarage power consumed in UPS mode
- */
-static double average_pwr;
-/*
- * Total battery capacity in minutes(mAM)
- */
-static int total_battery_capacity;
-/*
- * This variable indicates first battery level update after charger insert
- */
-static bool first_level_change = FALSE;
-/*
- * This variable indicates the battery header used in heart.conf file
- */
-static char battery_header[BATTERY_LINE_MAX] = "BATTERY";
-
-/*
- * Remaining Useful Life (RUL) prediction logic
- */
-static int logic_rul;
-struct rul_info rul;
-
-static int get_battery_remaining_time(int mode, enum charger_status_type status);
-
-int heart_battery_get_capacity(void)
-{
- return batt_stat.curr_capacity;
-}
-
-enum charger_status_type heart_battery_get_charger_status(void)
-{
- return batt_stat.curr_charger_status;
-}
-
-static inline void heart_battery_set_usage_reset_stime(int history, time_t start_time)
-{
- batt_stat.batt_reset_usage[history].start_time = start_time;
-}
-
-static inline void heart_battery_set_usage_reset(int history, enum charger_status_type status, long sec_per_cap, long cap_counter)
-{
- batt_stat.batt_reset_usage[history].sec_per_cap[status] = sec_per_cap;
- batt_stat.batt_reset_usage[history].cap_counter[status] = cap_counter;
-}
-
-static inline long heart_battery_get_usage_reset_total_time(int history, enum charger_status_type status)
-{
- return batt_stat.batt_reset_usage[history].sec_per_cap[status] * batt_stat.batt_reset_usage[history].cap_counter[status];
-}
-
-static inline long heart_battery_get_usage_reset_count(int history, enum charger_status_type status)
-{
- return batt_stat.batt_reset_usage[history].cap_counter[status];
-}
-
-static inline void heart_battery_set_usage_level_stime(int level, time_t start_time)
-{
- batt_stat.batt_lvl_usage[level].start_time = start_time;
-}
-
-static inline void heart_battery_set_usage_level(int level, enum charger_status_type status, long sec_per_cap, long cap_counter)
-{
- batt_stat.batt_lvl_usage[level].sec_per_cap[status] = sec_per_cap;
- batt_stat.batt_lvl_usage[level].cap_counter[status] = cap_counter;
-}
-
-static inline long heart_battery_get_usage_level_total_time(int level, enum charger_status_type status)
-{
- return batt_stat.batt_lvl_usage[level].sec_per_cap[status] * batt_stat.batt_lvl_usage[level].cap_counter[status];
-}
-
-static inline long heart_battery_get_usage_level_spc(int level, enum charger_status_type status)
-{
- return batt_stat.batt_lvl_usage[level].sec_per_cap[status];
-}
-
-static inline long heart_battery_get_usage_level_count(int level, enum charger_status_type status)
-{
- return batt_stat.batt_lvl_usage[level].cap_counter[status];
-}
-
-static inline long heart_battery_get_usage_week_total_time(int day, enum charger_status_type status)
-{
- return batt_stat.week_day_usage[day].sec_per_cap[status] * batt_stat.week_day_usage[day].cap_counter[status];
-}
-
-static inline long heart_battery_get_usage_week_count(int day, enum charger_status_type status)
-{
- return batt_stat.week_day_usage[day].cap_counter[status];
-}
-
-static inline void heart_battery_set_usage_week_stime(int day, time_t start_time)
-{
- batt_stat.week_day_usage[day].start_time = start_time;
-}
-
-static inline time_t heart_battery_get_usage_week_stime(int day)
-{
- return batt_stat.week_day_usage[day].start_time;
-}
-
-static inline int heart_battery_get_learning_mode(void)
-{
- int i, count = 0;
-
- if (logic_v2) { /* new logic */
- /*wait till enough data gets collected to estimated battery remaining time */
- if (batt_stat.data_available == TRUE)
- return 1;
- return 0;
- }
- /* old logic */
- for (i = 0; i < BATTERY_HISTORY_DAY_MAX; i++) {
- if (heart_battery_get_usage_week_stime(i))
- count++;
- if (count > 1)
- return 1;
- }
- return 0;
-}
-
-static inline void heart_battery_set_usage_week(int day, enum charger_status_type status, long sec_per_cap, long cap_counter)
-{
- batt_stat.week_day_usage[day].sec_per_cap[status] = sec_per_cap;
- batt_stat.week_day_usage[day].cap_counter[status] = cap_counter;
-}
-
-static inline void heart_battery_set_prediction(int strategy, enum charger_status_type status, long sec_per_cap, long cap_counter, long pred_min)
-{
- batt_stat.prediction[status].sec_per_cap[strategy] = sec_per_cap;
- batt_stat.prediction[status].cap_counter[strategy] = cap_counter;
- batt_stat.prediction[status].time_pred_min[strategy] = pred_min;
-}
-
-static inline long heart_battery_get_prediction_time(int strategy, enum charger_status_type status)
-{
- return batt_stat.prediction[status].time_pred_min[strategy];
-}
-
-static inline time_t heart_battery_get_file_commit_timestamp()
-{
- return last_file_commit_time;
-}
-
-static inline void heart_battery_set_file_commit_timestamp(time_t timestamp)
-{
- last_file_commit_time = timestamp;
-}
-
-static int heart_battery_calculate_discharge_rate_level(long spc)
-{
- long gap, total_spc;
-
- total_spc = batt_stat.prediction[DISCHARGING].sec_per_cap[TA];
- if (!total_spc)
- return BATTERY_DISCHARGE_NONE;
- gap = (total_spc * DISCHARGE_BASE_RATE);
-
- _I("total: %ld, spc: %ld, gap: %ld", total_spc, spc, gap);
-
- if (total_spc + gap < spc)
- return BATTERY_DISCHARGE_LOW;
- else if (total_spc - gap > spc)
- return BATTERY_DISCHARGE_HIGH;
-
- return BATTERY_DISCHARGE_AVG;
-}
-
-static void heart_battery_save_used_time(char *key, struct battery_used *used)
-{
- assert(key);
- assert(used);
-
- logging_leveldb_putv(key, strlen(key), "%d %d ",
- used->used_time_sec, used->last_update_time);
-};
-
-static void heart_battery_save_status(char *key, struct battery_status *status)
-{
- assert(key);
- assert(status);
-
- logging_leveldb_putv(key, strlen(key), "%d %ld %ld %ld %ld %d %d ",
- status->curr_capacity,
- status->curr_run_time_sec[DISCHARGING],
- status->curr_cap_counter[DISCHARGING],
- status->curr_run_time_sec[CHARGING],
- status->curr_cap_counter[CHARGING],
- status->curr_charger_status,
- status->reset_mark);
-};
-
-static void heart_battery_save_usage(char *key, struct battery_usage *usage, int total_size)
-{
- int i, len, num;
- char buf[BATTERY_DATA_MAX] = {0, };
-
- assert(key);
- assert(usage);
-
- len = 0;
- num = total_size/sizeof(struct battery_usage);
- for (i = 0; i < num; i++) {
- len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%ld %ld %ld %ld %ld ",
- usage[i].start_time,
- usage[i].sec_per_cap[DISCHARGING],
- usage[i].cap_counter[DISCHARGING],
- usage[i].sec_per_cap[CHARGING],
- usage[i].cap_counter[CHARGING]);
- }
- logging_leveldb_put(key, strlen(key), buf, len);
-};
-
-static void heart_battery_save_prediction(char *key, struct battery_prediction *prediction)
-{
- int i, len;
- char buf[BATTERY_DATA_MAX] = {0, };
-
- assert(key);
- assert(prediction);
-
- len = 0;
- for (i = 0; i < MAX_STRATEGY; i++) {
- len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%ld %ld %ld %ld %ld %ld ",
- prediction[DISCHARGING].sec_per_cap[i],
- prediction[DISCHARGING].cap_counter[i],
- prediction[DISCHARGING].time_pred_min[i],
- prediction[CHARGING].sec_per_cap[i],
- prediction[CHARGING].cap_counter[i],
- prediction[CHARGING].time_pred_min[i]);
- }
- logging_leveldb_put(key, strlen(key), buf, len);
-};
-
-
-static int heart_battery_load_used_time(char *key, struct battery_used *used)
-{
- int ret;
- char *token;
- char buf[BATTERY_DATA_MAX] = {0, };
- char *saveptr;
-
- if (!key || !used)
- return RESOURCED_ERROR_FAIL;
-
- ret = logging_leveldb_read(key, strlen(key), buf, sizeof(buf));
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to read leveldb key: %s", key);
- return RESOURCED_ERROR_FAIL;
- }
- token = strtok_r(buf, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- used->used_time_sec = atoi(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- used->last_update_time = atoi(token);
- return RESOURCED_ERROR_NONE;
-};
-
-static int heart_battery_load_status(char *key, struct battery_status *status)
-{
- int ret;
- char *token;
- char buf[BATTERY_DATA_MAX] = {0, };
- char *saveptr;
-
- if (!key || !status)
- return RESOURCED_ERROR_FAIL;
-
- ret = logging_leveldb_read(key, strlen(key), buf, sizeof(buf));
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to read leveldb key: %s", key);
- return RESOURCED_ERROR_FAIL;
- }
- token = strtok_r(buf, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- status->curr_capacity = atoi(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- status->curr_run_time_sec[DISCHARGING] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- status->curr_cap_counter[DISCHARGING] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- status->curr_run_time_sec[CHARGING] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- status->curr_cap_counter[CHARGING] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- status->curr_charger_status = atoi(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- status->reset_mark = atoi(token);
- return RESOURCED_ERROR_NONE;
-};
-
-static int heart_battery_load_usage(char *key, struct battery_usage *usage, int total_size)
-{
- int i, num, ret;
- char *token;
- char buf[BATTERY_DATA_MAX] = {0, };
- char *saveptr;
-
- if (!key || !usage)
- return RESOURCED_ERROR_FAIL;
-
- ret = logging_leveldb_read(key, strlen(key), buf, sizeof(buf));
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to read leveldb key");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (buf[0] == '\0') {
- _D("There is no history about %s", key);
- return RESOURCED_ERROR_NONE;
- }
-
- i = 0;
- num = total_size/sizeof(struct battery_usage);
- token = strtok_r(buf, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- while (token && i++ < num) {
- usage[i].start_time = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- usage[i].sec_per_cap[DISCHARGING] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- usage[i].cap_counter[DISCHARGING] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- usage[i].sec_per_cap[CHARGING] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- usage[i].cap_counter[CHARGING] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- _D("load [%d] stime: %ld, spc: %ld, count: %ld, spc: %ld, count: %ld",
- i, usage[i].start_time, usage[i].sec_per_cap[DISCHARGING],
- usage[i].cap_counter[DISCHARGING], usage[i].sec_per_cap[CHARGING],
- usage[i].cap_counter[CHARGING]);
- }
- return RESOURCED_ERROR_NONE;
-};
-
-static int heart_battery_load_prediction(char *key, struct battery_prediction *prediction)
-{
- int ret, i;
- char *token;
- char buf[BATTERY_DATA_MAX] = {0, };
- char *saveptr;
-
- if (!key || !prediction)
- return RESOURCED_ERROR_FAIL;
-
- ret = logging_leveldb_read(key, strlen(key), buf, sizeof(buf));
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to read leveldb key: %s", key);
- return RESOURCED_ERROR_FAIL;
- }
- token = strtok_r(buf, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- for (i = 0; i < MAX_STRATEGY && token; i++) {
- prediction[DISCHARGING].sec_per_cap[i] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- prediction[DISCHARGING].cap_counter[i] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- prediction[DISCHARGING].time_pred_min[i] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- prediction[CHARGING].sec_per_cap[i] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- prediction[CHARGING].cap_counter[i] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("Failed to token value");
- return RESOURCED_ERROR_FAIL;
- }
- prediction[CHARGING].time_pred_min[i] = atol(token);
- token = strtok_r(NULL, " ", &saveptr);
- }
- return RESOURCED_ERROR_NONE;
-};
-
-static void heart_battery_update_used_time(time_t now, enum charger_status_type status)
-{
- if (batt_used.last_charger_status == DISCHARGING)
- batt_used.used_time_sec +=
- now - batt_used.last_update_time;
- batt_used.last_charger_status = status;
- batt_used.last_update_time = now;
- heart_battery_save_used_time(BATTERY_USED_TIME, &batt_used);
-}
-
-static int heart_battery_get_capacity_history_size(void)
-{
- int size, ret;
-
- ret = pthread_mutex_lock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- size = g_slist_length(capacity_history_list);
- if (!size) {
- _I("capacity history is empty");
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_NONE;
- }
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return size;
-}
-
-static void heart_battery_insert_capacity(GSList **history_list, int capacity,
- int diff_capacity, time_t timestamp, long used_time, long charging_time,
- enum charger_status_type charger_status, int reset_mark, int clear)
-{
- static int old_reset_mark = 0;
- GSList *iter, *next;
- int ret, count;
- struct heart_battery_capacity *lbc, *tlbc;
-
- lbc = malloc(sizeof(struct heart_battery_capacity));
- if (!lbc) {
- _E("malloc failed");
- return;
- }
- lbc->capacity = capacity;
- lbc->diff_capacity = diff_capacity;
- lbc->used_time = used_time;
- lbc->charging_time = charging_time;
- lbc->charger_status = charger_status;
- lbc->reset_mark = reset_mark;
- lbc->timestamp = timestamp;
-
- ret = pthread_mutex_lock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- free(lbc);
- return;
- }
- /* clean all history when reset event */
- if (clear && *history_list && lbc->reset_mark != old_reset_mark) {
- g_slist_free_full(*history_list, free);
- *history_list = NULL;
- }
-
- /* history reached maximum limitation number */
- if (*history_list && g_slist_length(*history_list) > BATTERY_CAPACITY_MAX) {
- count = 0;
- gslist_for_each_safe(*history_list, iter, next, tlbc) {
- *history_list = g_slist_remove(*history_list, (gpointer)tlbc);
- free(tlbc);
- if (BATTERY_CLEAN_MAX < count++)
- break;
- }
- }
- old_reset_mark = lbc->reset_mark;
- *history_list = g_slist_append(*history_list, (gpointer)lbc);
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret)
- _E("pthread_mutex_unlock() failed, %d", ret);
-}
-
-/* ======================== Serialization/Deserialization ==================== */
-
-static void heart_battery_status_save_to_db(void)
-{
- heart_battery_save_used_time(BATTERY_USED_TIME, &batt_used);
- heart_battery_save_status(BATTERY_STATUS, &batt_stat);
-
- heart_battery_save_usage(BATTERY_RESET_USAGE, batt_stat.batt_reset_usage, sizeof(batt_stat.batt_reset_usage));
- heart_battery_save_usage(BATTERY_WEEK_DAY_USAGE, batt_stat.week_day_usage, sizeof(batt_stat.week_day_usage));
- heart_battery_save_usage(BATTERY_LEVEL_USAGE, batt_stat.batt_lvl_usage, sizeof(batt_stat.batt_lvl_usage));
-
- heart_battery_save_prediction(BATTERY_PREDICTION, batt_stat.prediction);
-}
-
-static int heart_battery_status_read_from_db(void)
-{
- bool ok = true;
-
- ok &= (RESOURCED_ERROR_NONE == heart_battery_load_used_time(BATTERY_USED_TIME, &batt_used));
- ok &= (RESOURCED_ERROR_NONE == heart_battery_load_status(BATTERY_STATUS, &batt_stat));
-
- ok &= (RESOURCED_ERROR_NONE == heart_battery_load_usage(BATTERY_RESET_USAGE, batt_stat.batt_reset_usage, sizeof(batt_stat.batt_reset_usage)));
- ok &= (RESOURCED_ERROR_NONE == heart_battery_load_usage(BATTERY_WEEK_DAY_USAGE, batt_stat.week_day_usage, sizeof(batt_stat.week_day_usage)));
- ok &= (RESOURCED_ERROR_NONE == heart_battery_load_usage(BATTERY_LEVEL_USAGE, batt_stat.batt_lvl_usage, sizeof(batt_stat.batt_lvl_usage)));
-
- ok &= (RESOURCED_ERROR_NONE == heart_battery_load_prediction(BATTERY_PREDICTION, batt_stat.prediction));
-
- return ok ? RESOURCED_ERROR_NONE : RESOURCED_ERROR_FAIL;
-}
-
-static int heart_battery_capacity_save_to_file(char *filename)
-{
- int size, ret, count, len = 0;
- struct heart_battery_capacity *lbc;
- GSList *iter, *next;
- FILE *fp;
- char buf[BATTERY_DATA_MAX] = {0, };
-
- if (!capacity_history_list) {
- _E("capacity history is NULL!");
- return RESOURCED_ERROR_NONE;
- }
- ret = pthread_mutex_lock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- size = g_slist_length(capacity_history_list);
- if (!size) {
- _I("capacity history is empty");
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_NONE;
- }
- fp = fopen(filename, "w");
- if (!fp) {
- _E("%s fopen failed %d", filename, errno);
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_FAIL;
- }
- gslist_for_each_item(iter, capacity_history_list) {
- lbc = (struct heart_battery_capacity *)iter->data;
- if (!lbc)
- break;
- len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%d %d %ld %ld %ld %d %d\n",
- lbc->capacity, lbc->diff_capacity, lbc->timestamp, lbc->used_time,
- lbc->charging_time, lbc->charger_status,
- lbc->reset_mark);
- if (BATTERY_DATA_MAX < len + BATTERY_LINE_MAX) {
- fputs(buf, fp);
- len = 0;
- }
- }
- fputs(buf, fp);
- fclose(fp);
- if (BATTERY_CAPACITY_MAX < size) {
- count = 0;
- gslist_for_each_safe(capacity_history_list, iter, next, lbc) {
- capacity_history_list = g_slist_remove(capacity_history_list, (gpointer)lbc);
- free(lbc);
- if (BATTERY_CLEAN_MAX < count++)
- break;
- }
- }
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_battery_capacity_read_from_file(char *filename)
-{
- int len;
- int capacity, diff_capacity, charger_status, reset_mark;
- long used_time, charging_time;
- time_t timestamp;
- FILE *fp;
- char buf[BATTERY_DATA_MAX] = {0, };
- int ret;
-
- fp = fopen(filename, "r");
- if (!fp) {
- if (errno != ENOENT) {
- _E("Fail to open %s (%d)", buf, errno);
- return RESOURCED_ERROR_FAIL;
- }
-
- _D("%s doesn't exist. Make new one.", buf);
- ret = mkdir(HEART_FILE_PATH, S_IRWXU | S_IRWXG | S_IROTH);
- if (ret != 0 && errno != EEXIST) {
- _E("Fail to create %s (%d)", buf, errno);
- return RESOURCED_ERROR_FAIL;
- }
-
- fp = fopen(filename, "w+");
- if (!fp) {
- _E("Fail to create %s (%d)", buf, errno);
- return RESOURCED_ERROR_FAIL;
- }
- fclose(fp);
- return RESOURCED_ERROR_NONE;
- }
-
- while (fgets(buf, BATTERY_DATA_MAX, fp)) {
- len = sscanf(buf, "%d %d %ld %ld %ld %d %d", &capacity, &diff_capacity,
- ×tamp, &used_time, &charging_time,
- &charger_status, &reset_mark);
- if (len < 0) {
- _E("sscanf failed");
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- heart_battery_insert_capacity(&capacity_history_list, capacity, diff_capacity,
- timestamp, used_time, charging_time,
- charger_status, reset_mark, true);
- }
- fclose(fp);
- return RESOURCED_ERROR_NONE;
-}
-
-/* ==================== Serialization/Deserialization END ==================== */
-
-static void heart_battery_save_to_file(bool force)
-{
- int ret;
- time_t now = logging_get_time(CLOCK_BOOTTIME);
-
- heart_battery_update_used_time(now, batt_stat.curr_charger_status);
-
- if (!force &&
- heart_battery_get_file_commit_timestamp() + HEART_BATTERY_SAVE_INTERVAL >= now)
- return;
-
- heart_battery_status_save_to_db();
-
- ret = heart_battery_capacity_save_to_file(HEART_BATTERY_CAPACITY_DATA_FILE);
- if (ret)
- _E("failed to save capacity file");
- heart_battery_set_file_commit_timestamp(now);
-}
-
-/*
- * This function will open the '.battery_data.dat' file and write all battery
- * related data into it.
- */
-static void heart_battery_write_data_to_file(void)
-{
- int i;
- int len = 0;
- char buff[BATTERY_DATA_MAX] = {0, 0};
- _cleanup_fclose_ FILE *fp = NULL;
-
- fp = fopen(HEART_BATTERY_DATA_FILE, "w");
- if (fp == NULL) {
- _E("Could not open file battery_data file\n");
- return;
- }
-
- for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
- len += snprintf(buff + len, BATTERY_DATA_MAX - len, "%ld %lf\n", \
- batt_stat.last_wall_time[i], batt_stat.last_volt_intg[i]);
-
- if (BATTERY_DATA_MAX < len + BATTERY_LINE_MAX) {
- fputs(buff, fp);
- len = 0;
- }
- }
- len += snprintf(buff + len, BATTERY_DATA_MAX - len, "%d %d %d %d %lf %d", \
- batt_stat.curr_index, batt_stat.last_capacity, batt_stat.remaining_time, \
- batt_stat.remaining_time_ups, batt_stat.last_pwr_bchg, batt_stat.data_available);
-
- fputs(buff, fp);
-}
-
-/*
- * This function will open the '.battery_data.dat' file and read all battery
- * related data from it and store in variable 'batt_stat'
- */
-static void heart_battery_read_data_from_file(void)
-{
- int i;
- int len = 0;
- char buff[BATTERY_DATA_MAX] = {0, 0};
- char *ch;
- _cleanup_fclose_ FILE *fp = NULL;
-
- fp = fopen(HEART_BATTERY_DATA_FILE, "r");
- if (fp == NULL) {
- _E("Could not open battery_data file\n");
- return;
- }
-
- for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
- ch = fgets(buff, BATTERY_DATA_MAX, fp);
- if (ch == NULL)
- /*if file is empty then return from here */
- return;
-
- len += sscanf(buff, "%ld %lf", \
- &batt_stat.last_wall_time[i], &batt_stat.last_volt_intg[i]);
- }
-
- ch = fgets(buff, BATTERY_DATA_MAX, fp);
- if (ch != NULL)
- len += sscanf(buff, "%d %d %d %d %lf %d", \
- &batt_stat.curr_index, &batt_stat.last_capacity, &batt_stat.remaining_time, \
- &batt_stat.remaining_time_ups, &batt_stat.last_pwr_bchg, &batt_stat.data_available);
-}
-
-/*
- * This function will reject all the battery related data which were stored earlier
- */
-static void heart_battery_reject_data(void)
-{
- int i;
-
- for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
- batt_stat.last_wall_time[i] = 0;
- batt_stat.last_volt_intg[i] = 0.0;
- }
-
- /* Do not reject this, once data available, do not change untill next binary flash */
- /*batt_stat.data_available = 0; */
- batt_stat.last_capacity = 0;
- batt_stat.curr_index = 0;
- batt_stat.remaining_time = 0;
- batt_stat.remaining_time_ups = 0;
- /* do not flush this value. When proper power value is not present, previously
- calculated power only will be used. */
- /*batt_stat.last_pwr_bchg = 0.0; */
-
- heart_battery_write_data_to_file();
-}
-
-/*
- * This function will calculate the voltage integral(energy) at battery level 100.
- * We will calculate Pivot using fast discharge and slow discharge rate for
- * estimating the battery time in normal mode
- */
-static void heart_battery_calculate_pivot(void)
-{
- int i;
-
- for (i = 0; i < ocv_degree; i++)
- volt_intg_full += (intg[i] /(i+1)) * pow(100 , i+1);
- volt_intg_full = volt_intg_full/100000.0;
-
- pivot_nor = ((sqrt(discharge_fast) + sqrt(discharge_slow))/2);
- pivot_nor = pivot_nor * pivot_nor; // taking square of Tpivot
-
- pivot_ups = ((sqrt(discharge_fast*UPS_FACTOR) + sqrt(discharge_slow*UPS_FACTOR))/2);
- pivot_ups = pivot_ups * pivot_ups; // taking square of Tpivot
-}
-
-/* function to return the time(in seconds) since the Epoch*/
-static long heart_battery_logging_get_time_sec_new(void)
-{
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
-
- return (tv.tv_sec + tv.tv_usec / 1000000);
-}
-
-/*
- * This function will read the current time and will compare with previously stored time.
- * If time difference is more then it is assumed that device was powered off and it will
- * adjust all stored time values
- */
-static void heart_battery_power_off_time_adjustment(void)
-{
- int i;
- int index;
- int clock_tick_diff = 0;
- long int curr_time;
- long int time_diff = 0;
-
- curr_time = heart_battery_logging_get_time_sec_new();
-
- index = BATTERY_WINDOW_INDEX(batt_stat.curr_index - 1);
- if (batt_stat.last_wall_time[index] == 0)
- index = 0;
-
- clock_tick_diff = logging_get_time(CLOCK_BOOTTIME) - batt_stat.last_clock_tick;
-
- /* check if we have store last time value or not */
- if (batt_stat.last_wall_time[index] != 0) {
- time_diff = curr_time - batt_stat.last_wall_time[index];
- time_diff -= clock_tick_diff;
- }
-
- _I("All store time value will be scaled up by %ld secs\n", time_diff);
-
- /*scale up all stored time value */
- for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
- if (batt_stat.last_wall_time[i] == 0) {
- /* we do not have stored time value from this point onwards, stop updating*/
- break;
- } else
- batt_stat.last_wall_time[i] += time_diff;
- }
-
- /* update same value in battery data file*/
- heart_battery_write_data_to_file();
-
- /*
- * during charge time
- */
- time_diff = curr_time - batt_stat.last_wall_time_chg;
- time_diff -= clock_tick_diff;
- /*
- * update last_wall_time_chg as per previous and new time diff
- * it will take care of positive of negative difference
- */
- batt_stat.last_wall_time_chg += time_diff;
- _I("last_wall_time_chg got updated by %ld\n", time_diff);
- /*
- * make first_level_change as TRUE so that charge remaining time
- * should not vary much
- */
- first_level_change = TRUE;
-
- /* for pivot data */
- if (batt_stat.pvt.start_time_dischg != 0) {
- time_diff = curr_time - batt_stat.pvt.start_time_dischg;
- clock_tick_diff = logging_get_time(CLOCK_BOOTTIME) - batt_stat.pvt.last_clock_tick;
- time_diff -= clock_tick_diff;
- batt_stat.pvt.start_time_dischg += time_diff;
- }
-}
-
-/*
- * In case of any time change in the device, this callback get called and it
- * will do the time adjustment
- */
-static void time_change_notify_cb(keynode_t *key, void *data)
-{
- heart_battery_power_off_time_adjustment();
-}
-
-static int get_battery_remaining_time_new(void)
-{
- return batt_stat.remaining_time;
-}
-
-static int get_battery_remaining_time_ups()
-{
- return batt_stat.remaining_time_ups;
-}
-
-/*
- * This function will return the average of stored time diff values
- */
-static int heart_battery_get_time_diff_avg(int time_diff_avg)
-{
- int temp_index;
- int i;
-
- if (data_avail_chg == true) {
- /*
- * calculate the average of last 5(including current) time diff values
- */
- temp_index = ((batt_stat.index_chg-1) + BATTERY_LEVEL_GAP) % BATTERY_LEVEL_GAP;
- for (i = 1; i < BATTERY_LEVEL_GAP; i++) {
- time_diff_avg += batt_stat.last_wall_time_chg_diff[temp_index];
- temp_index = ((temp_index-1) + BATTERY_LEVEL_GAP) % BATTERY_LEVEL_GAP;
- }
- time_diff_avg = time_diff_avg/BATTERY_LEVEL_GAP;
- } else {
- /*
- * take average of only available data. Do not include 1st value so
- * i stared from 1.
- */
- for (i = 1; i < batt_stat.index_chg; i++)
- time_diff_avg += batt_stat.last_wall_time_chg_diff[i];
-
- time_diff_avg = time_diff_avg/i;
- }
- /*
- * to minimize the time diff fluctuation
- */
- time_diff_avg = (time_diff_avg+BATTERY_C_RATE)/2;
- _I("time_diff after averaging= %d seconds\n", time_diff_avg);
-
- return time_diff_avg;
-}
-
-/*
- * This function will return the time diff between last and current battery
- * level change
- */
-int heart_battery_get_time_diff(long curr_wall_time)
-{
- if (batt_stat.last_wall_time_chg == 0)
- /*
- * First time estimation
- * In this case charge rate will be considered as time diff
- */
- return BATTERY_C_RATE;
-
- return (curr_wall_time - batt_stat.last_wall_time_chg);
-}
-
-static void heart_battery_print_prev_charge_data(void)
-{
- int i;
-
- _I("Charging stored data, current index = %d", batt_stat.index_chg);
-
- for (i = 0; i < BATTERY_LEVEL_GAP; i++)
- _I("Index = %d, time_diff = %d", i, batt_stat.last_wall_time_chg_diff[i]);
-}
-
-/*
- * This function will flush the stored charge data
- */
-static void heart_battery_flush_charge_data(void)
-{
- int i;
-
- _I("Prev and curr battery lvl gap = %d, flush charge data",
- batt_stat.last_capacity_chg - batt_stat.curr_capacity);
-
- for (i = 0; i < BATTERY_LEVEL_GAP; i++)
- batt_stat.last_wall_time_chg_diff[i] = 0;
-
- batt_stat.last_wall_time_chg = 0;
- batt_stat.index_chg = 0;
- data_avail_chg = false;
-}
-
-/*
- * store the discharge start time and capacity to calculte the
- * time taken for the discharge period
- */
-static void heart_battery_collect_discharge_data(void)
-{
- batt_stat.pvt.start_cap_dischg = batt_stat.curr_capacity;
- batt_stat.pvt.start_time_dischg = heart_battery_logging_get_time_sec_new();
- batt_stat.pvt.last_clock_tick = logging_get_time(CLOCK_BOOTTIME);
-}
-
-/*
- * Read all the stored pivot data from file and keep it in
- * local variable batt_stat.pvt
- */
-static void heart_battery_read_pivot_info_from_file(void)
-{
- int i;
- char buf[BATTERY_DATA_MAX] = {0, };
- char *p;
- _cleanup_fclose_ FILE *fp = NULL;
-
- fp = fopen(HEART_BATTERY_PIVOT_INFO, "r");
- if (fp == NULL) {
- _E("Could not open pivot info file");
- return;
- }
-
- for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
- p = fgets(buf, BATTERY_DATA_MAX, fp);
- if (p == NULL)
- return;
-
- if (sscanf(buf, "%d", &batt_stat.pvt.total_dischg_time[i]) == -1)
- return;
- }
-
- p = fgets(buf, BATTERY_DATA_MAX, fp);
- if (!p)
- return;
- if (sscanf(buf, "%d", &batt_stat.pvt.pvt_data_ind) == -1)
- return;
-
-}
-
-/*
- * Store all the local pivot data to a file
- */
-static void heart_battery_save_pivot_info(void)
-{
- int len = 0;
- int i;
- char buf[BATTERY_DATA_MAX] = {0, };
- _cleanup_fclose_ FILE *fp = NULL;
-
- fp = fopen(HEART_BATTERY_PIVOT_INFO, "w");
- if (fp == NULL) {
- _E("Could not open pivot info file");
- return;
- }
-
- for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
- len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%d\n",
- batt_stat.pvt.total_dischg_time[i]);
-
- if (BATTERY_DATA_MAX < len + BATTERY_LINE_MAX) {
- fputs(buf, fp);
- len = 0;
- }
- }
- len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%d",
- batt_stat.pvt.pvt_data_ind);
-
- fputs(buf, fp);
-}
-
-/*
- * Calculate the remaining enery in battery based on current capacity
- */
-static double heart_battery_get_energy(int capacity)
-{
- int i;
- double volt_intg = 0;
-
- for (i = 0; i < ocv_degree; i++)
- volt_intg += (intg[i] /(i+1)) * pow(capacity , i+1);
-
- return (volt_intg /100000.0);
-}
-
-/*
- * Update the pivot based on device learning data
- */
-static void heart_battery_update_pivot(void)
-{
- int i;
- int avg = 0;
-
- static int count = 1;
-
- for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
- if(batt_stat.pvt.total_dischg_time[i] == 0)
- break;
- avg += batt_stat.pvt.total_dischg_time[i];
- }
-
- if (avg == 0)
- return;
- if (i != 0)
- avg = (avg / i);
-
- /*
- * Total 10 discharge cycle data will be stored and based on those values
- * new pivot will be calculted. Untill 10 cycles data are not available, take
- * count/10 % from new pivot and 1-count/10 % from existing pivot. By
- * doing this, sudden jump in pivot can be avoided
- */
- if (count <= 10) {
- avg = NEW_PIVOT_WEIGHTAGE(count) * avg + OLD_PIVOT_WEIGHTAGE(count) * pivot_nor;
- count++;
- }
-
- _I("Old pivot = %lf, New pivot =%d, count = %d", pivot_nor, avg, count);
-
- pivot_nor = avg;
- pivot_ups = pivot_nor * UPS_FACTOR;
-}
-
-/*
- * This function will take the average of last 10 discharge time period and
- * update the pivot
- */
-static void heart_battery_collect_pivot_info(void)
-{
- long curr_time;
- int time_diff;
- int cap_diff;
- int total_time;
-
- double energy_dis;
- double energy_chg;
- double energy_total;
-
- if (batt_stat.pvt.start_time_dischg == 0)
- return;
-
- curr_time = heart_battery_logging_get_time_sec_new();
- time_diff = curr_time - batt_stat.pvt.start_time_dischg;
- cap_diff = batt_stat.pvt.start_cap_dischg - batt_stat.curr_capacity;
-
- /* discharge period is too less so do not consider this period */
- if (cap_diff < MIN_DISCHARGE_PERIOD)
- return;
-
- energy_dis = heart_battery_get_energy(batt_stat.pvt.start_cap_dischg);
- energy_chg = heart_battery_get_energy(batt_stat.curr_capacity);
- energy_total = heart_battery_get_energy(FULL_CAPACITY);
-
- total_time = (energy_total * time_diff) /(energy_dis - energy_chg);
-
- _I("Energy discharge = %lf, Energy charge = %lf, Energy Total = %lf, Total time = %d",
- energy_dis, energy_chg, energy_total, total_time);
-
- batt_stat.pvt.total_dischg_time[batt_stat.pvt.pvt_data_ind] = SEC_TO_MIN(total_time);
- batt_stat.pvt.pvt_data_ind = (batt_stat.pvt.pvt_data_ind + 1) % INDEX_WINDOW_SIZE;
-
- /* update the pivot */
- heart_battery_update_pivot();
- /* save pivot info into file */
- heart_battery_save_pivot_info();
-}
-
-/*
- * This function will calculate the battery charging remaining time
- */
-static void heart_battery_cal_charging_rem_time(void)
-{
- long curr_wall_time = 0;
- int rem_time;
- int time_diff;
- int time_diff_avg;
- double temp_cv;
-
- if (batt_stat.last_capacity_chg == batt_stat.curr_capacity) {
- _I("Last capacity %d is same as current capacity %d\n",
- batt_stat.last_capacity_chg, batt_stat.curr_capacity);
- return;
- }
-
- curr_wall_time = heart_battery_logging_get_time_sec_new();
-
- time_diff = heart_battery_get_time_diff(curr_wall_time);
-
- /*
- * just after inserting the charger, if time diff between two level
- * is less than MIN_TIME_FOR_LVL_CHANGE value then consider time diff
- * as BATTERY_C_RATE so that there will not be sudden fall in charge
- * remaining time
- */
- if (time_diff < MIN_TIME_FOR_LVL_CHANGE && first_level_change == TRUE) {
- /*
- * first_level_change will be set to TRUE in function
- * heart_battery_charger_status() and set to FALSE in function
- * heart_battery_capacity_status()
- */
- _I("time diff %d is less than min value of lvl change %d\n",
- time_diff, MIN_TIME_FOR_LVL_CHANGE);
- time_diff = BATTERY_C_RATE;
- }
-
- _I("data_avail_chg = %d, index_chg = %d\n",
- data_avail_chg, batt_stat.index_chg);
- _I("last_wall_time_chg = %ld, curr_wall_time = %ld\n",
- batt_stat.last_wall_time_chg, curr_wall_time);
- _I("time diff before averaging = %d seconds\n", time_diff);
-
- /*
- * get the average of all time diff values stored including current
- */
- time_diff_avg = heart_battery_get_time_diff_avg(time_diff);
-
- if (time_diff_avg > BATTERY_C_RATE && batt_stat.curr_capacity <= 30)
- time_diff_avg = BATTERY_C_RATE;
-
- if (batt_stat.curr_capacity == FULL_CAPACITY) {
- batt_stat.remaining_time_chg = 0;
- } else {
- /*
- * calculate the remaining charge time based on constant current
- * and constant votlage(CCCV) logic. 'time_diff_avg' is for CC and
- * 'temp_cv' is for CV part.
- */
- temp_cv = ((double)time_diff_avg)/((double)BATTERY_C_RATE);
- temp_cv = temp_cv * temp_cv;
- rem_time = (time_diff_avg + temp_cv)*(FULL_CAPACITY - batt_stat.curr_capacity);
- batt_stat.remaining_time_chg = SEC_TO_MIN(rem_time);
- }
-
- batt_stat.last_wall_time_chg = curr_wall_time;
- batt_stat.last_wall_time_chg_diff[batt_stat.index_chg] = time_diff;
- batt_stat.index_chg = (batt_stat.index_chg+1)%BATTERY_LEVEL_GAP;
- batt_stat.last_capacity_chg = batt_stat.curr_capacity;
- batt_stat.last_clock_tick = logging_get_time(CLOCK_BOOTTIME);
-
- _I("Capacity = %d, charging remaining time = %d minutes\n",
- batt_stat.curr_capacity, batt_stat.remaining_time_chg);
-
- if (batt_stat.index_chg+1 == BATTERY_LEVEL_GAP)
- data_avail_chg = true;
-}
-
-/*
- * This function will calculate the battery estimation time for every battery
- * level change
- */
-static void heart_battery_cal_discharge_rem_time(void)
-{
- double curr_volt_intg = 0;
- double volt_intg_diff = 0;
- double ps, pt;
- double batt_pwr;
- int rem_time = 0;
- int index = 0;
- int temp_index = 0;
- int index_count;
- int i;
- int update_time;
- long curr_wall_time = 0;
- long time_diff1, time_diff2;
-
- _I("last capacity = %d, current capacity = %d\n", batt_stat.last_capacity, batt_stat.curr_capacity);
-
- /* if battery level change happen then only calculate the new time*/
- if (batt_stat.last_capacity != batt_stat.curr_capacity) {
- /* calculate the voltage integral(energy) for current capacity */
- for (i = 0; i < ocv_degree; i++)
- curr_volt_intg += (intg[i] /(i+1)) * pow(batt_stat.curr_capacity , i+1);
- curr_volt_intg = curr_volt_intg /100000.0;
-
- /*current time*/
- curr_wall_time = heart_battery_logging_get_time_sec_new();
-
- _I("curr_volt_intg = %lf, curr_wall_time = %ld\n", curr_volt_intg, curr_wall_time);
-
- if (batt_stat.last_capacity < batt_stat.curr_capacity) {
- /*
- *this indicates that device was put for charging so need to reject
- *all the previous data except 'batt_stat.data_available' and
- *'batt_stat.last_pwr_bchg'. Use last available battery power
- *before connecting the charger as current average power.
- */
- batt_pwr = batt_stat.last_pwr_bchg;
- heart_battery_reject_data();
- } else {
- index = BATTERY_WINDOW_INDEX(batt_stat.curr_index - BATTERY_LEVEL_GAP);
- if (batt_stat.last_wall_time[index] == 0 &&
- batt_stat.last_volt_intg[index] == 0) {
- /*
- *do not have enough previous data so take 1st stored data
- *as reference
- */
- time_diff1 = curr_wall_time - batt_stat.last_wall_time[0];
- volt_intg_diff = batt_stat.last_volt_intg[0] - curr_volt_intg;
- if (volt_intg_diff < DOUBLE_ZERO)
- volt_intg_diff = volt_intg_full - curr_volt_intg;
- } else {
- /* time differenc since last battery level change*/
- time_diff1 = curr_wall_time - batt_stat.last_wall_time[index];
- /* voltage integral(energy) change since last battery level change */
- volt_intg_diff = batt_stat.last_volt_intg[index] - curr_volt_intg;
- }
- _I("time_diff1 = %ld, volt_intg_diff = %lf\n", time_diff1, volt_intg_diff);
-
- time_diff1 = SEC_TO_MIN(time_diff1); /*convert second to minute */
-
- /* calculate short term average power component*/
- if (time_diff1 != 0)
- ps = (total_battery_capacity *volt_intg_diff) / time_diff1;
- else
- ps = 0;
-
- _I("ps = %lf\n", ps);
-
- /* find the voltage integral(energy) of 1 hr back battery level.
- 1. Place the index at proper location
- 2. get the time stored at that index
- 3. if difference between last time and current time is >= 60 then take that voltage integral
- */
- index_count = INDEX_WINDOW_SIZE;
- time_diff2 = 0;
- temp_index = BATTERY_WINDOW_INDEX(batt_stat.curr_index - 1);
- while ((index_count > 0) && (time_diff2 < 60)) {
- if (batt_stat.last_wall_time[temp_index] == 0)
- /* data not available so break the loop */
- break;
-
- time_diff2 = SEC_TO_MIN(curr_wall_time - batt_stat.last_wall_time[temp_index]);
- temp_index = BATTERY_WINDOW_INDEX(temp_index - 1);
- index_count--;
- }
-
- /* calculate long term average power component*/
- if (time_diff2 < 60) {
- pt = 0;
- } else {
- temp_index = BATTERY_WINDOW_INDEX(temp_index + 1);
- volt_intg_diff = batt_stat.last_volt_intg[temp_index] - curr_volt_intg ;
- if (volt_intg_diff < DOUBLE_ZERO)
- pt = 0;
- else
- pt = (total_battery_capacity * volt_intg_diff) / time_diff2;
- }
-
- _I("time_diff2 = %ld, volt_intg_diff = %lf, pt = %lf\n", time_diff2, volt_intg_diff, pt);
-
- /* calculate the average power from the short component and long component*/
- if ((pt + ps) != 0)
- batt_pwr = (((pt * pt) + (ps * ps)) / (pt + ps));
- else
- batt_pwr = batt_stat.last_pwr_bchg;
- }
-
- /* total remaining time based on current battery level*/
- rem_time = (total_battery_capacity * curr_volt_intg) / batt_pwr;
-
- _I("pivot_nor = %lf, curr_volt_intg = %lf , volt_intg_full %lf, batt_pwr = %lf", pivot_nor, curr_volt_intg, volt_intg_full, batt_pwr);
-
- /* calculate remaining time for normal mode */
- update_time = (pivot_nor * curr_volt_intg) / volt_intg_full;
- batt_stat.remaining_time = (LONG_TIME_WEIGHT * update_time + SHORT_TIME_WEIGHT * CAL_MIN(update_time, rem_time));
-
- /* calculate remaining time for UPS mode */
- update_time = (pivot_ups * curr_volt_intg) / volt_intg_full;
- batt_stat.remaining_time_ups = (LONG_TIME_WEIGHT * update_time + SHORT_TIME_WEIGHT * CAL_MIN(update_time, rem_time));
-
- _I("normal mode remaining time = %d minutes, ups remaining time = %d minutes\n",
- batt_stat.remaining_time, batt_stat.remaining_time_ups);
-
- batt_stat.last_volt_intg[batt_stat.curr_index] = curr_volt_intg;
- batt_stat.last_wall_time[batt_stat.curr_index] = curr_wall_time;
- batt_stat.last_capacity = batt_stat.curr_capacity;
- batt_stat.curr_index = (batt_stat.curr_index + 1) % INDEX_WINDOW_SIZE;
- batt_stat.last_clock_tick = logging_get_time(CLOCK_BOOTTIME);
-
- if (batt_pwr > DOUBLE_ZERO) {
- /*
- *when battery percentage is 0 then available power will be 0 so
- *do not store this value. keep previous value only.
- */
- batt_stat.last_pwr_bchg = batt_pwr;
- }
-
- if (batt_stat.curr_index > BATTERY_LEVEL_GAP) {
- /*
- *When enough data to estimate the available battery time are
- *stored, no need to update the status of batt_stat. data_available
- *untill we are flashing new binary.
- */
- batt_stat.data_available = TRUE;
- }
-
- /* save all calculated battery data to file*/
- heart_battery_write_data_to_file();
- }
-}
-
-void heart_battery_update(struct logging_table_form *data, void *user_data)
-{
- heart_battery_save_to_file(false);
-}
-
-static int heart_battery_get_level_usage_index(int capacity)
-{
- return (capacity > 49) ? BATTERY_LEVEL_HIGH :
- (capacity < 16) ? BATTERY_LEVEL_LOW : BATTERY_LEVEL_MID;
-}
-
-static int heart_battery_get_week_day_usage_index(time_t timestamp)
-{
- int i;
-
- for (i = 0; i < BATTERY_HISTORY_DAY_MAX; i++) {
- if (!heart_battery_get_usage_week_stime(i))
- return i;
- else if (abs(timestamp - heart_battery_get_usage_week_stime(i)) < DAY_TO_SEC(1))
- return i;
- }
- for (i = 0; i < BATTERY_HISTORY_DAY_MAX - 1; i++) {
- batt_stat.week_day_usage[i].start_time =
- batt_stat.week_day_usage[i + 1].start_time;
- batt_stat.week_day_usage[i].sec_per_cap[DISCHARGING] =
- batt_stat.week_day_usage[i + 1].sec_per_cap[DISCHARGING];
- batt_stat.week_day_usage[i].sec_per_cap[CHARGING] =
- batt_stat.week_day_usage[i + 1].sec_per_cap[CHARGING];
- batt_stat.week_day_usage[i].cap_counter[DISCHARGING] =
- batt_stat.week_day_usage[i + 1].cap_counter[DISCHARGING];
- batt_stat.week_day_usage[i].cap_counter[CHARGING] =
- batt_stat.week_day_usage[i + 1].cap_counter[CHARGING];
- }
- return BATTERY_HISTORY_DAY_MAX - 1;
-}
-
-static int heart_battery_get_batt_reset_usage_index(void)
-{
- int i;
-
- for (i = 0; i < BATTERY_HISTORY_RESET_MAX; i++) {
- if (heart_battery_get_usage_reset_count(i, DISCHARGING) < BATTERY_HISTORY_COUNT_MAX
- && heart_battery_get_usage_reset_count(i, CHARGING) < BATTERY_HISTORY_COUNT_MAX)
- return i;
- }
- for (i = 0; i < BATTERY_HISTORY_RESET_MAX - 1; i++) {
- batt_stat.batt_reset_usage[i].start_time =
- batt_stat.batt_reset_usage[i + 1].start_time;
- batt_stat.batt_reset_usage[i].sec_per_cap[DISCHARGING] =
- batt_stat.batt_reset_usage[i + 1].sec_per_cap[DISCHARGING];
- batt_stat.batt_reset_usage[i].sec_per_cap[CHARGING] =
- batt_stat.batt_reset_usage[i + 1].sec_per_cap[CHARGING];
- batt_stat.batt_reset_usage[i].cap_counter[DISCHARGING] =
- batt_stat.batt_reset_usage[i + 1].cap_counter[DISCHARGING];
- batt_stat.batt_reset_usage[i].cap_counter[CHARGING] =
- batt_stat.batt_reset_usage[i + 1].cap_counter[CHARGING];
- }
- return BATTERY_HISTORY_RESET_CURRENT;
-}
-
-static int heart_battery_reset(void *data)
-{
- int idx;
- long total_time, total_count, sec_per_cap;
-
- idx = heart_battery_get_batt_reset_usage_index();
-
- /* DISCHARGING */
- total_time = 0; total_count = 0;
- total_time = heart_battery_get_usage_reset_total_time(idx, DISCHARGING) + batt_stat.curr_run_time_sec[DISCHARGING];
- total_count = heart_battery_get_usage_reset_count(idx, DISCHARGING) + batt_stat.curr_cap_counter[DISCHARGING];
-
- if (total_time && total_count) {
- sec_per_cap = total_time / total_count;
- if (sec_per_cap < default_sec_per_cap[DISCHARGING][DEFAULT_MIN])
- sec_per_cap = default_sec_per_cap[DISCHARGING][DEFAULT_MIN];
- else if (sec_per_cap > default_sec_per_cap[DISCHARGING][DEFAULT_MAX])
- sec_per_cap = default_sec_per_cap[DISCHARGING][DEFAULT_MAX];
- heart_battery_set_usage_reset(idx, DISCHARGING, sec_per_cap, total_count);
- }
- /* CHARGING */
- total_time = 0; total_count = 0;
- total_time = heart_battery_get_usage_reset_total_time(idx, CHARGING)
- + batt_stat.curr_run_time_sec[CHARGING];
- total_count = heart_battery_get_usage_reset_count(idx, CHARGING) + batt_stat.curr_cap_counter[CHARGING];
-
- if (total_time && total_count) {
- sec_per_cap = total_time / total_count;
- if (sec_per_cap < default_sec_per_cap[CHARGING][DEFAULT_MIN])
- sec_per_cap = default_sec_per_cap[CHARGING][DEFAULT_MIN];
- else if (sec_per_cap > default_sec_per_cap[CHARGING][DEFAULT_MAX])
- sec_per_cap = default_sec_per_cap[CHARGING][DEFAULT_MAX];
- heart_battery_set_usage_reset(idx, CHARGING, sec_per_cap, total_count);
- }
-
- batt_stat.reset_mark = batt_stat.reset_mark ? 0 : 1; /* Swap reset_mark */
- batt_stat.reset_mark_timestamp = time(NULL);
- batt_stat.curr_run_time_sec[DISCHARGING] = 0;
- batt_stat.curr_run_time_sec[CHARGING] = 0;
- batt_stat.curr_cap_counter[DISCHARGING] = 0;
- batt_stat.curr_cap_counter[CHARGING] = 0;
- batt_used.used_time_sec = 0;
- batt_used.last_update_time = logging_get_time(CLOCK_BOOTTIME);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static long heart_battery_compute_remaining_time_in_min(int capacity_count, long sec_per_cap)
-{
- /*
- * Calculates and returns remaining time in minutes based on number
- * of capacity changes and time needed for one change.
- */
- long time;
-
- time = (capacity_count * sec_per_cap); /* seconds */
- time = time + 30; /* add 30s margin */
- time = time / 60; /* change to minutes */
- return time;
-}
-
-static void heart_battery_calculate_prediction(enum charger_status_type goal)
-{
- int i, capacity, level;
- long total_time, total_count, sec_per_cap, pred_min;
- long low_count, mid_count, high_count;
- struct heart_battery_capacity *lbc = NULL;
- GArray *arrays = NULL;
-
- if (goal == CHARGING)
- capacity = REMAIN_CAPACITY(batt_stat.curr_capacity);
- else {
- capacity = batt_stat.curr_capacity;
-
- if (goal != DISCHARGING) {
- _E("Wrong charging status is written. Suppose discharging");
- goal = DISCHARGING;
- }
- }
-
- /* PREDICTION METHOD: total average */
- total_time = 0;
- total_count = 0;
- for (i = 0; i < BATTERY_HISTORY_RESET_MAX; i++) {
- total_time += heart_battery_get_usage_reset_total_time(i, goal);
- total_count += heart_battery_get_usage_reset_count(i, goal);
- }
- total_time += batt_stat.curr_run_time_sec[goal];
- total_count += batt_stat.curr_cap_counter[goal];
-
- if (total_time && total_count >= BATTERY_PREDICTION_DATA_MIN) {
- sec_per_cap = total_time / total_count;
- if (sec_per_cap < default_sec_per_cap[goal][DEFAULT_MIN])
- sec_per_cap = default_sec_per_cap[goal][DEFAULT_MIN];
- else if (sec_per_cap > default_sec_per_cap[goal][DEFAULT_MAX])
- sec_per_cap = default_sec_per_cap[goal][DEFAULT_MAX];
- pred_min = heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
- heart_battery_set_prediction(TA, goal,
- sec_per_cap, total_count,
- pred_min);
- } else {
- heart_battery_set_prediction(TA, goal, 0, 0, 0);
- }
-
-
- /* PREDICTION METHOD:
- * Prediction of battery remaining usage time
- * considering users' psychological usage patterns
- * by batt_lvl_usage of battery charge
- * */
- pred_min = 0;
- sec_per_cap = 0;
- level = heart_battery_get_level_usage_index(capacity);
- low_count = heart_battery_get_usage_level_count(BATTERY_LEVEL_LOW, goal);
- mid_count = heart_battery_get_usage_level_count(BATTERY_LEVEL_MID, goal);
- high_count = heart_battery_get_usage_level_count(BATTERY_LEVEL_HIGH, goal);
-
- if (level == BATTERY_LEVEL_LOW && low_count) {
- sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_LOW, goal);
- pred_min = heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
- } else if (level == BATTERY_LEVEL_MID && low_count && mid_count) {
- sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_LOW, goal);
- pred_min = heart_battery_compute_remaining_time_in_min(15, sec_per_cap);
- sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_MID, goal);
- pred_min +=
- heart_battery_compute_remaining_time_in_min(capacity - 15, sec_per_cap);
- } else if (level == BATTERY_LEVEL_HIGH && low_count && mid_count && high_count) {
- sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_LOW, goal);
- pred_min = heart_battery_compute_remaining_time_in_min(15, sec_per_cap);
- sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_MID, goal);
- pred_min +=
- heart_battery_compute_remaining_time_in_min(35, sec_per_cap);
- sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_HIGH, goal);
- pred_min +=
- heart_battery_compute_remaining_time_in_min(capacity - 50, sec_per_cap);
- }
- heart_battery_set_prediction(PCB, goal, 0, 0, pred_min);
-
-
- /* PREDICTION METHOD: week average */
- total_time = 0;
- total_count = 0;
- for (i = 0; i < BATTERY_HISTORY_DAY_MAX; i++) {
- total_time += heart_battery_get_usage_week_total_time(i, goal);
- total_count += heart_battery_get_usage_week_count(i, goal);
- }
- if (total_time && total_count >= BATTERY_PREDICTION_DATA_MIN) {
- sec_per_cap = total_time / total_count;
- if (sec_per_cap < default_sec_per_cap[goal][DEFAULT_MIN])
- sec_per_cap = default_sec_per_cap[goal][DEFAULT_MIN];
- else if (sec_per_cap > default_sec_per_cap[goal][DEFAULT_MAX])
- sec_per_cap = default_sec_per_cap[goal][DEFAULT_MAX];
- pred_min =
- heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
- heart_battery_set_prediction(WEEK, goal, sec_per_cap, total_count, pred_min);
- } else
- heart_battery_set_prediction(WEEK, goal, 0, 0, 0);
-
-
- /* PREDICTION METHOD: last BATTERY_PREDICTION_COUNT data average */
- arrays = g_array_new(FALSE, FALSE, sizeof(struct heart_battery_capacity *));
- if (!arrays) {
- _E("Failed to alloc array");
- return;
- }
- if (heart_battery_get_capacity_history_latest(arrays, goal, BATTERY_PREDICTION_LATEST_COUNT)
- != RESOURCED_ERROR_NONE) {
- _E("Failed to get battery capacity history");
- g_array_free(arrays, TRUE);
- arrays = NULL;
- return;
- }
- total_time = 0;
- total_count = 0;
- for (i = 0; i < arrays->len; i++) {
- lbc = g_array_index(arrays, struct heart_battery_capacity *, i);
- if (!lbc)
- break;
- total_count += lbc->diff_capacity;
- if (goal == CHARGING)
- total_time += lbc->charging_time;
- else
- total_time += lbc->used_time;
- free(lbc);
- }
- if (total_time && total_count >= BATTERY_PREDICTION_DATA_MIN) {
- sec_per_cap = total_time / total_count;
- if (sec_per_cap < default_sec_per_cap[goal][DEFAULT_MIN])
- sec_per_cap = default_sec_per_cap[goal][DEFAULT_MIN];
- else if (sec_per_cap > default_sec_per_cap[goal][DEFAULT_MAX])
- sec_per_cap = default_sec_per_cap[goal][DEFAULT_MAX];
-
- pred_min =
- heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
- heart_battery_set_prediction(COUNT, goal, sec_per_cap, total_count, pred_min);
- /* check current discharge rate */
- if (sec_per_cap && goal == DISCHARGING) {
- batt_stat.discharge_rate_level =
- heart_battery_calculate_discharge_rate_level(sec_per_cap);
- _I("discharge rate level : %d", batt_stat.discharge_rate_level);
- }
- } else
- heart_battery_set_prediction(COUNT, goal, 0, 0, 0);
- g_array_free(arrays, TRUE);
- arrays = NULL;
-
-
- /* PREDICTION METHOD: last BATTERY_PREDICTION_PERIOD hours average */
- arrays = g_array_new(FALSE, FALSE, sizeof(struct heart_battery_capacity *));
- if (!arrays) {
- _E("Failed to alloc array");
- return;
- }
- if (heart_battery_get_capacity_history(arrays, BATTERY_PREDICTION_PERIOD) != RESOURCED_ERROR_NONE) {
- _E("Failed to get battery capacity history");
- g_array_free(arrays, TRUE);
- arrays = NULL;
- return;
- }
- total_time = 0;
- total_count = 0;
- for (i = 0; i < arrays->len; i++) {
- lbc = g_array_index(arrays, struct heart_battery_capacity *, i);
- if (!lbc)
- break;
- if (goal == CHARGING) {
- if (lbc->charger_status != CHARGING) {
- free(lbc);
- continue;
- }
- total_time += lbc->charging_time;
- total_count += lbc->diff_capacity;
- } else {
- if (lbc->charger_status != DISCHARGING) {
- free(lbc);
- continue;
- }
- total_time += lbc->used_time;
- total_count += lbc->diff_capacity;
- }
- free(lbc);
- }
- g_array_free(arrays, TRUE);
- arrays = NULL;
- if (total_time && total_count >= BATTERY_PREDICTION_DATA_MIN) {
- sec_per_cap = total_time / total_count;
- if (sec_per_cap < default_sec_per_cap[goal][DEFAULT_MIN])
- sec_per_cap = default_sec_per_cap[goal][DEFAULT_MIN];
- else if (sec_per_cap > default_sec_per_cap[goal][DEFAULT_MAX])
- sec_per_cap = default_sec_per_cap[goal][DEFAULT_MAX];
- pred_min =
- heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
- heart_battery_set_prediction(PERIOD, goal, sec_per_cap, total_count, pred_min);
-
- } else
- heart_battery_set_prediction(PERIOD, goal, 0, 0, 0);
-
- /* Log values of all predictions calculated */
- for (i = 0; i < MAX_STRATEGY; i++) {
- _I("%s %d %ld %ld %ld",
- (goal == DISCHARGING) ? "TimeToEmpty:" : "TimeToFull:",
- batt_stat.curr_capacity,
- batt_stat.prediction[goal].sec_per_cap[i],
- batt_stat.prediction[goal].cap_counter[i],
- batt_stat.prediction[goal].time_pred_min[i]);
- }
-}
-
-static int heart_battery_add_capacity(int capacity)
-{
- char info[BATTERY_DATA_MAX];
- int ret, idx, status;
- long time_diff_capacity_lvl[MAX_CHARGER_STATE];
- int diff_capacity_lvl;
- long total_time, total_count, sec_per_cap;
- time_t timestamp = time(NULL);
- time_t curr_wall_time = logging_get_time(CLOCK_BOOTTIME);
-
- status = batt_stat.curr_charger_status;
- /* calculate diff */
- time_diff_capacity_lvl[status] = curr_wall_time - batt_stat.last_event_wall_time;
-
- if (time_diff_capacity_lvl[status] < 0) {
- batt_stat.last_event_wall_time = curr_wall_time;
- return 0;
- }
-
- time_diff_capacity_lvl[!status] = 0;
-
- if (!batt_stat.curr_capacity)
- diff_capacity_lvl = 1;
- else
- diff_capacity_lvl = abs(batt_stat.curr_capacity - capacity);
-
- _I("%d -> %d %ld %ld", batt_stat.curr_capacity, capacity,
- timestamp, time_diff_capacity_lvl[status]);
-
- /* update battery current status */
- batt_stat.last_event_wall_time = curr_wall_time;
- batt_stat.curr_capacity = capacity;
-
- /* Full Charging status */
- if (status == CHARGING && !REMAIN_CAPACITY(capacity) && !diff_capacity_lvl)
- return 0;
-
- /* update run usage */
- batt_stat.curr_run_time_sec[status] += time_diff_capacity_lvl[status];
- batt_stat.curr_cap_counter[status] += diff_capacity_lvl;
-
- /* update batt_lvl_usage usage */
- total_time = 0;
- total_count = 0;
-
- if (status == CHARGING)
- idx = heart_battery_get_level_usage_index(REMAIN_CAPACITY(capacity));
- else
- idx = heart_battery_get_level_usage_index(capacity);
-
- total_time = heart_battery_get_usage_level_total_time(idx, status) + time_diff_capacity_lvl[status];
- if (total_time)
- total_count = heart_battery_get_usage_level_count(idx, status) + diff_capacity_lvl;
-
- if (total_count) {
- sec_per_cap = total_time / total_count;
- if (sec_per_cap == 0)
- sec_per_cap = default_sec_per_cap[status][DEFAULT_AVG];
- else if (sec_per_cap < default_sec_per_cap[status][DEFAULT_MIN])
- sec_per_cap = default_sec_per_cap[status][DEFAULT_MIN];
- else if (sec_per_cap > default_sec_per_cap[status][DEFAULT_MAX])
- sec_per_cap = default_sec_per_cap[status][DEFAULT_MAX];
- /*
- * If counts reached MAXIMUM number,
- * counts is divided by 2 to reduce previous data's effect to equation
- */
- if (total_count >= BATTERY_HISTORY_COUNT_MAX)
- total_count = total_count >> 1;
-
- heart_battery_set_usage_level(idx, status, sec_per_cap, total_count);
- heart_battery_set_usage_level_stime(idx, timestamp);
- }
-
- /* update day usage */
- total_time = 0;
- total_count = 0;
-
- idx = heart_battery_get_week_day_usage_index(timestamp);
- total_time = heart_battery_get_usage_week_total_time(idx, status) + time_diff_capacity_lvl[status];
- if (total_time)
- total_count = heart_battery_get_usage_week_count(idx, status) + diff_capacity_lvl;
-
- if (total_count) {
- sec_per_cap = total_time / total_count;
- if (sec_per_cap == 0)
- sec_per_cap = default_sec_per_cap[status][DEFAULT_AVG];
- else if (sec_per_cap < default_sec_per_cap[status][DEFAULT_MIN])
- sec_per_cap = default_sec_per_cap[status][DEFAULT_MIN];
- else if (sec_per_cap > default_sec_per_cap[status][DEFAULT_MAX])
- sec_per_cap = default_sec_per_cap[status][DEFAULT_MAX];
- heart_battery_set_usage_week(idx, status, sec_per_cap, total_count);
- heart_battery_set_usage_week_stime(idx, CALCULATE_DAY_BASE_TIME(timestamp));
- }
-
- heart_battery_calculate_prediction(batt_stat.curr_charger_status);
-
- /* db backup */
- snprintf(info, sizeof(info), "%d %d %ld %ld %d %d ",
- capacity, diff_capacity_lvl,
- time_diff_capacity_lvl[DISCHARGING], time_diff_capacity_lvl[CHARGING],
- batt_stat.curr_charger_status, batt_stat.reset_mark);
- ret = logging_write(PID_FOR_ROOT, BATTERY_NAME, TIZEN_SYSTEM_BATTERY_APPID,
- TIZEN_SYSTEM_APPID, timestamp, info);
- if (ret != RESOURCED_ERROR_NONE)
- return ret;
-
- /* insert capacity history list */
- heart_battery_insert_capacity(&capacity_history_list, capacity, diff_capacity_lvl,
- timestamp, time_diff_capacity_lvl[DISCHARGING],
- time_diff_capacity_lvl[CHARGING], batt_stat.curr_charger_status,
- batt_stat.reset_mark, true);
-
- _D("battery_heart_capacity_write %d diff_capacity %d, used time %ld, charging time %ld, charger status %d, reset_mark %d",
- capacity, diff_capacity_lvl,
- time_diff_capacity_lvl[DISCHARGING], time_diff_capacity_lvl[CHARGING],
- batt_stat.curr_charger_status, batt_stat.reset_mark);
-
- resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
- return RESOURCED_ERROR_NONE;
-}
-
-static void rul_display_state_changed_cb(device_callback_e type, void *value, void *user_data)
-{
- int display_state = (int) ((intptr_t) value), charger_status;
- /* 0 : on, 1 : dim, 2: off */
-
- /*
- * If charger_status==CHARGING and raw capacity calculation ongoing,
- * then, handle display_on time for RUL
- */
-
- charger_status = heart_battery_get_charger_status();
- if ((charger_status == CHARGING) && (rul.charging_start_time != 0)) {
- if (type != DEVICE_CALLBACK_DISPLAY_STATE)
- return;
-
- if (display_state == DISPLAY_STATE_NORMAL) {
- _I("DISPLAY: NORMAL/DIM");
- rul.lcd_data.state = DISPLAY_STATE_NORMAL;
- if (rul.lcd_data.on_start_time == 0) {
- rul.lcd_data.on_start_time = logging_get_time(CLOCK_BOOTTIME);
- }
- } else if (display_state == DISPLAY_STATE_SCREEN_OFF) {
- _I("DISPLAY: OFF");
- rul.lcd_data.state = DISPLAY_STATE_SCREEN_OFF;
- if (rul.lcd_data.on_start_time > 0) {
- rul.lcd_data.on_stop_time = logging_get_time(CLOCK_BOOTTIME);
- rul.lcd_data.on_time += rul.lcd_data.on_stop_time - rul.lcd_data.on_start_time;
- rul.lcd_data.on_start_time = 0;
- rul.lcd_data.on_stop_time = 0;
- }
- }
- }
-}
-
-static void rul_write_data_to_file(void)
-{
- int len = 0;
- char buff[RUL_DATA_SIZE] = {0};
- _cleanup_fclose_ FILE *fp = NULL, *fp1 = NULL;
- float fullcapnom = 0, fullcapnom_mAh = 0;
-
- /* Update count of Charging cycles*/
- rul.charging_cycles += 1;
-
- /* Calculate normalized capacity, i.e., extrapolate for 0% to 100% */
- fullcapnom = rul.raw_capacity / ((rul.soc_stop/100.0f) - (rul.soc_start/100.0f));
- fullcapnom_mAh = fullcapnom / 3.6f;
- _I("rul : raw_capacity = %.4f As, fullcapnom = %.4f As = %.4f mAh", rul.raw_capacity, fullcapnom, fullcapnom_mAh);
-
- /* Update RUL data file */
- fp = fopen(RUL_DATA_FILE, "a");
- if (fp == NULL) {
- _E("Could not open file - RUL_DATA_FILE");
- return;
- }
-
- len = snprintf(buff, RUL_DATA_SIZE, "%d %.4f\n", rul.charging_cycles, fullcapnom_mAh);
-
- if (len < RUL_DATA_SIZE)
- fputs(buff, fp);
-
- /* Write Charging cycles count to file */
- fp1 = fopen(RUL_CHARGING_CYCLES_FILE, "w");
- if (fp1 == NULL) {
- _E("Could not open file for write - RUL_CHARGING_CYCLES_FILE");
- return;
- }
- fprintf(fp1, "%d", rul.charging_cycles);
-
-}
-
-static void rul_charging_cycle_end_work(void)
-{
- int capacity;
- long total_charging_time;
- bool lcd_on_time_check;
- float lcd_on_ratio = 1.0f;
-
- capacity = heart_battery_get_capacity();
-
- rul.soc_stop = capacity;
- rul.charging_stop_time = logging_get_time(CLOCK_BOOTTIME);
-
- /* If LCD was on before disconnecting charger, update display_on time */
- if (rul.lcd_data.on_start_time != 0) {
- rul.lcd_data.on_stop_time = logging_get_time(CLOCK_BOOTTIME);
- rul.lcd_data.on_time += rul.lcd_data.on_stop_time - rul.lcd_data.on_start_time;
- }
-
- /* Max LCD ON Time ratio criteria met ? */
- total_charging_time = rul.charging_stop_time - rul.charging_start_time;
- if (total_charging_time != 0)
- lcd_on_ratio = (rul.lcd_data.on_time / (total_charging_time * 1.0f));
- lcd_on_time_check = lcd_on_ratio <= RUL_DISPLAY_ON_CUTOFF_RATIO;
-
- /* write data to file if condititons met*/
- if ((rul.charging_start_time != 0) && (lcd_on_time_check == true) &&
- (rul.soc_stop - rul.soc_start >= RUL_MIN_CAPACITY_DIFF))
- rul_write_data_to_file();
-
- /* init for next charging cycle */
- rul.soc_start = 0;
- rul.soc_stop = 0;
- rul.charging_start_time = 0;
- rul.charging_stop_time = 0;
- rul.lcd_data.on_start_time = 0;
- rul.lcd_data.on_stop_time = 0;
- rul.lcd_data.on_time = 0;
-}
-
-static void rul_calculate_raw_capacity(void)
-{
- /*
- * This function updates Raw Capacity every 1% SoC change.
- *
- * Upon first time 1% SoC change, initialize rul_info variables.
- *
- * Subsequently, Update Raw Capacity using time interval and
- * current_now sys node values.
- *
- * If capacity = 100%, dump collected data
- */
-
- long rul_curr_time, rul_time_interval;
- static long prev_charging_time;
- int fg_curr_inst, capacity, ret;
- float fg_curr_inst_f;
- static float prev_fg_curr_inst_f = 0.0f;
-
- capacity = heart_battery_get_capacity();
-
- if (rul.charging_start_time == 0) {
- rul.charging_start_time = logging_get_time(CLOCK_BOOTTIME);
- rul.soc_start = capacity;
- rul.raw_capacity = 0.0f;
- prev_charging_time = rul.charging_start_time;
- prev_fg_curr_inst_f = 0.0f;
- rul.lcd_data.on_start_time = 0;
- rul.lcd_data.on_stop_time = 0;
- rul.lcd_data.on_time = 0;
-
- /* Get display status at time of initiating RUL calculations */
- ret = device_display_get_state(&rul.lcd_data.state);
- if (ret != DEVICE_ERROR_NONE) {
- _E("Failed to get device display state with err = %d", ret);
- return;
- }
- if ((rul.lcd_data.state == DISPLAY_STATE_NORMAL) || (rul.lcd_data.state == DISPLAY_STATE_SCREEN_DIM))
- rul.lcd_data.on_start_time = logging_get_time(CLOCK_BOOTTIME);
- } else {
- rul_curr_time = logging_get_time(CLOCK_BOOTTIME);
- rul_time_interval = rul_curr_time - prev_charging_time;
- prev_charging_time = rul_curr_time;
-
- ret = fread_int("/sys/class/power_supply/battery/current_now", &fg_curr_inst);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("This device doesn't support FG CURRENT_NOW information. Disable LOGIC_RUL");
- return;
- }
-
- fg_curr_inst_f = fg_curr_inst / 1000.0f;
- rul.raw_capacity += ((fg_curr_inst_f + prev_fg_curr_inst_f) / 2.0f)*rul_time_interval;
- prev_fg_curr_inst_f = fg_curr_inst_f;
- }
-
- if (capacity == 100) {
- rul_charging_cycle_end_work();
- }
-}
-
-/* ============================ DBUS -> DEVICED on demand ==================== */
-
-static int heart_battery_direct_get_capacity(void)
-{
- int capacity;
-
- capacity = d_bus_call_method_sync_gvariant(DEVICED_BUS_NAME, DEVICED_PATH_BATTERY,
- DEVICED_INTERFACE_BATTERY,
- GET_BATTERY_CAPACITY,
- NULL);
- if (capacity < 0) {
- _E("Failed to sync DBUS message.");
- return RESOURCED_ERROR_FAIL;
- }
-
- return capacity;
-}
-
-static enum charger_status_type heart_battery_direct_get_charger_status(void)
-{
- int status;
-
- status = d_bus_call_method_sync_gvariant(DEVICED_BUS_NAME, DEVICED_PATH_BATTERY,
- DEVICED_INTERFACE_BATTERY,
- GET_CHARGER_STATUS,
- NULL);
- if (status < 0) {
- _E("Failed to sync DBUS message.");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (status > 0)
- return CHARGING;
- return DISCHARGING;
-}
-
-/* ========================= DBUS -> DEVICED on demand END ================= */
-
-/* ============================ DBUS -> DEVICED handler ====================== */
-static void heart_battery_capacity_status(GVariant *params)
-{
- /*
- * This handler is called when battery capacity value change in 1%
- *
- * The message have current percent value of capacity
- *
- * (This requires deviced with commit at least:
- * "f1ae1d1f270e9 battery: add battery capacity dbus signal broadcast")
- */
-
- int capacity = -1;
- int bat_trigger = -1;
- int bat_ups_est = -1;
- int bat_normal_est = -1;
-
- do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &capacity);
- if (capacity < 0) {
- _E("Failed: dbus_message_get_args()");
- return;
- }
- heart_battery_add_capacity(capacity);
- heart_battery_update_used_time(logging_get_time(CLOCK_BOOTTIME),
- batt_stat.curr_charger_status);
-
- if (logic_v2) {
- /* get the device mode */
- if (vconf_get_int(VCONFKEY_HEART_BATTERY_DEVICE_MODE, &device_mode))
- _E("failed to get VCONFKEY_HEART_BATTERY_DEVICE_MODE\n");
-
- /* for every battery level change, calculate the battery estimation time using new logic*/
- heart_battery_cal_discharge_rem_time();
-
- if (batt_stat.curr_charger_status == CHARGING &&
- batt_stat.last_capacity_chg < batt_stat.curr_capacity) {
- heart_battery_cal_charging_rem_time();
- first_level_change = FALSE;
- } else {
- /*
- * if battery is very very low then update the pivot before power off
- */
- if (batt_stat.curr_capacity == LOW_CAPACITY)
- heart_battery_collect_pivot_info();
- }
- }
- if (logic_rul) {
- /* Update prev_soc, curr_soc */
- rul.prev_soc = rul.curr_soc;
- rul.curr_soc = capacity;
-
- /*
- * If charger_status==CHARGING and SOC_INCREASING, start/continue raw capacity calculation.
- * Else, if raw capacity calculation was ongoing, then dump collected data.
- */
- if ((batt_stat.curr_charger_status == CHARGING) && (rul.curr_soc >= rul.prev_soc))
- rul_calculate_raw_capacity();
- else if (rul.charging_start_time != 0)
- rul_charging_cycle_end_work();
- }
-
- /* Get the UPSM trigger value and remaining estimate */
- if (vconf_get_int(VCONFKEY_SETAPPL_MANAGE_BATTERY_TRIGGER_TIME, &bat_trigger)) {
- _E("failed to get VCONFKEY_SETAPPL_MANAGE_BATTERY_TRIGGER_TIME\n");
- return;
- }
- if (bat_trigger > 0) { /* Battery planner is enabled*/
- bat_ups_est = get_battery_remaining_time(ULTRA_SAVING_MODE, DISCHARGING);
- bat_normal_est = get_battery_remaining_time(POWER_NORMAL_MODE, DISCHARGING);
- _I(" trigger time: %d, ups est:%d, normal est:%d", bat_trigger, bat_ups_est, bat_normal_est);
- if (bat_ups_est > 0 && bat_trigger >= bat_ups_est) {
- char *args[4] = { "_SYSPOPUP_CONTENT_", "manage_battery",
- "_BAT_POPUP_TYPE_", "enable_mbp"};
-
- d_bus_call_method_sync(SYSTEM_POPUP_BUS_NAME,
- SYSTEM_POPUP_PATH_SYSTEM, SYSTEM_POPUP_IFACE_SYSTEM,
- "PopupLaunch", "ssss", args);
- }
- if (bat_normal_est > 0 && bat_normal_est >= bat_trigger) {
- char *args[4] = { "_SYSPOPUP_CONTENT_", "manage_battery",\
- "_BAT_POPUP_TYPE_", "disable_mbp"};
-
- d_bus_call_method_sync(SYSTEM_POPUP_BUS_NAME,
- SYSTEM_POPUP_PATH_SYSTEM, SYSTEM_POPUP_IFACE_SYSTEM,
- "PopupLaunch", "ssss", args);
- }
- }
-}
-
-static void heart_battery_charger_status(GVariant *params)
-{
- /*
- * This handler is called when USB cable with charging capabilities
- * is connected or disconnected from the device.
- *
- * The message have current status of charger connection.
- * STATUSES:
- * 0 - charger was disconnected
- * 1 - charger was connected
- */
- int charger_status = -1, cap_history_size;
-
- do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &charger_status);
- if (charger_status < 0) {
- _E("Failed: dbus_message_get_args()");
- return;
- }
-
- /* Update the statistics with capacity when charger state was changed */
- heart_battery_add_capacity(batt_stat.curr_capacity);
-
- cap_history_size = heart_battery_get_capacity_history_size();
-
- if (charger_status == DISCHARGING && batt_stat.curr_capacity >= 90) {
- /*
- * If battery is charged over 90 and charger was disconnected.
- * So most probably the phone was "charged".
- * Let's reset the statistics.
- */
- resourced_notify(RESOURCED_NOTIFIER_DATA_RESET, NULL);
- } else if (charger_status == DISCHARGING && cap_history_size >= BATTERY_CAPACITY_MAX) {
- /*
- * Charger is not connected and the battery history is over limit.
- * Let's reset the statistics.
- */
- resourced_notify(RESOURCED_NOTIFIER_DATA_RESET, NULL);
- }
- /* Update current charger connection status */
- batt_stat.curr_charger_status = charger_status;
- heart_battery_update_used_time(logging_get_time(CLOCK_BOOTTIME),
- batt_stat.curr_charger_status);
- heart_battery_calculate_prediction(batt_stat.curr_charger_status);
-
- if (logic_v2) {
- /*
- * If charger removed/inserted then update the battery estimation time
- */
- heart_battery_cal_discharge_rem_time();
-
- if (charger_status == CHARGING) {
- /*
- * if diff is more than 10% then flush the previous charge data
- */
- if ((batt_stat.last_capacity_chg > 0) &&
- (batt_stat.last_capacity_chg - batt_stat.curr_capacity > BATT_CHG_FLUSH_DATA))
- heart_battery_flush_charge_data();
-
- /* collect the data for pivot update */
- heart_battery_collect_pivot_info();
-
- batt_stat.last_wall_time_chg = 0;
- first_level_change = TRUE;
- heart_battery_print_prev_charge_data();
- heart_battery_cal_charging_rem_time();
- } else {
- heart_battery_collect_discharge_data();
- }
- }
- if (logic_rul) {
- /*
- * If charger disconnected and raw capacity calculation was ongoing,
- * then dump collected data.
- */
- if ((charger_status == DISCHARGING) && (rul.charging_start_time != 0))
- rul_charging_cycle_end_work();
- }
-}
-
-/* ========================= DBUS -> DEVICED handler END ==================== */
-
-int heart_battery_get_capacity_history_latest(GArray *arrays, int charge, int max_size)
-{
- int ret, size, count;
- struct heart_battery_capacity *lbc, *lbci;
- GSList *iter, *rlist;
-
- if (!capacity_history_list) {
- _E("empty capacity history list");
- return RESOURCED_ERROR_FAIL;
- }
- size = g_slist_length(capacity_history_list);
- if (!size) {
- _I("capacity history is empty");
- return RESOURCED_ERROR_NONE;
- }
- ret = pthread_mutex_lock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- count = 0;
-
- rlist = g_slist_copy(capacity_history_list);
-
- rlist = g_slist_reverse(rlist);
-
- gslist_for_each_item(iter, rlist) {
- lbc = (struct heart_battery_capacity *)iter->data;
- if (!lbc)
- break;
- if (charge < MAX_CHARGER_STATE && charge != lbc->charger_status)
- continue;
- count++;
- if (max_size < count)
- break;
- lbci = malloc(sizeof(struct heart_battery_capacity));
- if (!lbci) {
- _E("malloc failed");
- goto unlock_exit;
- }
- lbci->capacity = lbc->capacity;
- lbci->diff_capacity = lbc->diff_capacity;
- if (!lbc->diff_capacity)
- count--;
- lbci->used_time = lbc->used_time;
- lbci->charging_time = lbc->charging_time;
- lbci->charger_status = lbc->charger_status;
- g_array_prepend_val(arrays, lbci);
- }
-unlock_exit:
- g_slist_free(rlist);
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_NONE;
-}
-
-int heart_battery_get_capacity_history(GArray *arrays, enum heart_data_period period)
-{
- int ret, index, size;
- struct heart_battery_capacity *lbc, *lbci;
- GSList *iter;
- time_t curr = time(NULL);
-
- switch (period) {
- case DATA_LATEST:
- index = 0;
- break;
- case DATA_3HOUR:
- index = 3;
- break;
- case DATA_6HOUR:
- index = 6;
- break;
- case DATA_12HOUR:
- index = 12;
- break;
- case DATA_1DAY:
- index = 24;
- break;
- default:
- _E("Wrong message arguments! %d", period);
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!capacity_history_list) {
- _E("empty capacity history list");
- return RESOURCED_ERROR_FAIL;
- }
- size = g_slist_length(capacity_history_list);
- if (!size) {
- _I("capacity history is empty");
- return RESOURCED_ERROR_NONE;
- }
- ret = pthread_mutex_lock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- gslist_for_each_item(iter, capacity_history_list) {
- lbc = (struct heart_battery_capacity *)iter->data;
- if (!lbc)
- break;
- if (index && (lbc->timestamp < curr - (index * 3600)))
- continue;
- lbci = malloc(sizeof(struct heart_battery_capacity));
- if (!lbci) {
- _E("malloc failed");
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- lbci->capacity = lbc->capacity;
- lbci->diff_capacity = lbc->diff_capacity;
- lbci->used_time = lbc->used_time;
- lbci->charging_time = lbc->charging_time;
- lbci->charger_status = lbc->charger_status;
- g_array_append_val(arrays, lbci);
- }
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_NONE;
-}
-
-/* ============================ DBUS interface ====================== */
-
-static void dbus_get_battery_capacity_history_latest(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int i, size, charge, max_size;
- GArray *arrays = NULL;
- GVariantBuilder builder, *sub_builder;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(ii)", &charge, &max_size);
- if (charge < 0 || max_size < 0) {
- _E("Wrong message arguments!");
- goto failure;
- }
-
- size = g_slist_length(capacity_history_list);
- if (!size) {
- _I("capacity history is empty");
- goto failure;
- }
- arrays = g_array_new(FALSE, FALSE, sizeof(struct heart_battery_capacity *));
- if (!arrays) {
- _E("Failed to alloc array");
- goto failure;
- }
- if (heart_battery_get_capacity_history_latest(arrays, charge, max_size) != RESOURCED_ERROR_NONE) {
- _E("Failed to get capacity history latest");
- D_BUS_REPLY_ERR(invocation);
- return;
- }
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
- sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(iii)"));
- if (!arrays->len) {
- _E("No battery capacity history data");
- goto exit;
- }
-
- for (i = 0; i < arrays->len; i++) {
- struct heart_battery_capacity *lbc;
- lbc = g_array_index(arrays, struct heart_battery_capacity *, i);
- if (!lbc)
- break;
-
- g_variant_builder_add(sub_builder, "(iii)", lbc->capacity,
- lbc->used_time, lbc->charging_time);
- free(lbc);
- }
-exit:
- g_variant_builder_add_value(&builder, g_variant_new("a(iii)", sub_builder));
- g_variant_builder_unref(sub_builder);
- g_array_free(arrays, TRUE);
- g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_get_battery_capacity_history(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret, size, period = -1, index;
- struct heart_battery_capacity *lbc;
- GSList *iter;
- time_t curr = time(NULL);
- GVariantBuilder builder, *sub_builder;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &period);
- if (period < 0) {
- _E("Wrong message arguments!");
- goto failure;
- }
- switch (period) {
- case DATA_LATEST:
- index = 0;
- break;
- case DATA_3HOUR:
- index = 3;
- break;
- case DATA_6HOUR:
- index = 6;
- break;
- case DATA_12HOUR:
- index = 12;
- break;
- case DATA_1DAY:
- index = 24;
- break;
- default:
- _E("Wrong message arguments! %d", period);
- goto failure;
- }
- size = g_slist_length(capacity_history_list);
- if (!size) {
- _I("capacity history is empty");
- goto failure;
- }
- ret = pthread_mutex_lock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- goto failure;
- }
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
- sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(su)"));
-
- gslist_for_each_item(iter, capacity_history_list) {
- lbc = (struct heart_battery_capacity *)iter->data;
- if (!lbc)
- break;
- if (index && (lbc->timestamp < curr - (index * 3600)))
- continue;
-
- g_variant_builder_add(sub_builder, "(iii)", lbc->capacity,
- lbc->used_time, lbc->charging_time);
- }
-
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- g_variant_builder_unref(sub_builder);
- goto failure;
- }
-
- g_variant_builder_add_value(&builder, g_variant_new("a(iii)", sub_builder));
- g_variant_builder_unref(sub_builder);
-
- g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_get_battery_used_time(GDBusMethodInvocation *invocation, GVariant *params)
-{
- heart_battery_update_used_time(logging_get_time(CLOCK_BOOTTIME),
- batt_stat.curr_charger_status);
-
- g_dbus_method_invocation_return_value(invocation,
- g_variant_new("(i)", batt_used.used_time_sec));
-}
-
-static int get_battery_remaining_time(int mode, enum charger_status_type status)
-{
- int i, ret, count;
- long sum, time, cumul_average, trend_average;
- double result;
-
- ret = count = 0;
- sum = time = 0;
- cumul_average = trend_average = 0;
- /* get prediction time of cumulative value */
- for (i = 0; i <= WEEK; i++) {
- time = heart_battery_get_prediction_time(i, status);
- if (time) {
- sum += time;
- count++;
- }
- }
- if (count)
- cumul_average = sum / count;
-
- count = 0;
- sum = 0;
- /* get prediction time of trend value */
- for (i = COUNT; i < MAX_STRATEGY; i++) {
- time = heart_battery_get_prediction_time(i, status);
- if (time) {
- sum += time;
- count++;
- }
- }
- if (count)
- trend_average = sum / count;
-
- /* failed to get prediction so return learning mode */
- if (!cumul_average && !trend_average) {
- if (batt_stat.curr_capacity != 100 && batt_stat.curr_capacity != 0)
- ret = BATTERY_USAGE_LEARNING;
- } else if (cumul_average && !trend_average) {
- /* failed to get prediction of trend average */
- ret = cumul_average;
- } else if (!cumul_average && trend_average) {
- /* failed to get prediction of cumulative average */
- ret = trend_average;
- } else
- ret = ((cumul_average * CUMUL_WEIGHT) + (trend_average * TREND_WEIGHT));
-
- if (status == CHARGING) {
- if (logic_v2) /* new logic */
- return batt_stat.remaining_time_chg;
- return ret; /* old logic */
- }
-
- if (logic_v2) { /* new logic */
- switch (mode) {
- case POWER_SAVING_MODE:
- /* Fall through */
- case ULTRA_SAVING_MODE:
- ret = get_battery_remaining_time_ups();
- break;
- case POWER_NORMAL_MODE:
- ret = get_battery_remaining_time_new();
- break;
- default:
- break;
- }
- return ret;
- }
-
- if (ret <= 0)
- return BATTERY_USAGE_LEARNING;
-
- /* old logic */
- switch (mode) {
- case ULTRA_SAVING_MODE:
- /* Fall through */
- case POWER_SAVING_MODE:
- result = (double)ret * default_mode_factor[mode];
- return (int)result;
- case POWER_NORMAL_MODE:
- /* Fall through */
- default:
- return ret;
- }
-}
-
-static void dbus_get_battery_remaining_time(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret, mode = -1;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &mode);
- if (mode < 0) {
- _E("Wrong message arguments!");
- goto failure;
- }
-
- if (!battery_learning_mode)
- battery_learning_mode = heart_battery_get_learning_mode();
-
- if (!battery_learning_mode) {
- _E("data is not enough to calculate prediction");
- ret = BATTERY_USAGE_LEARNING;
- } else {
- if (batt_stat.curr_capacity <= 0) {
- _I("Last capacity read may not be proper so read again");
- batt_stat.curr_capacity = heart_battery_direct_get_capacity();
- if (batt_stat.curr_capacity <= 0) {
- /*
- * still not proper ? return learning mode
- */
- ret = BATTERY_USAGE_LEARNING;
- } else {
- heart_battery_cal_discharge_rem_time();
- ret = get_battery_remaining_time(mode, DISCHARGING);
- }
- } else {
- ret = get_battery_remaining_time(mode, DISCHARGING);
- }
- }
-
- _I("Remaining_time %d (mode: %d)", ret, mode);
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_get_battery_charging_time(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret = get_battery_remaining_time(POWER_NORMAL_MODE, CHARGING);
- _I("Remaining_charging_time %d", ret);
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
-}
-
-static void dbus_get_battery_discharge_rate_level(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret = batt_stat.discharge_rate_level;
- _I("discharge_rate_level %d", ret);
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
-}
-
-static void dbus_battery_save_to_file(GDBusMethodInvocation *invocation, GVariant *params)
-{
- heart_battery_status_save_to_db();
-
- int ret = heart_battery_capacity_save_to_file(HEART_BATTERY_CAPACITY_DATA_FILE);
- if (ret) {
- _E("save to file failed");
- D_BUS_REPLY_ERR(invocation)
- return;
- }
-
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
-}
-
-static const char dbus_methods_xml[] =
-" <method name='GetBatteryCapacityHistory'>"
-" <arg type='i' name='Period' direction='in'/>"
-" <arg type='a(iii)' name='CapacityHistory' direction='out'/>"
-" </method>"
-" <method name='GetBatteryCapacityHistoryLatest'>"
-" <arg type='i' name='Charge' direction='in'/>"
-" <arg type='i' name='MaxSize' direction='in'/>"
-" <arg type='a(iii)' name='CapacityHistory' direction='out'/>"
-" </method>"
-" <method name='GetBatteryUsedTime'>"
-" <arg type='i' name='UsedTime' direction='out'/>"
-" </method>"
-" <method name='GetBatteryRemainingTime'>"
-" <arg type='i' name='Mode' direction='in'/>"
-" <arg type='i' name='RemainingTime' direction='out'/>"
-" </method>"
-" <method name='GetBatteryChargingTime'>"
-" <arg type='i' name='ChargingTime' direction='out'/>"
-" </method>"
-" <method name='GetBatteryDischargeRateLevel'>"
-" <arg type='i' name='DischargeRateLevel' direction='out'/>"
-" </method>"
-" <method name='SaveBatteryData'>"
-" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
-" </method>";
-
-static struct d_bus_method dbus_methods[] = {
- { "GetBatteryCapacityHistory", dbus_get_battery_capacity_history },
- { "GetBatteryCapacityHistoryLatest", dbus_get_battery_capacity_history_latest },
- { "GetBatteryUsedTime", dbus_get_battery_used_time },
- { "GetBatteryRemainingTime", dbus_get_battery_remaining_time },
- { "GetBatteryChargingTime", dbus_get_battery_charging_time },
- { "GetBatteryDischargeRateLevel", dbus_get_battery_discharge_rate_level },
- { "SaveBatteryData", dbus_battery_save_to_file },
-};
-
-/* ========================= DBUS interface END ==================== */
-static void heart_battery_used_time_init(enum charger_status_type status)
-{
- batt_used.last_charger_status = status;
- batt_used.last_update_time = logging_get_time(CLOCK_BOOTTIME);
-}
-
-static void heart_battery_status_init(void)
-{
- int i, ret, status, capacity;
-
- batt_stat.curr_capacity = 0;
- batt_stat.curr_run_time_sec[DISCHARGING] = 0;
- batt_stat.curr_run_time_sec[CHARGING] = 0;
- batt_stat.curr_cap_counter[DISCHARGING] = 0;
- batt_stat.curr_cap_counter[CHARGING] = 0;
- batt_stat.curr_charger_status = 0;
- batt_stat.reset_mark = 0;
-
- for (i = 0; i < BATTERY_HISTORY_RESET_MAX; i++) {
- heart_battery_set_usage_reset_stime(i, 0);
- heart_battery_set_usage_reset(i, DISCHARGING, 0, 0);
- heart_battery_set_usage_reset(i, CHARGING, 0, 0);
- }
-
-
- for (i = 0; i < BATTERY_LEVEL_MAX; i++) {
- heart_battery_set_usage_level_stime(i, 0);
- heart_battery_set_usage_level(i, DISCHARGING, default_sec_per_cap[DISCHARGING][DEFAULT_AVG], 0);
- heart_battery_set_usage_level(i, CHARGING, default_sec_per_cap[CHARGING][DEFAULT_AVG], 0);
- }
-
- for (i = 0; i < BATTERY_HISTORY_DAY_MAX; i++) {
- heart_battery_set_usage_week_stime(i, 0);
- heart_battery_set_usage_week(i, DISCHARGING, 0, 0);
- heart_battery_set_usage_week(i, CHARGING, 0, 0);
- }
-
- for (i = 0; i < MAX_STRATEGY; i++) {
- heart_battery_set_prediction(i, DISCHARGING, 0, 0, 0);
- heart_battery_set_prediction(i, CHARGING, 0, 0, 0);
- }
-
- ret = heart_battery_status_read_from_db();
- if (ret < 0)
- _E("Failed to read battery status data");
-
- if (logic_v2) {
- for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
- batt_stat.last_wall_time[i] = 0;
- batt_stat.last_volt_intg[i] = 0.0;
- }
- for (i = 0; i < BATTERY_LEVEL_GAP; i++)
- batt_stat.last_wall_time_chg_diff[i] = 0;
-
- batt_stat.data_available = 0;
- batt_stat.last_capacity = 0;
- batt_stat.last_capacity_chg = 0;
- first_level_change = FALSE;
- batt_stat.curr_index = 0;
- batt_stat.remaining_time = 0;
- batt_stat.remaining_time_ups = 0;
- batt_stat.last_pwr_bchg = average_pwr;
- batt_stat.last_wall_time_chg = 0;
- batt_stat.index_chg = 0;
- batt_stat.remaining_time_chg = 0;
- batt_stat.last_clock_tick = logging_get_time(CLOCK_BOOTTIME);
- for (i = 0; i < INDEX_WINDOW_SIZE; i++)
- batt_stat.pvt.total_dischg_time[i] = 0;
- batt_stat.pvt.pvt_data_ind = 0;
- batt_stat.pvt.start_cap_dischg = 0;
- batt_stat.pvt.start_time_dischg = 0;
- batt_stat.pvt.last_clock_tick = 0;
-
- /* During the device boot-up, calculate energy for 100% battery and calcuate
- pivot(norma and UPS mode) for time remaining time estimation*/
- heart_battery_calculate_pivot();
- /*get all the previousely stored data from file to program variable*/
- heart_battery_read_data_from_file();
- /* get all the previosly stored pivot info */
- heart_battery_read_pivot_info_from_file();
- /* if enough pivot data present then update the pivot */
- heart_battery_update_pivot();
- /*
- * check whether was device power off for long time. If yes then adjust
- * our stored time values
- */
- heart_battery_power_off_time_adjustment();
- /*
- * register callback for any time change from user side.
- * If any time change happen then adjust whole data as per new time
- */
- vconf_notify_key_changed(VCONFKEY_SETAPPL_TIMEZONE_INT, time_change_notify_cb, NULL);
- vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, time_change_notify_cb, NULL);
- vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, time_change_notify_cb, NULL);
- }
-
- battery_learning_mode = heart_battery_get_learning_mode();
-
- ret = heart_battery_capacity_read_from_file(HEART_BATTERY_CAPACITY_DATA_FILE);
- if (ret < 0)
- _E("Failed to read battery capacity data");
-
- capacity = heart_battery_direct_get_capacity();
- status = heart_battery_direct_get_charger_status();
-
- /*
- * Consider power off charing mode
- * If new capacity is higher than old capacity and it is full, reset heart data
- */
- if (capacity > batt_stat.curr_capacity && status == DISCHARGING && capacity >= 90)
- heart_battery_reset(NULL);
- else
- heart_battery_used_time_init(batt_stat.curr_charger_status);
-
- if (capacity > 0)
- batt_stat.curr_capacity = capacity;
- if (status >= 0)
- batt_stat.curr_charger_status = status;
-
- heart_battery_calculate_prediction(batt_stat.curr_charger_status);
- batt_stat.last_event_wall_time = logging_get_time(CLOCK_BOOTTIME);
- batt_stat.discharge_rate_level = BATTERY_DISCHARGE_NONE;
-
- if (logic_v2) {
- heart_battery_cal_discharge_rem_time();
-
- if (batt_stat.curr_charger_status == CHARGING) {
- heart_battery_cal_charging_rem_time();
- first_level_change = TRUE;
- } else {
- heart_battery_collect_discharge_data();
- }
- }
-}
-
-static int low_battery_handler(void *data)
-{
- heart_battery_save_to_file(false);
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_battery_config(struct parse_result *result, void *user_data)
-{
- int val;
- int battery_capacity = 0;
-
- if (!result)
- return -EINVAL;
-
- if (!strncmp(result->section, HEART_BATTERY_CONF_SECTION, sizeof(HEART_BATTERY_CONF_SECTION) + 1)) {
- if (!strncmp(result->name, "POWER_NORMAL_MODE", sizeof("POWER_NORMAL_MODE") + 1)) {
- val = atoi(result->value);
- if (val > 0)
- default_mode_spc[POWER_NORMAL_MODE] = val;
- _D("POWER_NORMAL_MODE SPC: %d", val);
- } else if (!strncmp(result->name, "POWER_SAVING_MODE", sizeof("POWER_SAVING_MODE") + 1)) {
- val = atoi(result->value);
- if (val > 0)
- default_mode_spc[POWER_SAVING_MODE] = val;
- _D("POWER_SAVING_MODE SPC: %d", val);
- } else if (!strncmp(result->name, "ULTRA_SAVING_MODE", sizeof("ULTRA_SAVING_MODE") + 1)) {
- val = atoi(result->value);
- if (val > 0)
- default_mode_spc[ULTRA_SAVING_MODE] = val;
- _D("ULTRA_POWER_SAVING_MODE SPC: %d", val);
- }
- } else if (!strncmp(result->section, battery_header, sizeof(battery_header) + 1)) {
- if (!strncmp(result->name, "LOGIC_V2", sizeof("LOGIC_V2") + 1)) {
- logic_v2 = atoi(result->value);
- _I("logic_v2 : %d", logic_v2);
- } else if (!strncmp(result->name, "LOGIC_RUL", sizeof("LOGIC_RUL") + 1)) {
- logic_rul = atoi(result->value);
- _I("logic_rul : %d", logic_rul);
- } else if (!strncmp(result->name, "BATTERY_CAPACITY", sizeof("BATTERY_CAPACITY") + 1)) {
- battery_capacity = atoi(result->value);
- _I("total battery capacity: %d", battery_capacity);
-
- if(total_battery_capacity == 0 && !battery_capacity) {
- /* sys interface battery capacity path not found, read from conf file */
- total_battery_capacity = battery_capacity * 60; /* mAm */
- }
- } else if (!strncmp(result->name, "DISCHARGE_FAST", sizeof("DISCHARGE_FAST") + 1)) {
- discharge_fast = atoi(result->value);
- _I("discharge_fast: %d", discharge_fast);
- } else if (!strncmp(result->name, "DISCHARGE_SLOW", sizeof("DISCHARGE_SLOW") + 1)) {
- discharge_slow = atoi(result->value);
- _I("discharge_slow: %d", discharge_slow);
- } else if (!strncmp(result->name, "AVERAGE_PWR", sizeof("AVERAGE_PWR") + 1)) {
- average_pwr = atof(result->value);
- _I("average_power: %lf", average_pwr);
- } else if (!strncmp(result->name, "OCV_SOC_POLY_COEF", sizeof("OCV_SOC_POLY_COEF") + 1)) {
- char *token, *saveptr = NULL;
- int i;
- token = strtok_r(result->value, " ", &saveptr);
- if (token) {
- ocv_degree = atoi(token);
- if (ocv_degree <= 0) {
- _E("ocv_degree should be positive if you decide to use logic_v2");
- return -EINVAL;
- }
- intg = calloc(ocv_degree, sizeof(double));
- if (!intg) {
- _E("Out of memory");
- return -ENOMEM;
- }
- _I("Degree of OCV_SOC_POLY = %d", ocv_degree);
-
- for (i = 0; i < ocv_degree; i++) {
- token = strtok_r(NULL, " ", &saveptr);
- if (!token) {
- _E("There is no OCV_SOC_POLY_COEF_%d", i + 1);
- return -EINVAL;
- }
- intg[i] = atof(token);
- _I("OCV_SOC_POLY_COEF_%d = %.9g", i + 1, intg[i]);
- }
- }
- }
- } else if (!strncmp(result->section, "POWER_PROFILE", sizeof("POWER_PROFILE") + 1)) {
- if (!strncmp(result->name, "WIFI_ACTIVE", sizeof("WIFI_ACTIVE") + 1)) {
- power_profile.wifi_active = atof(result->value);
- _D("HEART WIFI_ACTIVE: %f", power_profile.wifi_active);
- } else if (!strncmp(result->name, "WIFI_ON", sizeof("WIFI_ON") + 1)) {
- power_profile.wifi_on = atof(result->value);
- _D("HEART WIFI_ON: %f", power_profile.wifi_on);
- }
- }
- return RESOURCED_ERROR_NONE;
-}
-
-static void heart_battery_mode_factor_init(void)
-{
- double val;
-
- val = default_mode_spc[POWER_SAVING_MODE]/default_mode_spc[POWER_NORMAL_MODE];
-
- if (1.0 < val)
- default_mode_factor[POWER_SAVING_MODE] = val;
- _I("POWER_SAVING_MODE factor: %f", val);
-
- val = default_mode_spc[ULTRA_SAVING_MODE]/default_mode_spc[POWER_NORMAL_MODE];
-
- if (1.0 < val)
- default_mode_factor[ULTRA_SAVING_MODE] = val;
- _I("ULTRA_POWER_SAVING_MODE factor: %f", val);
-}
-
-/*
- * This function will read total battery capacity from sys interface
- * example - 1500mAh or 2600mAh
- */
-static void heart_read_battery_total_capacity(void)
-{
- u_int32_t batt_capacity;
-
- /*
- * read the battery total capacity from sys interface path
- * "/sys/class/power_supply/battery/batt_capacity"
- * which is provided by kernel
- */
- if (fread_uint("/sys/class/power_supply/battery/batt_capacity",
- &batt_capacity) != RESOURCED_ERROR_NONE) {
- _D("This device doesn't support battery capacity information. Disable LOGIC_V2");
- return;
- }
-
- snprintf(battery_header, sizeof(battery_header), "BATTERY_%d",
- batt_capacity);
-
- /*
- * convert battery capacity from mAh to mAm
- */
- total_battery_capacity = batt_capacity * 60;
- _I("battery capacity = %d, battery header = %s",
- batt_capacity, battery_header);
-}
-
-/* Database related operations for heart-battery tables */
-
-static int heart_battery_stats_init_db(void)
-{
- sqlite3 *battery_stats_db;
- char *err_msg = NULL;
- char buf[HEART_BATTERY_STATS_MAX] = {0, };
- int ret;
-
- ret = sqlite3_open(BATTERY_STATS_DB_FILE_NAME, &battery_stats_db);
- if (ret != SQLITE_OK) {
- _E("Can't open database %s: %s", BATTERY_STATS_DB_FILE_NAME,
- sqlite3_errmsg(battery_stats_db));
- goto error_db_open;
- }
-
- snprintf(buf, HEART_BATTERY_STATS_MAX, "%s", QUERY_CREATE_BATTERY_STATS);
- ret = sqlite3_exec(battery_stats_db, buf, NULL, NULL, &err_msg);
- if (ret != SQLITE_OK) {
- _E("create failed: %s", err_msg);
- sqlite3_free(err_msg);
- goto error_db_open;
- }
- _I("Create db Success");
-
-error_db_open:
- sqlite3_close(battery_stats_db);
- return ret;
-}
-
-static int heart_battery_stats_db_open_transaction(sqlite3 *db)
-{
- char *err_msg = NULL;
-
- if (sqlite3_exec(db, "PRAGMA journal_mode = PERSIST", NULL, NULL, &err_msg) != SQLITE_OK) {
- _E("sqlite3_exec(\"PRAGMA journal_mode = PERSIST\") failed! -> %s", err_msg);
- sqlite3_free(err_msg);
- return RESOURCED_ERROR_DB_FAILED;
- }
-
- if (sqlite3_exec(db, "BEGIN EXCLUSIVE", NULL, NULL, &err_msg) != SQLITE_OK) {
- _E("sqlite3_exec(\"BEGIN EXCLUSIVE\") failed! -> %s", err_msg);
- sqlite3_free(err_msg);
- return RESOURCED_ERROR_DB_FAILED;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-int heart_battery_stats_execute_insert_db(char buf[])
-{
- sqlite3 *battery_stats_db;
- char *err_msg = NULL;
- int ret;
-
- if (sqlite3_open(BATTERY_STATS_DB_FILE_NAME, &battery_stats_db) != SQLITE_OK) {
- _E("Can't open database %s: %s", BATTERY_STATS_DB_FILE_NAME,
- sqlite3_errmsg(battery_stats_db));
- return RESOURCED_ERROR_DB_FAILED;
- }
- ret = heart_battery_stats_db_open_transaction(battery_stats_db);
- if (ret != RESOURCED_ERROR_NONE)
- goto error_close;
-
- if (sqlite3_exec(battery_stats_db, buf, NULL, NULL, &err_msg) != SQLITE_OK) {
- _E("sqlite3_exec(\"%s\") failed! -> %s", buf, err_msg);
- sqlite3_free(err_msg);
- goto error_db;
- }
-
- if (sqlite3_exec(battery_stats_db, "COMMIT", NULL, NULL, NULL) != SQLITE_OK) {
- _E("sqlite3_exec(\"COMMIT\") failed!");
- goto error_db;
- }
- _I("QUERY: %s SUCCESS", buf);
-
- sqlite3_close(battery_stats_db);
- return RESOURCED_ERROR_NONE;
-
-error_db:
- if (sqlite3_exec(battery_stats_db, "ROLLBACK", NULL, NULL, NULL) != SQLITE_OK)
- _E("sqlite3_exec(\"ROLLBACK\") failed!");
- _I("QUERY: %s FAILED", buf);
-error_close:
- sqlite3_close(battery_stats_db);
- return RESOURCED_ERROR_DB_FAILED;
-}
-
-long heart_battery_stats_execute_select_total_db(char buf[])
-{
- sqlite3 *battery_stats_db;
- sqlite3_stmt *stmt;
- long totaltime = 0;
- int ret;
-
- if (sqlite3_open(BATTERY_STATS_DB_FILE_NAME, &battery_stats_db) != SQLITE_OK) {
- _E("Can't open database %s: %s", BATTERY_STATS_DB_FILE_NAME,
- sqlite3_errmsg(battery_stats_db));
- return 0;
- }
-
- ret = sqlite3_prepare_v2(battery_stats_db, buf, -1, &stmt, NULL);
- if (ret != SQLITE_OK) {
- _E("Failed to prepare query %s", sqlite3_errmsg(battery_stats_db));
- goto error_db;
- }
-
- ret = sqlite3_step(stmt);
- switch (ret) {
- case SQLITE_ROW:
- _I("QUERY: %s SUCCESS", buf);
- totaltime = (long)sqlite3_column_int(stmt, 0);
- _D("totaltime: (%ld)", totaltime);
- break;
- case SQLITE_DONE:
- _D("SQLITE_DONE");
- break;
- case SQLITE_ERROR:
- /* FALLTHROUGH */
- _E("sqlite3_step failed %s", sqlite3_errmsg(battery_stats_db));
- default:
- _E("RESOURCED_ERROR_DB_FAILED");
- break;
- }
- sqlite3_finalize(stmt);
-error_db:
- sqlite3_close(battery_stats_db);
- return totaltime;
-}
-
-static void rul_data_init(void)
-{
- _cleanup_fclose_ FILE *fp = NULL;
- int ret, check;
-
- rul.charging_start_time = 0;
- rul.charging_stop_time = 0;
- rul.raw_capacity = 0;
- rul.soc_start = 0;
- rul.soc_stop = 0;
- rul.curr_soc = heart_battery_direct_get_capacity();
- rul.prev_soc = rul.curr_soc;
-
- /* Init LCD related data */
- rul.lcd_data.on_start_time = 0;
- rul.lcd_data.on_stop_time = 0;
- rul.lcd_data.on_time = 0;
- ret = device_display_get_state(&rul.lcd_data.state);
- if (ret != DEVICE_ERROR_NONE) {
- _E("Failed to get device display state with err = %d", ret);
- return;
- }
-
- /* Register callback for LCD state change */
- check = device_add_callback(DEVICE_CALLBACK_DISPLAY_STATE, rul_display_state_changed_cb, NULL);
- if (check != DEVICE_ERROR_NONE) {
- _E("Failed to add calback with err = %d", check);
- //TODO: consider "rul.charging_cycles = 0;"
- return;
- }
-
- /* Read Charging cycles count from file */
- fp = fopen(RUL_CHARGING_CYCLES_FILE, "r");
- if (fp == NULL) {
- _E("Can't open RUL_CHARGING_CYCLES_FILE");
- rul.charging_cycles = 0;
- return;
- }
-
- if (fscanf(fp, "%d", &rul.charging_cycles) != 1) {
- _E("Unable to assign charging cycles from file");
- rul.charging_cycles = 0;
- return;
- }
-}
-
-static int heart_battery_init(void *data)
-{
- int ret;
- bool supported;
-
- ret = system_info_get_platform_bool("tizen.org/feature/battery", &supported);
- if (ret != SYSTEM_INFO_ERROR_NONE || !supported) {
- return RESOURCED_ERROR_NOTIMPL;
- }
-
- ret = heart_battery_stats_init_db();
- if (ret != RESOURCED_ERROR_NONE) {
- _E("heart module init failed at db creation");
- return RESOURCED_ERROR_FAIL;
- }
-
- heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
-
- ret = d_bus_register_signal(DEVICED_PATH_BATTERY,
- DEVICED_INTERFACE_BATTERY, GET_BATTERY_CAPACITY,
- heart_battery_capacity_status, NULL);
- if (ret < 0)
- _E("heart module failed to add a capacity status signal handler");
-
- ret = d_bus_register_signal(DEVICED_PATH_BATTERY,
- DEVICED_INTERFACE_BATTERY, GET_CHARGER_STATUS,
- heart_battery_charger_status, NULL);
- if (ret < 0)
- _E("heart module failed to add a charger status signal handler");
-
- heart_read_battery_total_capacity();
-
- config_parse(HEART_CONF_FILE_PATH, heart_battery_config, NULL);
- _I("heart config init");
-
-
- heart_battery_mode_factor_init();
-
- heart_battery_status_init();
-
- if (logic_rul)
- rul_data_init();
-
- register_notifier(RESOURCED_NOTIFIER_LOW_BATTERY, low_battery_handler);
- register_notifier(RESOURCED_NOTIFIER_DATA_RESET, heart_battery_reset);
-
- heart_battery_set_file_commit_timestamp(logging_get_time(CLOCK_BOOTTIME));
-
- ret = logging_module_init(BATTERY_NAME, ONE_DAY, TEN_MINUTE, heart_battery_update,
- HEART_BATTERY_UPDATE_INTERVAL, SYSTEM_DEFAULT);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("logging module init failed");
- return RESOURCED_ERROR_FAIL;
- }
-
- _D("heart battery init finished");
- return RESOURCED_ERROR_NONE;
-}
-
-void heart_capacity_history_update(struct logging_table_form *data, void *user_data)
-{
- int status, reset, capacity, diff;
- unsigned long discharging = 0, charging = 0;
- GSList **history_list = NULL;
-
- if (user_data)
- history_list = (GSList **)user_data;
- else
- history_list = &capacity_history_list;
-
- _D("%s %s %ld %s", data->appid, data->pkgid, data->time, data->data);
- if (sscanf(data->data, "%d %d %ld %ld %d %d ",
- &capacity, &diff,
- &discharging, &charging,
- &status, &reset) < 0) {
- _E("sscanf failed");
- return;
- }
- heart_battery_insert_capacity(history_list, capacity,
- diff, data->time, discharging, charging, status,
- reset, false);
-}
-
-static int heart_battery_dump(FILE *fp, int mode, void *data)
-{
- struct heart_battery_capacity *lbc;
- GSList *iter;
- char buf[BATTERY_DATA_MAX] = {0, };
- int ret, size, len = 0;
- time_t starttime;
- char timestr[80];
- struct tm loc_tm;
- GSList *history_list = NULL;
-
- starttime = time(NULL);
- starttime -= mode;
- localtime_r(&starttime, &loc_tm);
- /* print timestamp */
- strftime(timestr, sizeof(timestr),
- "%Y-%m-%d %H:%M:%S%z", &loc_tm);
-
- logging_read_foreach(BATTERY_NAME, NULL, NULL, starttime, 0,
- heart_capacity_history_update, &history_list);
-
- if (!history_list) {
- _E("capacity history is NULL!");
- return RESOURCED_ERROR_NONE;
- }
- LOG_DUMP(fp, "[BATTERY CAPACITY HISTORY] since %s\n", timestr);
- LOG_DUMP(fp, "capacity diff timestamp used_time charging_time charger_status, reset_mark\n");
- ret = pthread_mutex_lock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- size = g_slist_length(history_list);
- if (!size) {
- _I("capacity history is empty");
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_NONE;
- }
- gslist_for_each_item(iter, history_list) {
- lbc = (struct heart_battery_capacity *)iter->data;
- if (!lbc)
- break;
- len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%d %d %ld %ld %ld %d %d\n",
- lbc->capacity, lbc->diff_capacity, lbc->timestamp, lbc->used_time,
- lbc->charging_time, lbc->charger_status,
- lbc->reset_mark);
- if (BATTERY_DATA_MAX < len + BATTERY_LINE_MAX) {
- LOG_DUMP(fp, "%s\n", buf);
- len = 0;
- }
- }
- LOG_DUMP(fp, "%s\n", buf);
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- fflush(fp);
- if (history_list) {
- g_slist_free_full(history_list, free);
- history_list = NULL;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_battery_exit(void *data)
-{
- int ret;
- GSList *iter, *next;
- struct heart_battery_capacity *lbc;
-
- heart_battery_save_to_file(true);
- ret = pthread_mutex_lock(&heart_battery_mutex);
- if (ret)
- _E("pthread_mutex_lock() failed, %d", ret);
-
- gslist_for_each_safe(capacity_history_list, iter, next, lbc) {
- capacity_history_list = g_slist_remove(capacity_history_list, lbc);
- free(lbc);
- }
- capacity_history_list = NULL;
-
- ret = pthread_mutex_unlock(&heart_battery_mutex);
- if (ret)
- _E("pthread_mutex_unlock() failed, %d", ret);
-
- unregister_notifier(RESOURCED_NOTIFIER_LOW_BATTERY, low_battery_handler);
- unregister_notifier(RESOURCED_NOTIFIER_DATA_RESET, heart_battery_reset);
-
- logging_module_exit();
-
- _D("heart battery exit");
- return RESOURCED_ERROR_NONE;
-}
-
-static const struct heart_module_ops heart_battery_ops = {
- .name = "BATTERY",
- .init = heart_battery_init,
- .dump = heart_battery_dump,
- .exit = heart_battery_exit,
-};
-HEART_MODULE_REGISTER(&heart_battery_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- */
-
-/*
- * @file heart-cpu.c
- *
- * @desc heart cpu module
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <math.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "proc-common.h"
-#include "notifier.h"
-#include "resourced.h"
-#include "dbus-handler.h"
-#include "heart.h"
-#include "logging.h"
-#include "heart-common.h"
-#include "trace.h"
-#include "module.h"
-#include "macro.h"
-#include "userinfo-list.h"
-#include "proc-main.h"
-
-#define PROC_PATH "/proc/%d"
-#define PROC_STAT_PATH "/proc/%d/stat"
-#define CPU_NAME "cpu"
-#define CPU_DATA_MAX 1024
-#define CPU_ARRAY_MAX 24
-#define HEART_CPU_SAVE_INTERVAL 3600
-#define HEART_CPU_DATA_FILE HEART_USER_FILE_PATH"/.cpu.dat"
-
-enum {
- SERVICE = 0,
- FOREG = 1,
- BACKG = 2
-};
-
-struct heart_cpu_info {
- unsigned long utime;
- unsigned long stime;
- int state;
- pid_t pid;
-};
-
-struct heart_cpu_table {
- char appid[MAX_APPID_LENGTH];
- char pkgid[MAX_PKGNAME_LENGTH];
- unsigned long total_utime;
- unsigned long total_stime;
- unsigned long utime;
- unsigned long stime;
- int fg_count;
- unsigned long fg_time;
- unsigned long bg_time;
- GSList *last_pid_info;
- pid_t last_pid;
- time_t last_renew_time;
- GArray *cpu_info;
-};
-
-struct heart_cpu_dat_cache {
- char *path;
- GHashTable *list;
- time_t last_file_commit_time;
-};
-
-static GHashTable *heart_cpu_app_list;
-static pthread_mutex_t heart_cpu_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void heart_cpu_remove_last_pid_info_exited(struct heart_cpu_table *table)
-{
- char proc_path[sizeof(PROC_PATH) + MAX_DEC_SIZE(int)];
- GSList *iter, *next;
- struct heart_cpu_info *ci = NULL;
-
- if (!table || !table->last_pid_info)
- return;
-
- gslist_for_each_safe(table->last_pid_info, iter, next, ci) {
- snprintf(proc_path, sizeof(proc_path), PROC_PATH, ci->pid);
- if (!access(proc_path, F_OK))
- continue;
- table->last_pid_info = g_slist_remove(table->last_pid_info, ci);
- free(ci);
- }
-}
-
-static struct heart_cpu_info *find_pid_info(struct heart_cpu_table *table, pid_t pid)
-{
- GSList *iter = NULL;
- struct heart_cpu_info *ci = NULL;
-
- if (!table || !table->last_pid_info)
- return NULL;
-
- gslist_for_each_item(iter, table->last_pid_info) {
- ci = (struct heart_cpu_info *)iter->data;
- if (ci && ci->pid == pid)
- return ci;
- }
- return NULL;
-}
-
-static int heart_cpu_get_cpu_time(pid_t pid, unsigned long *utime,
- unsigned long *stime)
-{
- char proc_path[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
- FILE *fp;
-
- assert(utime != NULL);
- assert(stime != NULL);
-
- snprintf(proc_path, sizeof(proc_path), PROC_STAT_PATH, pid);
- fp = fopen(proc_path, "r");
- if (fp == NULL)
- return RESOURCED_ERROR_FAIL;
-
- if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s") < 0) {
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- if (fscanf(fp, "%lu %lu", utime, stime) < 1) {
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- fclose(fp);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static GHashTable* heart_cpu_get_user_app_list(int uid)
-{
- struct heart_cpu_dat_cache *cache;
-
- cache = (struct heart_cpu_dat_cache*)g_hash_table_lookup(heart_cpu_app_list, (gconstpointer)&uid);
- if (!cache) {
- _E("There is no table of uid %d", uid);
- return NULL;
- }
-
- return cache->list;
-}
-
-static int heart_cpu_write_data(struct proc_status *ps, pid_t pid, int type)
-{
- int ret;
- unsigned long utime, stime;
- char info[CPU_DATA_MAX];
- char *appid, *pkgid;
-
- ret = heart_cpu_get_cpu_time(pid, &utime, &stime);
- if (ret != RESOURCED_ERROR_NONE)
- return ret;
-
- snprintf(info, sizeof(info), "%lu %lu %d %d ", utime, stime, pid, type);
-
- ret = proc_get_id_info(ps, &appid, &pkgid);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to proc_get_id_info");
- return ret;
- }
- ret = logging_write(pid, CPU_NAME, appid, pkgid, time(NULL), info);
- _D("heart_cpu_write_data : pid = %d, appname = %s, pkgname = %s, type=%d",
- pid, appid, pkgid, type);
- return ret;
-}
-
-static int heart_cpu_service_launch(void *data)
-{
- int ret;
- struct proc_status *ps = (struct proc_status *)data;
-
- ret = heart_cpu_write_data(ps, ps->pid, SERVICE);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to write cpu info %d", ps->pid);
- return ret;
- }
- resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_cpu_foreground_state(void *data)
-{
- int ret;
- struct proc_status *ps = (struct proc_status *)data;
-
- ret = heart_cpu_write_data(ps, ps->pid, FOREG);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to write cpu info %d", ps->pid);
- return ret;
- }
- resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_cpu_background_state(void *data)
-{
- int ret;
- GSList *giter = NULL;
- struct proc_status *ps = (struct proc_status *)data;
-
- ret = heart_cpu_write_data(ps, ps->pid, BACKG);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to write cpu info %d", ps->pid);
- return ret;
- }
- if (!ps->pai->childs)
- return RESOURCED_ERROR_NONE;
- gslist_for_each_item(giter, ps->pai->childs) {
- pid_t child = GPOINTER_TO_PID(giter->data);
- ret = heart_cpu_write_data(ps, child, BACKG);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to write child cpu info %d", child);
- return ret;
- }
- }
- resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_cpu_update_state(void *data)
-{
- int ret, state;
- GSList *giter = NULL;
- struct proc_status *ps = (struct proc_status *)data;
-
- if (!ps->pai) {
- _E("Invalid parameter");
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
- if (ps->pai->lru_state == PROC_FOREGROUND)
- state = FOREG;
- else
- state = BACKG;
-
- ret = heart_cpu_write_data(ps, ps->pid, state);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to write cpu info %d", ps->pid);
- return ret;
- }
- _D("heart_cpu_update_state : pid = %d, state = %d",
- ps->pid, state);
- if (!ps->pai->childs)
- return RESOURCED_ERROR_NONE;
- gslist_for_each_item(giter, ps->pai->childs) {
- pid_t child = GPOINTER_TO_PID(giter->data);
- ret = heart_cpu_write_data(ps, child, state);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to write cpu info %d", child);
- return ret;
- }
- }
- resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_cpu_update_app_list(void *data)
-{
- _cleanup_app_list_close_ GSList *proc_app_list = PAL_INIT_VALUE;
- GSList *giter = NULL;
- struct proc_app_info *pai = NULL;
-
- proc_app_list = proc_app_list_open();
- gslist_for_each_item(giter, proc_app_list) {
- struct proc_status ps;
- pai = (struct proc_app_info *)giter->data;
- if (!pai->ai)
- continue;
- ps.pid = pai->main_pid;
- ps.pai = pai;
- heart_cpu_update_state(&ps);
- }
- return RESOURCED_ERROR_NONE;
-}
-
-static void heart_cpu_free_uid(gpointer data)
-{
- if (data)
- free(data);
-}
-
-static void heart_cpu_free_dat_cache(gpointer data)
-{
- struct heart_cpu_dat_cache *cache = (struct heart_cpu_dat_cache*)data;
- if (cache) {
- free(cache->path);
- g_hash_table_destroy(cache->list);
- free(cache);
- }
-}
-
-static void heart_free_value(gpointer value)
-{
- int i;
- struct heart_cpu_info *info;
- struct heart_cpu_table *table = (struct heart_cpu_table *)value;
-
- if (!table)
- return;
-
- if (table->last_pid_info)
- g_slist_free_full(table->last_pid_info, free);
-
- if (table->cpu_info) {
- for (i = 0; i < table->cpu_info->len; i++) {
- info = g_array_index(table->cpu_info,
- struct heart_cpu_info *, i);
- free(info);
- }
- g_array_free(table->cpu_info, TRUE);
- }
-
- free(table);
-}
-
-static int heart_cpu_read_length(char *buf, int count)
-{
- int i, find = 0;
- int len = strlen(buf);
-
- for (i = 0; i < len; i++) {
- if (buf[i] == ' ')
- find++;
- if (find == count)
- return i + 1;
- }
- return RESOURCED_ERROR_FAIL;
-}
-
-static int heart_cpu_read_from_file(struct heart_cpu_dat_cache *cache)
-{
- int i, len, ret, fg_count, state;
- unsigned long total_utime, total_stime;
- unsigned long utime, stime;
- unsigned long fg_time, bg_time;
- pid_t pid;
- FILE *fp;
- struct heart_cpu_table *table;
- char appid[MAX_APPID_LENGTH] = {0, };
- char pkgid[MAX_PKGNAME_LENGTH] = {0, };
- char buf[CPU_DATA_MAX] = {0, };
-
- if (!cache) {
- _E("Cache doesn't exist");
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
-
- snprintf(buf, CPU_DATA_MAX, HEART_CPU_DATA_FILE, cache->path);
- fp = fopen(buf, "r");
- if (!fp) {
- if (errno != ENOENT) {
- _E("Fail to open %s (%d)", buf, errno);
- return RESOURCED_ERROR_FAIL;
- }
-
- _D("%s doesn't exist. Make new one.", buf);
- snprintf(buf, CPU_DATA_MAX, HEART_USER_FILE_PATH, cache->path);
- ret = mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH);
- if (ret != 0 && errno != EEXIST) {
- _E("Fail to create %s (%d)", buf, errno);
- return RESOURCED_ERROR_FAIL;
- }
-
- snprintf(buf, CPU_DATA_MAX, HEART_CPU_DATA_FILE, cache->path);
- fp = fopen(buf, "w+");
- if (!fp) {
- _E("Fail to create %s (%d)", buf, errno);
- return RESOURCED_ERROR_FAIL;
- }
- fclose(fp);
- return RESOURCED_ERROR_NONE;
- }
-
- while (fgets(buf, CPU_DATA_MAX, fp)) {
- table = malloc(sizeof(struct heart_cpu_table));
-
- if (!table) {
- _E("malloc failed");
- fclose(fp);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- /* make return values */
- ret = sscanf(buf, STR_FS(MAX_APPID_LENGTH_M1)" "STR_FS(MAX_PKGNAME_LENGTH_M1)" %lu %lu %lu %lu %lu %lu %d ",
- appid, pkgid,
- &total_utime, &total_stime,
- &utime, &stime,
- &fg_time, &bg_time, &fg_count);
-
- if (ret <= 0) {
- _E("sscanf failed");
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", appid) < 0) {
- _E("sprintf failed");
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", pkgid) < 0) {
- _E("snprintf failed");
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- len = heart_cpu_read_length(buf, 9);
- if (len <= 0) {
- _E("sscanf failed");
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- table->total_utime = total_utime;
- table->total_stime = total_stime;
- table->utime = utime;
- table->stime = stime;
- table->last_pid_info = NULL;
- table->last_pid = 0;
- table->fg_time = fg_time;
- table->bg_time = bg_time;
- table->fg_count = fg_count;
- table->last_renew_time = 0;
- table->cpu_info =
- g_array_new(FALSE, FALSE, sizeof(struct heart_cpu_info *));
-
- for (i = 0; i < CPU_ARRAY_MAX; i++) {
- struct heart_cpu_info *ci;
-
- ret = sscanf(buf + len, "%lu %lu %d %d ", &utime, &stime, &pid, &state);
- if (ret <= 0) {
- _E("file read fail %s", buf + len);
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- ci = malloc(sizeof(struct heart_cpu_info));
- if (!ci) {
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
- ci->utime = utime;
- ci->stime = stime;
- ci->pid = pid;
- ci->state = state;
- len += heart_cpu_read_length(buf + len, 4);
- g_array_append_val(table->cpu_info, ci);
- }
-
- ret = pthread_mutex_lock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- g_array_free(table->cpu_info, TRUE);
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- g_hash_table_insert(cache->list, (gpointer)table->appid, (gpointer)table);
- ret = pthread_mutex_unlock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- }
-
- fclose(fp);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_cpu_save_to_file(struct heart_cpu_dat_cache *cache)
-{
- int i, len, ret, array_len;
- gpointer value;
- gpointer key;
- GHashTableIter iter;
- struct heart_cpu_table *table;
- FILE *fp;
- char buf[CPU_DATA_MAX] = {0, };
-
- if (!cache) {
- _D("Cache is empty. Do nothing.");
- return RESOURCED_ERROR_NONE;
- }
-
- snprintf(buf, CPU_DATA_MAX, HEART_CPU_DATA_FILE, cache->path);
- fp = fopen(buf, "w");
- if (!fp) {
- _E("%s fopen failed %d", buf, errno);
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!(cache->list)) {
- _E("empty app list");
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!g_hash_table_size(cache->list)) {
- _E("hash table is empty");
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- ret = pthread_mutex_lock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- g_hash_table_iter_init(&iter, cache->list);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- table = (struct heart_cpu_table *)value;
- array_len = table->cpu_info->len;
- len = snprintf(buf, CPU_DATA_MAX, "%s %s %lu %lu %lu %lu %lu %lu %d ",
- table->appid, table->pkgid,
- table->total_utime,
- table->total_stime,
- table->utime,
- table->stime,
- table->fg_time,
- table->bg_time,
- table->fg_count);
-
- for (i = 0; i < CPU_ARRAY_MAX; i++) {
- struct heart_cpu_info *ci;
- if (array_len <= i) {
- len += snprintf(buf + len, CPU_DATA_MAX - len, "0 0 0 0 ");
- } else {
- ci = g_array_index(table->cpu_info, struct heart_cpu_info *, i);
- if (!ci)
- break;
- len += snprintf(buf + len, CPU_DATA_MAX - len, "%lu %lu %d %d ",
- ci->utime,
- ci->stime,
- ci->pid,
- ci->state);
- }
- }
- snprintf(buf + len, CPU_DATA_MAX - len, "\n");
- fputs(buf, fp);
- }
- ret = pthread_mutex_unlock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- fclose(fp);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_cpu_hashtable_renew(GHashTable *hashtable, time_t now)
-{
- int ret;
- gpointer value;
- gpointer key;
- GHashTableIter iter;
- struct heart_cpu_table *table;
-
- if (!hashtable) {
- _E("empty app list");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!g_hash_table_size(hashtable)) {
- _E("hash table is empty");
- return RESOURCED_ERROR_FAIL;
- }
- ret = pthread_mutex_lock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- g_hash_table_iter_init(&iter, hashtable);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- table = (struct heart_cpu_table *)value;
- table->total_utime = 0;
- table->total_stime = 0;
- table->last_renew_time = now;
- table->fg_count = 0;
- table->fg_time = 0;
- table->bg_time = 0;
- }
- ret = pthread_mutex_unlock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_NONE;
-}
-
-void heart_cpu_update(struct logging_table_form *data, void *user_data)
-{
- const char *path;
- int ret;
- pid_t pid;
- uid_t *uid;
- int state;
- unsigned long utime, stime;
- unsigned long utime_diff = 0, stime_diff = 0;
- time_t curr_time = logging_get_time(CLOCK_BOOTTIME);
- struct heart_cpu_table *table;
- struct heart_cpu_info *ci = NULL;
- struct heart_cpu_dat_cache *cache;
- GHashTable *cpu_usage_list = NULL;
-
- cache = (struct heart_cpu_dat_cache*)g_hash_table_lookup(
- heart_cpu_app_list, (gpointer)(&(data->uid)));
- if (!cache) {
- path = userinfo_find_home_dir((uid_t)data->uid);
- if (!path) {
- _E("uid %d doesn't existed", data->uid);
- return;
- }
-
- cache = (struct heart_cpu_dat_cache*)malloc(sizeof(struct heart_cpu_dat_cache));
- if (!cache) {
- _E("malloc failed");
- return;
- }
-
- cache->path = strndup(path, strlen(path));
- if (!cache->path) {
- _E("strndup failed");
- free(cache);
- return;
- }
-
- cache->list = g_hash_table_new_full(
- g_str_hash,
- g_str_equal,
- NULL,
- heart_free_value);
- if (!cache->list) {
- _E("g_hash_table_new_full failed");
- free(cache->path);
- free(cache);
- return;
- }
-
- uid = malloc(sizeof(uid_t));
- if (!uid) {
- _E("malloc failed");
- g_hash_table_unref(cache->list);
- free(cache->path);
- free(cache);
- return;
- }
- *uid = (uid_t)data->uid;
-
- g_hash_table_insert(heart_cpu_app_list, (gpointer)uid, (gpointer)cache);
- }
- cpu_usage_list = cache->list;
-
- _D("%d %s %s %ld %s", data->uid, data->appid, data->pkgid, data->time, data->data);
- if (sscanf(data->data, "%lu %lu %d %d ", &utime, &stime, &pid, &state) < 0) {
- _E("sscanf failed");
- return;
- }
-
- ret = pthread_mutex_lock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return;
- }
-
- /* update */
- table = g_hash_table_lookup(cpu_usage_list, data->appid);
- if (table) {
-
- if (table->last_renew_time > data->time)
- goto unlock_exit;
-
- ci = find_pid_info(table, pid);
- if (table->last_pid_info && ci) {
- utime_diff = utime - ci->utime;
- table->utime += utime_diff;
- table->total_utime += utime_diff;
- stime_diff = stime - ci->stime;
- table->stime += stime_diff;
- table->total_stime += stime_diff;
- ci->utime = utime;
- ci->stime = stime;
- if (ci->state == BACKG || ci->state == SERVICE) {
- table->bg_time += utime_diff + stime_diff;
- if (state == FOREG)
- table->fg_count++;
- } else
- table->fg_time += utime_diff + stime_diff;
- ci->state = state;
- } else {
- table->utime += utime;
- table->total_utime += utime;
- table->stime += stime;
- table->total_stime += stime;
- if (table->last_pid_info)
- heart_cpu_remove_last_pid_info_exited(table);
- ci = malloc(sizeof(struct heart_cpu_info));
- if (!ci) {
- _E("malloc failed");
- goto unlock_exit;
- }
- ci->pid = pid;
- ci->utime = utime;
- ci->stime = stime;
- ci->state = state;
- if (ci->state == FOREG)
- table->fg_count++;
- table->last_pid_info = g_slist_prepend(table->last_pid_info, ci);
- table->last_pid = pid;
- }
- } else {
- table = calloc(1, sizeof(struct heart_cpu_table));
-
- if (!table) {
- _E("malloc failed");
- goto unlock_exit;
- }
-
- if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", data->appid) < 0) {
- free(table);
- _E("snprintf failed");
- goto unlock_exit;
- }
-
- if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", data->pkgid) < 0) {
- free(table);
- _E("snprintf failed");
- goto unlock_exit;
- }
- table->total_utime = utime;
- table->total_stime = stime;
- table->utime = utime;
- table->stime = stime;
- table->fg_count = 0;
- table->fg_time = 0;
- table->bg_time = 0;
- if (state == FOREG)
- table->fg_count = 1;
-
- table->cpu_info =
- g_array_new(FALSE, FALSE, sizeof(struct heart_cpu_info *));
- if (!table->cpu_info) {
- free(table);
- _E("g_array_new failed");
- goto unlock_exit;
- }
-
- ci = malloc(sizeof(struct heart_cpu_info));
- if (!ci) {
- _E("malloc failed");
- free(table);
- goto unlock_exit;
- }
- ci->pid = pid;
- ci->utime = utime;
- ci->stime = stime;
- ci->state = state;
- table->last_pid_info = g_slist_prepend(NULL, ci);
- table->last_pid = pid;
-
- g_hash_table_insert(cpu_usage_list, (gpointer)table->appid, (gpointer)table);
- }
- ret = pthread_mutex_unlock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return;
- }
-
- if (cache->last_file_commit_time + HEART_CPU_SAVE_INTERVAL < curr_time) {
- /* all hash table update and make new array */
- gpointer value;
- gpointer key;
- GHashTableIter iter;
- struct heart_cpu_table *search;
- struct heart_cpu_info *ci;
-
- ret = pthread_mutex_lock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return;
- }
-
- g_hash_table_iter_init(&iter, cpu_usage_list);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- search = (struct heart_cpu_table *)value;
-
- ci = malloc(sizeof(struct heart_cpu_info));
-
- if (!ci) {
- _E("malloc failed");
- goto unlock_exit;
- }
- /* make new array node */
- ci->pid = search->last_pid;
- ci->utime = search->utime;
- ci->stime = search->stime;
- search->utime = 0;
- search->stime = 0;
- /* hashtable sliding : remove last node and make new one */
- if (search->cpu_info->len == CPU_ARRAY_MAX)
- g_array_remove_index(search->cpu_info, CPU_ARRAY_MAX - 1);
- g_array_prepend_val(search->cpu_info, ci);
- }
- ret = pthread_mutex_unlock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return;
- }
- /* rewrite hashtable list file */
- ret = heart_cpu_save_to_file(cache);
- if (ret) {
- _E("save to file failed");
- goto unlock_exit;
- }
-
- cache->last_file_commit_time = curr_time;
- }
-
- return;
-
-unlock_exit:
- ret = pthread_mutex_unlock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return;
- }
-}
-
-struct heart_cpu_data *heart_cpu_get_data(int uid, char *appid, enum heart_data_period period, struct heart_cpu_data *data)
-{
- int index, i, ret;
- struct heart_cpu_table *table;
- GHashTable *hashtable;
-
- if (!appid) {
- _E("Wrong arguments!");
- return NULL;
- }
-
- hashtable = heart_cpu_get_user_app_list(uid);
- if (!hashtable) {
- _E("Fail to get app list");
- return NULL;
- }
-
- if (!g_hash_table_size(hashtable)) {
- _D("hash table is empty");
- return NULL;
- }
-
- switch (period) {
- case DATA_LATEST:
- index = 0;
- break;
- case DATA_3HOUR:
- index = 3;
- break;
- case DATA_6HOUR:
- index = 6;
- break;
- case DATA_12HOUR:
- index = 12;
- break;
- case DATA_1DAY:
- index = 24;
- break;
- default:
- _E("Wrong message arguments! %d", period);
- return NULL;
- }
-
- ret = pthread_mutex_lock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return NULL;
- }
-
- table = g_hash_table_lookup(hashtable, (gconstpointer)appid);
- if (!table) {
- data = NULL;
- goto unlock_exit;
- }
- if (snprintf(data->appid, MAX_APPID_LENGTH, "%s", table->appid) < 0) {
- _E("snprintf failed");
- data = NULL;
- goto unlock_exit;
- }
- if (snprintf(data->pkgid, MAX_PKGNAME_LENGTH, "%s", table->pkgid) < 0) {
- _E("snprintf failed");
- data = NULL;
- goto unlock_exit;
- }
- if (period == DATA_LATEST) {
- data->utime = table->total_utime;
- data->stime = table->total_stime;
- } else {
- data->utime = table->utime;
- data->stime = table->stime;
- i = table->cpu_info->len;
- if (i == 0) {
- data = NULL;
- goto unlock_exit;
- }
- if (i < index)
- index = i;
- for (i = 0; i < index; i++) {
- struct heart_cpu_info *cpu_info;
- cpu_info =
- g_array_index(table->cpu_info, struct heart_cpu_info *, i);
- if (!cpu_info)
- break;
- data->utime += cpu_info->utime;
- data->stime += cpu_info->stime;
- }
- }
-unlock_exit:
- ret = pthread_mutex_unlock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return NULL;
- }
- return data;
-}
-
-static int compare_usage(const struct heart_app_usage *lau_a,
- const struct heart_app_usage *lau_b)
-{
- if (lau_a->point != lau_b->point)
- return (lau_b->point - lau_a->point);
-
- return 0;
-}
-
-/*
- * Calculate application usage using frequency and time
- */
-static double heart_cpu_get_point(int freq, int time)
-{
- double weightForFrequence = 3;
- double point = 0;
- point = sqrt(time + (freq*weightForFrequence));
- return point;
-}
-
-int heart_cpu_get_appusage_list(int uid, GHashTable *lists, int top)
-{
- int index = top, i, ret;
- gpointer value;
- gpointer key;
- GHashTableIter h_iter;
- struct heart_cpu_table *table;
- struct heart_app_usage lau;
- GArray *app_lists = NULL;
- GHashTable *hashtable;
-
- hashtable = heart_cpu_get_user_app_list(uid);
- if (!hashtable) {
- _E("Fail to get app list");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!g_hash_table_size(hashtable)) {
- _E("hash table is empty");
- return RESOURCED_ERROR_FAIL;
- }
-
- app_lists = g_array_new(false, false, sizeof(struct heart_app_usage));
- ret = pthread_mutex_lock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- g_array_free(app_lists, true);
- return RESOURCED_ERROR_FAIL;
- }
-
- g_hash_table_iter_init(&h_iter, hashtable);
-
- while (g_hash_table_iter_next(&h_iter, &key, &value)) {
-
- table = (struct heart_cpu_table *)value;
- if (!table->fg_count)
- continue;
-
- lau.appid = table->appid;
- lau.pkgid = table->pkgid;
- lau.fg_count = table->fg_count;
- lau.used_time = table->fg_time;
- lau.point = (int)heart_cpu_get_point(lau.fg_count, lau.used_time);
- /*
- * make all application lists with weighted point value excepting service application
- */
- g_array_append_val(app_lists, lau);
- }
- ret = pthread_mutex_unlock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- g_array_free(app_lists, true);
- return RESOURCED_ERROR_FAIL;
- }
- if (app_lists->len < top) {
- _I("too small data for making app usage lists");
- g_array_free(app_lists, true);
- return RESOURCED_ERROR_NO_DATA;
- }
-
- g_array_sort(app_lists, (GCompareFunc)compare_usage);
-
- if (!top)
- index = app_lists->len;
-
- /*
- * replace application usage lists with sorted usage arrays
- */
- g_hash_table_remove_all(lists);
- for (i = 0; i < index; i++) {
- struct heart_app_usage *usage = &g_array_index(app_lists, struct heart_app_usage, i);
- _D("appid : %s, point : %d", usage->appid, usage->point);
- g_hash_table_insert(lists, g_strndup(usage->appid, strlen(usage->appid)), GINT_TO_POINTER(1));
- }
- g_array_free(app_lists, true);
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_cpu_update_appid(void *data)
-{
- int pid;
- char old_appid[MAX_APPID_LENGTH], new_appid[MAX_APPID_LENGTH];
- char *info;
-
- if (!data) {
- _E("Invalid parameter");
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
-
- info = (char*)data;
- if (sscanf(info, "%d "STR_FS(MAX_APPID_LENGTH_M1)" "STR_FS(MAX_APPID_LENGTH_M1),
- &pid, old_appid, new_appid) < 0) {
- _E("sscanf failed, %m");
- return RESOURCED_ERROR_FAIL;
- }
-
- return logging_modify_appid(CPU_NAME, old_appid, new_appid, pid);
-}
-
-static void dbus_heart_get_cpu_data(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int period = -1;
- char *appid = NULL;
- struct heart_cpu_data *data = NULL;
-
- int uid = -1;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i&si)", &uid, &appid, &period);
- if (uid < 0 || !appid || period < 0) {
- _E("Wrong message arguments!");
- goto failure;
- }
-
- data = malloc(sizeof(struct heart_cpu_data));
- if (!data) {
- _E("malloc failed");
- goto failure;
- }
-
- if (heart_cpu_get_data(uid, appid, period, data) == NULL)
- goto failure;
-
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(ii)",
- data->utime, data->stime));
- free(data);
- return;
-
-failure:
- if (data)
- free(data);
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_heart_get_cpu_data_list(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int period = -1, index, i, ret;
- gpointer value;
- gpointer key;
- GHashTableIter h_iter;
- struct heart_cpu_table *table;
-
- char *appid;
- unsigned long utime, stime, ftime, total;
-
- int uid = -1;
- GHashTable *hashtable;
-
- GVariantBuilder builder, *sub_builder;
-
- utime = stime = ftime = total = 0;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(ii)", &uid, &period);
- if (uid < 0 || period < 0) {
- _E("Wrong message arguments!");
- goto failure;
- }
-
- heart_cpu_update_app_list(NULL);
-
- logging_save_to_storage(true);
- /* update data list from db */
- logging_update(true);
-
- switch (period) {
- case DATA_LATEST:
- index = 0;
- break;
- case DATA_3HOUR:
- index = 3;
- break;
- case DATA_6HOUR:
- index = 6;
- break;
- case DATA_12HOUR:
- index = 12;
- break;
- case DATA_1DAY:
- index = 24;
- break;
- default:
- _E("Wrong message arguments! %d", period);
- goto failure;
- }
-
- hashtable = heart_cpu_get_user_app_list(uid);
- if (!hashtable) {
- _E("Fail to get app list");
- goto failure;
- }
-
- if (!g_hash_table_size(hashtable)) {
- _E("hash table is empty");
- goto failure;
- }
-
- ret = pthread_mutex_lock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- goto failure;
- }
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
- sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(sii)"));
-
- g_hash_table_iter_init(&h_iter, hashtable);
- while (g_hash_table_iter_next(&h_iter, &key, &value)) {
- table = (struct heart_cpu_table *)value;
- if (!table)
- break;
- if (period == DATA_LATEST) {
- utime = table->total_utime;
- stime = table->total_stime;
- } else {
- utime = table->utime;
- stime = table->stime;
- i = table->cpu_info->len;
- if (i < index)
- index = i;
- for (i = 0; i < index; i++) {
- struct heart_cpu_info *ci;
- ci = g_array_index(table->cpu_info, struct heart_cpu_info *, i);
- if (!ci)
- break;
- utime += ci->utime;
- stime += ci->stime;
- }
- }
- ftime = table->fg_time;
- total = utime + stime;
- if (total == 0)
- continue;
- appid = table->appid;
-
- g_variant_builder_add(sub_builder, "(sii)", appid, total, ftime);
- }
-
- ret = pthread_mutex_unlock(&heart_cpu_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- g_variant_builder_unref(sub_builder);
- goto failure;
- }
-
- g_variant_builder_add_value(&builder, g_variant_new("a(sii)", sub_builder));
- g_variant_builder_unref(sub_builder);
-
- g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_heart_reset_cpu_data(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret = -1;
-
- GHashTableIter iter_table;
- gpointer key, value;
-
- g_hash_table_iter_init(&iter_table, heart_cpu_app_list);
- while (g_hash_table_iter_next(&iter_table, &key, &value))
- ret = heart_cpu_hashtable_renew(((struct heart_cpu_dat_cache*)value)->list, time(NULL));
-
-
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
-}
-
-static void dbus_heart_update_cpu_data(GDBusMethodInvocation *invocation, GVariant *params)
-{
- heart_cpu_update_app_list(NULL);
-
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", 0));
-}
-
-static void dbus_heart_sync_cpu_data(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret = 0;
-
- heart_cpu_update_app_list(NULL);
-
- ret = logging_sync(invocation);
- if (ret)
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
-}
-
-static void dbus_heart_save_to_file(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret;
-
- GHashTableIter iter_table;
- gpointer key, value;
- struct heart_cpu_dat_cache *cache;
-
- g_hash_table_iter_init(&iter_table, heart_cpu_app_list);
- while (g_hash_table_iter_next(&iter_table, &key, &value)) {
- cache = (struct heart_cpu_dat_cache*)value;
- ret = heart_cpu_save_to_file(cache);
- if (ret) {
- _E("save to file failed");
- D_BUS_REPLY_ERR(invocation);
- return;
- }
- cache->last_file_commit_time = logging_get_time(CLOCK_BOOTTIME);
- }
-
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
-}
-
-static const char dbus_methods_xml[] =
-" <method name='GetCpuData'>"
-" <arg type='i' name='Uid' direction='in'/>"
-" <arg type='s' name='Appid' direction='in'/>"
-" <arg type='i' name='Period' direction='in'/>"
-" <arg type='i' name='Utime' direction='out'/>"
-" <arg type='i' name='Stime' direction='out'/>"
-" </method>"
-" <method name='GetCpuDataList'>"
-" <arg type='i' name='Uid' direction='in'/>"
-" <arg type='i' name='Period' direction='in'/>"
-" <arg type='a(sii)' name='CpuTimePerApp' direction='out'/>"
-" </method>"
-" <method name='ResetCpuData'>"
-" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
-" </method>"
-" <method name='UpdateCpuData'>"
-" <arg type='i' name='Zero' direction='out'/>"
-" </method>"
-" <method name='SyncCpuData'>"
-" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
-" </method>"
-" <method name='SaveCpuData'>"
-" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
-" </method>";
-
-static struct d_bus_method dbus_methods[] = {
- { "GetCpuData", dbus_heart_get_cpu_data },
- { "GetCpuDataList", dbus_heart_get_cpu_data_list },
- { "ResetCpuData", dbus_heart_reset_cpu_data },
- { "UpdateCpuData", dbus_heart_update_cpu_data },
- { "SyncCpuData", dbus_heart_sync_cpu_data },
- { "SaveCpuData", dbus_heart_save_to_file },
-};
-
-static int heart_cpu_reset(void *data)
-{
- GHashTableIter iter_table;
- gpointer key, value;
- int ret = RESOURCED_ERROR_FAIL;
-
- g_hash_table_iter_init(&iter_table, heart_cpu_app_list);
- while (g_hash_table_iter_next(&iter_table, &key, &value))
- ret = heart_cpu_hashtable_renew(((struct heart_cpu_dat_cache*)value)->list, time(NULL));
-
- return ret;
-}
-
-static int heart_cpu_init(void *data)
-{
- const GArray *user_list = NULL;
- int ret;
- uid_t *uid;
- struct heart_cpu_dat_cache *cache;
-
- ret = logging_module_init(CPU_NAME, ONE_DAY, TEN_MINUTE, heart_cpu_update, TEN_MINUTE, USER_DEFAULT);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("logging module init failed");
- return RESOURCED_ERROR_FAIL;
- }
-
- user_list = userinfo_get_list();
- if (!user_list) {
- _E("Fail to get user table");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!heart_cpu_app_list) {
- heart_cpu_app_list = g_hash_table_new_full(
- g_int_hash,
- g_int_equal,
- heart_cpu_free_uid,
- heart_cpu_free_dat_cache);
-
- userinfo_for_each(elem, user_list) {
- cache = (struct heart_cpu_dat_cache*)malloc(sizeof(struct heart_cpu_dat_cache));
- assert(cache);
-
- cache->path = strndup(elem->home_dir, strlen(elem->home_dir));
- cache->list = g_hash_table_new_full(
- g_str_hash,
- g_str_equal,
- NULL,
- heart_free_value);
-
- ret = heart_cpu_read_from_file(cache);
- assert(ret == RESOURCED_ERROR_NONE);
-
- cache->last_file_commit_time = logging_get_time(CLOCK_BOOTTIME);
-
- uid = malloc(sizeof(uid_t));
- assert(uid);
-
- *uid = elem->uid;
- g_hash_table_insert(heart_cpu_app_list, (gpointer)uid, (gpointer)cache);
- }
- }
-
- heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
-
- register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, heart_cpu_service_launch);
- register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, heart_cpu_foreground_state);
- register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, heart_cpu_background_state);
- register_notifier(RESOURCED_NOTIFIER_APP_GROUP, heart_cpu_update_appid);
- register_notifier(RESOURCED_NOTIFIER_DATA_UPDATE, heart_cpu_update_app_list);
- register_notifier(RESOURCED_NOTIFIER_DATA_RESET, heart_cpu_reset);
-
- heart_cpu_get_appusage_list_func = heart_cpu_get_appusage_list;
-
- _D("heart cpu init finished");
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_cpu_exit(void *data)
-{
- GHashTableIter iter;
- gpointer key, value;
- struct heart_cpu_dat_cache *cache;
-
- unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, heart_cpu_service_launch);
- unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, heart_cpu_foreground_state);
- unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, heart_cpu_background_state);
- unregister_notifier(RESOURCED_NOTIFIER_APP_GROUP, heart_cpu_update_appid);
- unregister_notifier(RESOURCED_NOTIFIER_DATA_UPDATE, heart_cpu_update_app_list);
- unregister_notifier(RESOURCED_NOTIFIER_DATA_RESET, heart_cpu_reset);
-
- if (heart_cpu_app_list) {
- g_hash_table_iter_init(&iter, heart_cpu_app_list);
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- cache = (struct heart_cpu_dat_cache*)value;
- heart_cpu_save_to_file(cache);
- }
- g_hash_table_destroy(heart_cpu_app_list);
- }
-
- logging_module_exit();
-
- heart_cpu_get_appusage_list_func = NULL;
-
- _D("heart cpu exit");
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_cpu_dump(FILE *fp, int mode, void *data)
-{
- time_t starttime;
- char timestr[80];
- struct tm loc_tm;
- static GHashTable *cpu_usage_list;
- gpointer value;
- gpointer key;
- GHashTableIter h_iter;
- struct heart_cpu_table *table;
-
- starttime = time(NULL);
-
- starttime -= mode;
- localtime_r(&starttime, &loc_tm);
- /* print timestamp */
- strftime(timestr, sizeof(timestr),
- "%Y-%m-%d %H:%M:%S%z", &loc_tm);
-
- cpu_usage_list = g_hash_table_new_full(
- g_str_hash,
- g_str_equal,
- NULL,
- free);
-
-
- logging_read_foreach(CPU_NAME, NULL, NULL, starttime, 0,
- heart_cpu_update, cpu_usage_list);
-
- if (!g_hash_table_size(cpu_usage_list)) {
- _E("hash table is empty");
- return 0;
- }
-
- LOG_DUMP(fp, "[CPU USAGE LISTS] since %s\n", timestr);
- LOG_DUMP(fp, "appid pkgid total fg_count fg_time\n");
- g_hash_table_iter_init(&h_iter, cpu_usage_list);
-
- while (g_hash_table_iter_next(&h_iter, &key, &value)) {
-
- table = (struct heart_cpu_table *)value;
- if (!table)
- break;
- LOG_DUMP(fp, "%s %s %ld %d %ld\n", table->appid, table->pkgid,
- table->total_utime + table->total_stime,
- table->fg_count, table->fg_time);
- }
- fflush(fp);
- g_hash_table_destroy(cpu_usage_list);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static const struct heart_module_ops heart_cpu_ops = {
- .name = "CPU",
- .init = heart_cpu_init,
- .dump = heart_cpu_dump,
- .exit = heart_cpu_exit,
-};
-HEART_MODULE_REGISTER(&heart_cpu_ops)
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * @file heart-abnormal.c
+ *
+ * @desc heart abnormal module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <sys/time.h>
+
+#include "proc-common.h"
+#include "notifier.h"
+#include "resourced.h"
+#include "dbus-handler.h"
+#include "heart.h"
+#include "logging.h"
+#include "heart-common.h"
+#include "trace.h"
+#include "module.h"
+#include "macro.h"
+
+#define ABNORMAL_NAME "abnormal"
+#define ABNORMAL_DATA_MAX 1024
+#define ABNORMAL_CHECK_NUM 10
+
+#define TIMESTAMP_LEN 16
+#define MILLISEC 1000
+#define TIME_MAX_LEN 64
+#define SLUG_TYPE_MALFUN 6
+#define NOPID 0
+
+enum abnormal_type {
+ FC = 0,
+ ANR = 1,
+ ABNORMAL_TYPE_MAX,
+};
+
+struct heart_abnormal_table {
+ char appid[MAX_APPID_LENGTH];
+ char pkgid[MAX_PKGNAME_LENGTH];
+ time_t time;
+ int count[ABNORMAL_TYPE_MAX];
+};
+
+static GHashTable *heart_abnormal_list;
+static pthread_mutex_t heart_abnormal_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void heart_abnormal_fill_array(struct logging_table_form *entry, void *data)
+{
+ int ret, i;
+ unsigned int type;
+ struct heart_abnormal_table *table = NULL;
+ GHashTable *list = (GHashTable *)data;
+
+ if (sscanf((char *)entry->data, "%*s %*s %u ", &type) < 0) {
+ _E("sscanf failed, %m");
+ return;
+ }
+
+ if (type >= ABNORMAL_TYPE_MAX) {
+ _E("wrong abnormal type, %u", type);
+ return;
+ }
+ ret = pthread_mutex_lock(&heart_abnormal_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return;
+ }
+ table = g_hash_table_lookup(list, entry->appid);
+ if (!table) {
+ table = malloc(sizeof(struct heart_abnormal_table));
+ if (!table) {
+ _E("malloc failed");
+ goto unlock_exit;
+ }
+
+ if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", entry->appid) < 0) {
+ _E("snprintf failed");
+ free(table);
+ goto unlock_exit;
+ }
+
+ if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", entry->pkgid) < 0) {
+ _E("snprintf failed");
+ free(table);
+ goto unlock_exit;
+ }
+ table->time = entry->time;
+
+ for (i = 0; i < ABNORMAL_TYPE_MAX; i++)
+ table->count[i] = 0;
+
+ table->count[type] = 0;
+ g_hash_table_insert(list, (gpointer)table->appid, (gpointer)table);
+ }
+ table->count[type]++;
+
+unlock_exit:
+ ret = pthread_mutex_unlock(&heart_abnormal_mutex);
+ if (ret)
+ _E("pthread_mutex_unlock() failed, %d", ret);
+}
+
+static void heart_abnormal_launch_popup(char *appid, int count)
+{
+ _W("A malfunction popup is supposed to be created here, but system-popup "
+ "doesn't actually expose a MalfunctionNotifierLaunch DBus method and "
+ "this legacy functionality is deprecated.");
+
+#if 0
+ /* Dead code (see above); it has been disabled instead of outright removed
+ * because I've seen too many braindead repository copy-pastes annihilating
+ * git history to trust people to be able to find this code in case their
+ * legacy system suddenly stops working and I don't want to deal with the
+ * flak I could be getting for it. In a year or two (unless somebody patches
+ * system-popup to add MalfurionNotifierLaunch or some other good reason
+ * appears) it would be good to get rid of this code though. */
+
+ int ret;
+ char num[10];
+ char _appid[MAX_APPID_LENGTH];
+ GVariant *param;
+
+ /* Launch malfunction system popup */
+ snprintf(num, 10, "%d", count);
+ snprintf(_appid, MAX_APPID_LENGTH, "%s", appid);
+ _D("appid %s, count %d", appid, count);
+
+ param = g_variant_new("(ssssss)", "_SYSPOPUP_CONTENT_",
+ "malfunction_notifier",
+ "_ERRORS_",
+ num,
+ "_APPID_",
+ _appid)
+
+ ret = d_bus_call_method_async_gvariant("org.tizen.system.popup",
+ "/Org/Tizen/System/Popup/System",
+ "org.tizen.system.popup.System",
+ "MalfunctionNotifierLaunch", param);
+ if (ret < 0)
+ _E("Failed to launch MalfunctionNotifier");
+ else
+ _I("MalfunctionNotifierLaunch Success");
+#endif
+}
+
+static int heart_abnormal_report_malfunction(char *name)
+{
+ int ret = -1;
+ char timestr[TIMESTAMP_LEN] = {0,};
+ int milli;
+ char msgid[TIME_MAX_LEN + sizeof '+' + MAX_DEC_SIZE(milli)] = {0,};
+ char ts[TIME_MAX_LEN] = {0,};
+ struct timeval time_of_day;
+ time_t unix_time = time(NULL);
+ struct tm loc_tm;
+
+ if (gettimeofday(&time_of_day, NULL)) {
+ _E("gettimeofday failed");
+ return ret;
+ }
+ if (!localtime_r(&time_of_day.tv_sec, &loc_tm)) {
+ _E("localtime_r failed");
+ return ret;
+ }
+
+ snprintf(timestr, sizeof(timestr), "%.10ld", unix_time);
+ milli = time_of_day.tv_usec / MILLISEC;
+ strftime(ts, TIME_MAX_LEN, "%Y.%m.%d-%H:%M:%S", &loc_tm);
+ snprintf(msgid, sizeof(msgid), "%s+%d", ts, milli);
+
+ ret = d_bus_call_method_async_gvariant("org.tizen.system.crash", "/Org/Tizen/System/Crash/Crash", "org.tizen.system.crash.Crash",
+ "sluggish_dump",
+ g_variant_new("(iisss)", SLUG_TYPE_MALFUN, NOPID, name, timestr, msgid));
+
+ if (ret < 0)
+ _E("Malfunction reporting to sluggish tool failed");
+ return ret;
+}
+
+static void heart_abnormal_process_crashed(GVariant *params)
+{
+ int ret, notify, count;
+ gpointer key, value;
+ time_t curtime, starttime;
+ GHashTableIter hiter;
+ char *process_name = NULL, *exepath = NULL, *appid = NULL, *pkgid = NULL;
+ char info[ABNORMAL_DATA_MAX];
+ struct heart_abnormal_table *table = NULL;
+
+ do_expr_unless_g_variant_get_typechecked(return, params, "(&s&s&s&ssiia{sv})", &process_name, &exepath, &appid, &pkgid,
+ NULL, NULL, NULL, NULL);
+ if (!process_name || !exepath || !appid || !pkgid) {
+ _E("Failed: dbus_message_get_args()");
+ return;
+ }
+ curtime = time(NULL);
+ starttime = curtime - 604800;
+ if (starttime < 0)
+ starttime = 0;
+
+ if (g_hash_table_size(heart_abnormal_list))
+ g_hash_table_remove_all(heart_abnormal_list);
+
+ logging_read_foreach(ABNORMAL_NAME, appid, NULL, starttime, curtime,
+ heart_abnormal_fill_array, heart_abnormal_list);
+
+ g_hash_table_iter_init(&hiter, heart_abnormal_list);
+
+ count = 0;
+ while (g_hash_table_iter_next(&hiter, &key, &value)) {
+ table = (struct heart_abnormal_table *)value;
+ if (!table)
+ break;
+ count += table->count[FC];
+ }
+
+ notify = 0;
+ if (count > ABNORMAL_CHECK_NUM) {
+ heart_abnormal_launch_popup(appid, count);
+ notify = 1;
+ heart_abnormal_report_malfunction(appid);
+ }
+
+ g_hash_table_remove_all(heart_abnormal_list);
+
+ snprintf(info, sizeof(info), "%s %s %d %d ", process_name, exepath, notify, FC);
+ _D("info : %s %d", info, count);
+ ret = logging_write(PID_FOR_ROOT, ABNORMAL_NAME, appid, pkgid, time(NULL), info);
+ if (ret != RESOURCED_ERROR_NONE)
+ _E("Failed to logging_write %s", info);
+}
+
+static int heart_abnormal_anr(void *data)
+{
+ int ret;
+ char info[ABNORMAL_DATA_MAX];
+ struct proc_status *ps = (struct proc_status *)data;
+ char *appid, *pkgid;
+
+ ret = proc_get_id_info(ps, &appid, &pkgid);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to proc_get_id_info");
+ return ret;
+ }
+ snprintf(info, sizeof(info), "%d ANR %d ", ps->pid, ANR);
+ _D("info : %s", info);
+ ret = logging_write(PID_FOR_ROOT, ABNORMAL_NAME, appid, pkgid, time(NULL), info);
+ if (ret != RESOURCED_ERROR_NONE)
+ _E("Failed to logging_write %s", info);
+ return ret;
+}
+
+static void heart_abnormal_free_value(gpointer value)
+{
+ struct heart_abnormal_table *table =
+ (struct heart_abnormal_table *)value;
+
+ if (!table)
+ return;
+
+ free(table);
+}
+
+static void dbus_heart_get_abnormal_data(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int type = -1, period = -1;
+ int ret, count, i;
+ time_t starttime;
+ char *appid;
+ gpointer key, value;
+ GHashTableIter hiter;
+ struct heart_abnormal_table *table = NULL;
+ GVariantBuilder builder, *sub_builder;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(ii)", &type, &period);
+ if (type < 0 || ABNORMAL_TYPE_MAX < type || period < 0) {
+ _E("Wrong message arguments! %d", type);
+ goto failure;
+ }
+ starttime = time(NULL);
+ switch (period) {
+ case DATA_LATEST:
+ starttime = 0;
+ break;
+ case DATA_3HOUR:
+ starttime -= 10800;
+ break;
+ case DATA_6HOUR:
+ starttime -= 21600;
+ break;
+ case DATA_12HOUR:
+ starttime -= 43200;
+ break;
+ case DATA_1DAY:
+ starttime -= 86400;
+ break;
+ case DATA_1WEEK:
+ starttime -= 604800;
+ break;
+ default:
+ _E("Wrong message arguments! %d", period);
+ goto failure;
+ }
+
+ if (starttime < 0)
+ starttime = 0;
+
+ if (g_hash_table_size(heart_abnormal_list))
+ g_hash_table_remove_all(heart_abnormal_list);
+
+ logging_read_foreach(ABNORMAL_NAME, NULL, NULL, starttime, time(NULL),
+ heart_abnormal_fill_array, heart_abnormal_list);
+
+ ret = pthread_mutex_lock(&heart_abnormal_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ goto failure;
+ }
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(si)"));
+
+ g_hash_table_iter_init(&hiter, heart_abnormal_list);
+ while (g_hash_table_iter_next(&hiter, &key, &value)) {
+ table = (struct heart_abnormal_table *)value;
+ if (!table)
+ break;
+ count = 0;
+ appid = table->appid;
+
+ if (type == ABNORMAL_TYPE_MAX) {
+ for (i = 0; i < ABNORMAL_TYPE_MAX; i++)
+ count += table->count[i];
+ } else
+ count += table->count[type];
+
+ if (!count)
+ continue;
+
+ g_variant_builder_add(sub_builder, "(si)", appid, count);
+ }
+ g_variant_builder_add_value(&builder, g_variant_new("a(si)", sub_builder));
+ g_variant_builder_unref(sub_builder);
+
+ ret = pthread_mutex_unlock(&heart_abnormal_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ goto failure;
+ }
+ g_hash_table_remove_all(heart_abnormal_list);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static const char dbus_methods_xml[] =
+" <method name='GetAbnormalData'>"
+" <arg type='i' name='Type' direction='in'/>"
+" <arg type='i' name='Period' direction='in'/>"
+" <arg type='a(si)' name='CountPerApp' direction='out'/>"
+" </method>";
+
+static struct d_bus_method dbus_methods[] = {
+ { "GetAbnormalData", dbus_heart_get_abnormal_data },
+};
+
+static int heart_abnormal_init(void *data)
+{
+ int ret;
+
+ ret = logging_module_init(ABNORMAL_NAME, ONE_WEEK, HALF_HOUR, NULL, 0, SYSTEM_DEFAULT);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("logging module init failed");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
+
+ ret = d_bus_register_signal(CRASH_PATH_CRASH,
+ CRASH_INTERFACE_CRASH, PROCESS_CRASHED,
+ heart_abnormal_process_crashed, NULL);
+ if (ret < 0)
+ _E("Failed to add a capacity status signal handler");
+ heart_abnormal_list = g_hash_table_new_full(
+ g_str_hash,
+ g_str_equal,
+ NULL,
+ heart_abnormal_free_value);
+
+ register_notifier(RESOURCED_NOTIFIER_APP_ANR, heart_abnormal_anr);
+ _D("heart abnormal init finished");
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_abnormal_exit(void *data)
+{
+ if (heart_abnormal_list)
+ g_hash_table_destroy(heart_abnormal_list);
+ logging_module_exit();
+ unregister_notifier(RESOURCED_NOTIFIER_APP_ANR, heart_abnormal_anr);
+ _D("heart abnormal exit");
+ return RESOURCED_ERROR_NONE;
+}
+
+static const struct heart_module_ops heart_abnormal_ops = {
+ .name = "ABNORMAL",
+ .init = heart_abnormal_init,
+ .exit = heart_abnormal_exit,
+};
+HEART_MODULE_REGISTER(&heart_abnormal_ops)
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * @file heart-battery.c
+ *
+ * @desc heart battery module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <sqlite3.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <math.h>
+#include <device/display.h>
+#include <device/callback.h>
+#include <system_info.h>
+
+#include "proc-common.h"
+#include "notifier.h"
+#include "resourced.h"
+#include "dbus-handler.h"
+#include "heart.h"
+#include "logging.h"
+#include "heart-common.h"
+#include "config-parser.h"
+#include "trace.h"
+#include "vconf.h"
+#include "module.h"
+#include "macro.h"
+#include "util.h"
+#include "file-helper.h"
+
+#define TIZEN_SYSTEM_APPID "org.tizen.system"
+#define TIZEN_SYSTEM_BATTERY_APPID "org.tizen.system.battery.capacity"
+#define BATTERY_NAME "battery"
+#define BATTERY_DATA_MAX 1024
+#define BATTERY_CAPACITY_MAX 512
+#define BATTERY_LINE_MAX 128
+#define BATTERY_CLEAN_MAX 100
+#define BATTERY_HISTORY_DAY_MAX 7
+#define BATTERY_HISTORY_RESET_MAX 5
+#define BATTERY_HISTORY_RESET_CURRENT (BATTERY_HISTORY_RESET_MAX - 1)
+#define BATTERY_HISTORY_COUNT_MAX 1000
+#define HEART_BATTERY_UPDATE_INTERVAL HALF_HOUR
+#define HEART_BATTERY_SAVE_INTERVAL HALF_HOUR
+#define HEART_BATTERY_CAPACITY_DATA_FILE HEART_FILE_PATH"/.battery_capacity.dat"
+#define HEART_BATTERY_CONF_SECTION "BATTERY_POWER_MODE"
+#define GET_CHARGER_STATUS "ChargerStatus"
+#define GET_BATTERY_CAPACITY "GetPercent"
+#define CALCULATE_DAY_BASE_TIME(x) ((x / DAY_TO_SEC(1)) * (DAY_TO_SEC(1)))
+#define REMAIN_CAPACITY(x) (100 - x)
+#define BATTERY_PREDICTION_DATA_MIN 5
+#define BATTERY_USAGE_LEARNING -1
+#define CUMUL_WEIGHT (0.8)
+#define TREND_WEIGHT (1 - CUMUL_WEIGHT)
+#define DISCHARGE_BASE_RATE (0.2)
+
+/*
+ * BATTERY_PREDICTION_LATEST_COUNT must be >= BATTERY_PREDICTION_DATA_MIN
+ */
+#define BATTERY_PREDICTION_LATEST_COUNT 5
+/*
+ * BATTERY_PREDICTION_PERIOD possible values:
+ * DATA_LATEST, DATA_3HOUR, DATA_6HOUR, DATA_12HOUR, DATA_1DAY
+ */
+#define BATTERY_PREDICTION_PERIOD DATA_3HOUR
+
+#define BATTERY_USED_TIME "BATTERY_USED_TIME"
+#define BATTERY_STATUS "BATTERY_STATUS"
+#define BATTERY_RESET_USAGE "BATTERY_RESET_USAGE"
+#define BATTERY_WEEK_DAY_USAGE "BATTERY_WEEK_DAY_USAGE"
+#define BATTERY_LEVEL_USAGE "BATTERY_LEVEL_USAGE"
+#define BATTERY_PREDICTION "BATTERY_PREDICTION"
+
+#define INDEX_WINDOW_SIZE 10 /*data storing index*/
+#define BATTERY_LEVEL_GAP 5 /*previous 5 battery data*/
+#define LONG_TIME_WEIGHT (0.7) /*weightage given for longer time discharge*/
+#define SHORT_TIME_WEIGHT (1-LONG_TIME_WEIGHT) /*weightage given for short time discharge*/
+#define NEW_PIVOT_WEIGHTAGE(x) (x * 0.10) /* x/10th part */
+#define OLD_PIVOT_WEIGHTAGE(x) (1.0 - NEW_PIVOT_WEIGHTAGE(x))
+#define MIN_DISCHARGE_PERIOD 40
+#define LOW_CAPACITY 2
+#define MIN_TIME_FOR_LVL_CHANGE 50
+#define BATT_CHG_FLUSH_DATA 10
+
+/*
+ * Below 6 values are the co-efficient of the polynomial. These are devired from
+ * OCV and and battery percentage level based on experiment
+ */
+#define OCV_SOC_POLY_COEF_1 (3402.664)
+#define OCV_SOC_POLY_COEF_2 (42.031)
+#define OCV_SOC_POLY_COEF_3 (-1.76745)
+#define OCV_SOC_POLY_COEF_4 (0.034798)
+#define OCV_SOC_POLY_COEF_5 (-0.00030516)
+#define OCV_SOC_POLY_COEF_6 (0.0000010116)
+#define UPS_FACTOR (2.88)
+#define DOUBLE_ZERO (0.000000)
+#define FULL_CAPACITY 100
+/* BATTERY_C_RATE is defined as the rate of which battery capacity is changing
+ * If total battery capacity is XmAh, then in one second battery capacity change
+ * will be considered as 90
+ */
+#define BATTERY_C_RATE 90
+#define SEC_TO_MIN(x) ((x + 30)/60) /* 30 secs buffer to round off */
+#define CAL_MIN(x, y) ((x < y) ? x : y)
+#define BATTERY_WINDOW_INDEX(x) (((x) + INDEX_WINDOW_SIZE) % INDEX_WINDOW_SIZE)
+#define HEART_BATTERY_DATA_FILE HEART_FILE_PATH"/.battery_data.dat"
+#define HEART_BATTERY_PIVOT_INFO HEART_FILE_PATH"/.battery_pivot_data.dat"
+#define VCONFKEY_HEART_BATTERY_DEVICE_MODE "db/setting/psmode"
+#define VCONFKEY_SETAPPL_MANAGE_BATTERY_TRIGGER_TIME "db/setting/manage_battery_trigger_time"
+
+/*
+ * Remaining Useful Life prediction logic
+ */
+#define RUL_DATA_FILE HEART_FILE_PATH"/.rul_data.dat"
+#define RUL_CHARGING_CYCLES_FILE HEART_FILE_PATH"/.charging_cycles.dat"
+#define RUL_MIN_CAPACITY_DIFF 50
+#define RUL_DISPLAY_ON_CUTOFF_RATIO 0.1f
+#define RUL_DATA_SIZE 32
+
+enum {
+ TA = 0, /* prediction based on total data average */
+ PCB = 1, /* prediction with physiological behaviors */
+ WEEK = 2, /* prediction based on weekly data */
+ COUNT = 3, /* prediction based on last BATTERY_PREDICTION_COUNT number of items */
+ PERIOD = 4, /* prediction based on data from last BATTERY_PREDICTION_PERIOD time */
+ MAX_STRATEGY = 5,
+};
+
+enum {
+ POWER_NORMAL_MODE = 0,
+ POWER_SAVING_MODE = 1,
+ ULTRA_SAVING_MODE = 2,
+ POWER_MODE_MAX = 3,
+};
+
+enum {
+ BATTERY_LEVEL_LOW = 0, /* 15 ~ 0 */
+ BATTERY_LEVEL_MID = 1, /* 49 ~ 16 */
+ BATTERY_LEVEL_HIGH = 2, /* 50 ~ 100 */
+ BATTERY_LEVEL_MAX = 3,
+};
+
+enum {
+ DEFAULT_MIN = 0,
+ DEFAULT_AVG = 1,
+ DEFAULT_MAX = 2,
+ DEFAULT_VALUE_MAX = 3,
+};
+
+/* Structure to calculate percentage time LCD on during charging */
+struct rul_lcd_data {
+ display_state_e state;
+ long on_time;
+ long on_start_time;
+ long on_stop_time;
+};
+
+/* Structure to store RUL related charging info */
+struct rul_info {
+ long charging_start_time;
+ long charging_stop_time;
+ float raw_capacity; /* capacity (mAh) accumulation during charging */
+ int soc_start; /* SoC(%) value when charging starts */
+ int soc_stop; /* SoC(%) value when charging stops */
+ int charging_cycles; /* Number of charging cycles */
+ int curr_soc; /* Current SoC %, compare with prev_soc to determine if charging */
+ int prev_soc; /* Previous value of SoC % */
+ struct rul_lcd_data lcd_data; /* LCD related data */
+};
+
+struct battery_used {
+ time_t used_time_sec; /* seconds on battery */
+ time_t last_update_time;
+ int last_charger_status;
+};
+
+struct battery_usage {
+ time_t start_time; /* timestamp when event started */
+ long sec_per_cap[MAX_CHARGER_STATE]; /* seconds per capacity level change */
+ long cap_counter[MAX_CHARGER_STATE]; /* number of capacity level changes */
+};
+
+struct battery_prediction {
+ long sec_per_cap[MAX_STRATEGY]; /* seconds per capacity level change */
+ long cap_counter[MAX_STRATEGY]; /* number of capacity level changes */
+ long time_pred_min[MAX_STRATEGY]; /* time prediction in minutes */
+};
+
+struct battery_pivot_info {
+ long start_time_dischg; /* store the time from when discharge started */
+ int pvt_data_ind; /* index to keep track of total_dischg_time value */
+ int start_cap_dischg; /* capacity from when discharge started */
+ int total_dischg_time[INDEX_WINDOW_SIZE]; /* total discharge period */
+ time_t last_clock_tick; /* last tick stored */
+};
+
+struct battery_status {
+ /* current battery status */
+ enum charger_status_type curr_charger_status;
+ int curr_capacity;
+
+ enum discharge_rate_level_type discharge_rate_level;
+ /* current runtime statistics */
+ long curr_run_time_sec[MAX_CHARGER_STATE]; /* seconds since reset */
+ long curr_cap_counter[MAX_CHARGER_STATE]; /* capacity level changes */
+
+ long last_wall_time[INDEX_WINDOW_SIZE]; /* previous battery level discharge time */
+ /* previous battery level change time in charging mode */
+ long last_wall_time_chg;
+ /* charging data index*/
+ int index_chg;
+ /* store last 5 battery level change time diff */
+ int last_wall_time_chg_diff[BATTERY_LEVEL_GAP];
+ /* indicates whether do we have enough data to estimate the battery time */
+ int data_available;
+ int curr_index; /* store current index value */
+ int last_capacity; /* last battery capacity value */
+ int last_capacity_chg; /* last battery capacity value in charge mode */
+ int remaining_time; /* previous remaining time */
+ int remaining_time_chg; /* previous remaining time in charging mode */
+ int remaining_time_ups; /* previous remaining time in UPS */
+ double last_volt_intg[INDEX_WINDOW_SIZE]; /* store previous calculated voltage integral(energy) value */
+ double last_pwr_bchg; /* store the battery power available just before charging start */
+
+ /* wall clock time stamp when last event happened in seconds */
+ time_t last_event_wall_time;
+ time_t last_clock_tick;
+
+ /*
+ * reset mark is set when battery is charged in over 90% and
+ * charger was disconnected from the device.
+ * We consider then the device as "charged"
+ *
+ * The possible values are 0 and 1 they're swapped to opposite on change.
+ */
+ int reset_mark;
+ time_t reset_mark_timestamp;
+
+ /* usage time from last reset_mark change*/
+ struct battery_usage batt_reset_usage[BATTERY_HISTORY_RESET_MAX];
+
+ /* usage time by week day */
+ struct battery_usage week_day_usage[BATTERY_HISTORY_DAY_MAX];
+
+ /* usage time by user behavior & battery level */
+ struct battery_usage batt_lvl_usage[BATTERY_LEVEL_MAX];
+
+ /* calculated battery prediction */
+ struct battery_prediction prediction[MAX_CHARGER_STATE];
+
+ /* battery pivot information */
+ struct battery_pivot_info pvt;
+};
+
+static int default_sec_per_cap[MAX_CHARGER_STATE][DEFAULT_VALUE_MAX] = {
+ { 70, 670, 3600 }, /* DISCHARGING MIN: 70s, AVG: 670s, MAX: 1 hour */
+ { 30, 80, 3600 } /* CHARGING MIN: 30s, AVG: 80s, MAX: 1 hour */
+};
+
+static double default_mode_spc[POWER_MODE_MAX] = {
+ 670, /* POWER_NORMAL_MODE */
+ 750, /* POWER_SAVING_MODE */
+ 1947 /* ULTRA_SAVING_MODE */
+};
+
+static double default_mode_factor[POWER_MODE_MAX] = {
+ 1, /* POWER_NORMAL_MODE */
+ 1.1, /* POWER_SAVING_MODE */
+ 2.88 /* ULTRA_SAVING_MODE */
+};
+
+struct heart_power_profile {
+ float wifi_on;
+ float wifi_active;
+ float wifi_scan;
+};
+
+static struct heart_power_profile power_profile;
+#ifdef NETWORK_SUPPORT
+static struct heart_calc_time calc_time;
+#endif
+static struct battery_used batt_used;
+static struct battery_status batt_stat;
+static GSList *capacity_history_list = NULL;
+static pthread_mutex_t heart_battery_mutex = PTHREAD_MUTEX_INITIALIZER;
+static time_t last_file_commit_time;
+static int battery_learning_mode;
+
+static int ocv_degree; /* Degree of the OCV and SOC polynomial */
+static double *intg; /* Co-efficients of the OCV and SOC polynomial */
+static double pivot_nor; /* time pivot for normal mode */
+static double pivot_ups; /* time pivot for UPS mode */
+static double volt_intg_full; /* 100% battery voltage integral(engery) value */
+static bool data_avail_chg = false; /* 5 readings in charging mode */
+ /*
+ * variable to hold the current device mode(NORMAL, PS & UPS)
+ */
+static int device_mode = POWER_NORMAL_MODE;
+
+static int heart_battery_direct_get_capacity(void);
+
+/*
+ * Given the 'SOC', remaining energy of the cell can be predicted. New battery
+ * remaining time estimation logic will calculating the remaining energy as
+ * 'curr_volt_intg'.
+ *
+ * Based on estimated average power(P), a time estimate can be calcluated.
+ * Power can be estimated based on constant SOC interval Ps and constant
+ * time interval Pt.
+ *
+ * At high usage Ps will be short term average power and Pt will be long term
+ * average power.
+ *
+ * At low usage Ps will be long term average power and Pt will be short term
+ * average power.
+ *
+ * The new logic will calculate the average power 'batt_pwr' from Ps and Pt.
+ *
+ * Under-relaxation is a popular and effective technique of stabilizing prediction.
+ * The predicted time is stabilized around a pivot, which is calculated from the
+ * high-usage time and low-usage time
+ *
+ * The new logic will calculated 'pivot_nor' and 'pivot_ups' for normal and UPS
+ * mode respectively
+ *
+ * Finally, using current available energy(curr_volt_intg), average power(batt_pwr)
+ * and pivot time (pivot_nor or pivot_ups) this new logic will estimate the Battery
+ * Remaining Time for normal mode and UPS mode
+ */
+/*
+ * new battery remaining time estimation logic
+ */
+static int logic_v2;
+/*
+ * Total time taken in minutes when device is discharging at fastest rate
+ */
+static int discharge_fast;
+/*
+ * Total time taken in minutes when device is discharging at slowest rate
+ */
+static int discharge_slow;
+/*
+ * Avarage power consumed in UPS mode
+ */
+static double average_pwr;
+/*
+ * Total battery capacity in minutes(mAM)
+ */
+static int total_battery_capacity;
+/*
+ * This variable indicates first battery level update after charger insert
+ */
+static bool first_level_change = FALSE;
+/*
+ * This variable indicates the battery header used in heart.conf file
+ */
+static char battery_header[BATTERY_LINE_MAX] = "BATTERY";
+
+/*
+ * Remaining Useful Life (RUL) prediction logic
+ */
+static int logic_rul;
+struct rul_info rul;
+
+static int get_battery_remaining_time(int mode, enum charger_status_type status);
+
+int heart_battery_get_capacity(void)
+{
+ return batt_stat.curr_capacity;
+}
+
+enum charger_status_type heart_battery_get_charger_status(void)
+{
+ return batt_stat.curr_charger_status;
+}
+
+static inline void heart_battery_set_usage_reset_stime(int history, time_t start_time)
+{
+ batt_stat.batt_reset_usage[history].start_time = start_time;
+}
+
+static inline void heart_battery_set_usage_reset(int history, enum charger_status_type status, long sec_per_cap, long cap_counter)
+{
+ batt_stat.batt_reset_usage[history].sec_per_cap[status] = sec_per_cap;
+ batt_stat.batt_reset_usage[history].cap_counter[status] = cap_counter;
+}
+
+static inline long heart_battery_get_usage_reset_total_time(int history, enum charger_status_type status)
+{
+ return batt_stat.batt_reset_usage[history].sec_per_cap[status] * batt_stat.batt_reset_usage[history].cap_counter[status];
+}
+
+static inline long heart_battery_get_usage_reset_count(int history, enum charger_status_type status)
+{
+ return batt_stat.batt_reset_usage[history].cap_counter[status];
+}
+
+static inline void heart_battery_set_usage_level_stime(int level, time_t start_time)
+{
+ batt_stat.batt_lvl_usage[level].start_time = start_time;
+}
+
+static inline void heart_battery_set_usage_level(int level, enum charger_status_type status, long sec_per_cap, long cap_counter)
+{
+ batt_stat.batt_lvl_usage[level].sec_per_cap[status] = sec_per_cap;
+ batt_stat.batt_lvl_usage[level].cap_counter[status] = cap_counter;
+}
+
+static inline long heart_battery_get_usage_level_total_time(int level, enum charger_status_type status)
+{
+ return batt_stat.batt_lvl_usage[level].sec_per_cap[status] * batt_stat.batt_lvl_usage[level].cap_counter[status];
+}
+
+static inline long heart_battery_get_usage_level_spc(int level, enum charger_status_type status)
+{
+ return batt_stat.batt_lvl_usage[level].sec_per_cap[status];
+}
+
+static inline long heart_battery_get_usage_level_count(int level, enum charger_status_type status)
+{
+ return batt_stat.batt_lvl_usage[level].cap_counter[status];
+}
+
+static inline long heart_battery_get_usage_week_total_time(int day, enum charger_status_type status)
+{
+ return batt_stat.week_day_usage[day].sec_per_cap[status] * batt_stat.week_day_usage[day].cap_counter[status];
+}
+
+static inline long heart_battery_get_usage_week_count(int day, enum charger_status_type status)
+{
+ return batt_stat.week_day_usage[day].cap_counter[status];
+}
+
+static inline void heart_battery_set_usage_week_stime(int day, time_t start_time)
+{
+ batt_stat.week_day_usage[day].start_time = start_time;
+}
+
+static inline time_t heart_battery_get_usage_week_stime(int day)
+{
+ return batt_stat.week_day_usage[day].start_time;
+}
+
+static inline int heart_battery_get_learning_mode(void)
+{
+ int i, count = 0;
+
+ if (logic_v2) { /* new logic */
+ /*wait till enough data gets collected to estimated battery remaining time */
+ if (batt_stat.data_available == TRUE)
+ return 1;
+ return 0;
+ }
+ /* old logic */
+ for (i = 0; i < BATTERY_HISTORY_DAY_MAX; i++) {
+ if (heart_battery_get_usage_week_stime(i))
+ count++;
+ if (count > 1)
+ return 1;
+ }
+ return 0;
+}
+
+static inline void heart_battery_set_usage_week(int day, enum charger_status_type status, long sec_per_cap, long cap_counter)
+{
+ batt_stat.week_day_usage[day].sec_per_cap[status] = sec_per_cap;
+ batt_stat.week_day_usage[day].cap_counter[status] = cap_counter;
+}
+
+static inline void heart_battery_set_prediction(int strategy, enum charger_status_type status, long sec_per_cap, long cap_counter, long pred_min)
+{
+ batt_stat.prediction[status].sec_per_cap[strategy] = sec_per_cap;
+ batt_stat.prediction[status].cap_counter[strategy] = cap_counter;
+ batt_stat.prediction[status].time_pred_min[strategy] = pred_min;
+}
+
+static inline long heart_battery_get_prediction_time(int strategy, enum charger_status_type status)
+{
+ return batt_stat.prediction[status].time_pred_min[strategy];
+}
+
+static inline time_t heart_battery_get_file_commit_timestamp()
+{
+ return last_file_commit_time;
+}
+
+static inline void heart_battery_set_file_commit_timestamp(time_t timestamp)
+{
+ last_file_commit_time = timestamp;
+}
+
+static int heart_battery_calculate_discharge_rate_level(long spc)
+{
+ long gap, total_spc;
+
+ total_spc = batt_stat.prediction[DISCHARGING].sec_per_cap[TA];
+ if (!total_spc)
+ return BATTERY_DISCHARGE_NONE;
+ gap = (total_spc * DISCHARGE_BASE_RATE);
+
+ _I("total: %ld, spc: %ld, gap: %ld", total_spc, spc, gap);
+
+ if (total_spc + gap < spc)
+ return BATTERY_DISCHARGE_LOW;
+ else if (total_spc - gap > spc)
+ return BATTERY_DISCHARGE_HIGH;
+
+ return BATTERY_DISCHARGE_AVG;
+}
+
+static void heart_battery_save_used_time(char *key, struct battery_used *used)
+{
+ assert(key);
+ assert(used);
+
+ logging_leveldb_putv(key, strlen(key), "%d %d ",
+ used->used_time_sec, used->last_update_time);
+};
+
+static void heart_battery_save_status(char *key, struct battery_status *status)
+{
+ assert(key);
+ assert(status);
+
+ logging_leveldb_putv(key, strlen(key), "%d %ld %ld %ld %ld %d %d ",
+ status->curr_capacity,
+ status->curr_run_time_sec[DISCHARGING],
+ status->curr_cap_counter[DISCHARGING],
+ status->curr_run_time_sec[CHARGING],
+ status->curr_cap_counter[CHARGING],
+ status->curr_charger_status,
+ status->reset_mark);
+};
+
+static void heart_battery_save_usage(char *key, struct battery_usage *usage, int total_size)
+{
+ int i, len, num;
+ char buf[BATTERY_DATA_MAX] = {0, };
+
+ assert(key);
+ assert(usage);
+
+ len = 0;
+ num = total_size/sizeof(struct battery_usage);
+ for (i = 0; i < num; i++) {
+ len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%ld %ld %ld %ld %ld ",
+ usage[i].start_time,
+ usage[i].sec_per_cap[DISCHARGING],
+ usage[i].cap_counter[DISCHARGING],
+ usage[i].sec_per_cap[CHARGING],
+ usage[i].cap_counter[CHARGING]);
+ }
+ logging_leveldb_put(key, strlen(key), buf, len);
+};
+
+static void heart_battery_save_prediction(char *key, struct battery_prediction *prediction)
+{
+ int i, len;
+ char buf[BATTERY_DATA_MAX] = {0, };
+
+ assert(key);
+ assert(prediction);
+
+ len = 0;
+ for (i = 0; i < MAX_STRATEGY; i++) {
+ len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%ld %ld %ld %ld %ld %ld ",
+ prediction[DISCHARGING].sec_per_cap[i],
+ prediction[DISCHARGING].cap_counter[i],
+ prediction[DISCHARGING].time_pred_min[i],
+ prediction[CHARGING].sec_per_cap[i],
+ prediction[CHARGING].cap_counter[i],
+ prediction[CHARGING].time_pred_min[i]);
+ }
+ logging_leveldb_put(key, strlen(key), buf, len);
+};
+
+
+static int heart_battery_load_used_time(char *key, struct battery_used *used)
+{
+ int ret;
+ char *token;
+ char buf[BATTERY_DATA_MAX] = {0, };
+ char *saveptr;
+
+ if (!key || !used)
+ return RESOURCED_ERROR_FAIL;
+
+ ret = logging_leveldb_read(key, strlen(key), buf, sizeof(buf));
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to read leveldb key: %s", key);
+ return RESOURCED_ERROR_FAIL;
+ }
+ token = strtok_r(buf, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ used->used_time_sec = atoi(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ used->last_update_time = atoi(token);
+ return RESOURCED_ERROR_NONE;
+};
+
+static int heart_battery_load_status(char *key, struct battery_status *status)
+{
+ int ret;
+ char *token;
+ char buf[BATTERY_DATA_MAX] = {0, };
+ char *saveptr;
+
+ if (!key || !status)
+ return RESOURCED_ERROR_FAIL;
+
+ ret = logging_leveldb_read(key, strlen(key), buf, sizeof(buf));
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to read leveldb key: %s", key);
+ return RESOURCED_ERROR_FAIL;
+ }
+ token = strtok_r(buf, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ status->curr_capacity = atoi(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ status->curr_run_time_sec[DISCHARGING] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ status->curr_cap_counter[DISCHARGING] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ status->curr_run_time_sec[CHARGING] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ status->curr_cap_counter[CHARGING] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ status->curr_charger_status = atoi(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ status->reset_mark = atoi(token);
+ return RESOURCED_ERROR_NONE;
+};
+
+static int heart_battery_load_usage(char *key, struct battery_usage *usage, int total_size)
+{
+ int i, num, ret;
+ char *token;
+ char buf[BATTERY_DATA_MAX] = {0, };
+ char *saveptr;
+
+ if (!key || !usage)
+ return RESOURCED_ERROR_FAIL;
+
+ ret = logging_leveldb_read(key, strlen(key), buf, sizeof(buf));
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to read leveldb key");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (buf[0] == '\0') {
+ _D("There is no history about %s", key);
+ return RESOURCED_ERROR_NONE;
+ }
+
+ i = 0;
+ num = total_size/sizeof(struct battery_usage);
+ token = strtok_r(buf, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ while (token && i++ < num) {
+ usage[i].start_time = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ usage[i].sec_per_cap[DISCHARGING] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ usage[i].cap_counter[DISCHARGING] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ usage[i].sec_per_cap[CHARGING] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ usage[i].cap_counter[CHARGING] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ _D("load [%d] stime: %ld, spc: %ld, count: %ld, spc: %ld, count: %ld",
+ i, usage[i].start_time, usage[i].sec_per_cap[DISCHARGING],
+ usage[i].cap_counter[DISCHARGING], usage[i].sec_per_cap[CHARGING],
+ usage[i].cap_counter[CHARGING]);
+ }
+ return RESOURCED_ERROR_NONE;
+};
+
+static int heart_battery_load_prediction(char *key, struct battery_prediction *prediction)
+{
+ int ret, i;
+ char *token;
+ char buf[BATTERY_DATA_MAX] = {0, };
+ char *saveptr;
+
+ if (!key || !prediction)
+ return RESOURCED_ERROR_FAIL;
+
+ ret = logging_leveldb_read(key, strlen(key), buf, sizeof(buf));
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to read leveldb key: %s", key);
+ return RESOURCED_ERROR_FAIL;
+ }
+ token = strtok_r(buf, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ for (i = 0; i < MAX_STRATEGY && token; i++) {
+ prediction[DISCHARGING].sec_per_cap[i] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ prediction[DISCHARGING].cap_counter[i] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ prediction[DISCHARGING].time_pred_min[i] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ prediction[CHARGING].sec_per_cap[i] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ prediction[CHARGING].cap_counter[i] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("Failed to token value");
+ return RESOURCED_ERROR_FAIL;
+ }
+ prediction[CHARGING].time_pred_min[i] = atol(token);
+ token = strtok_r(NULL, " ", &saveptr);
+ }
+ return RESOURCED_ERROR_NONE;
+};
+
+static void heart_battery_update_used_time(time_t now, enum charger_status_type status)
+{
+ if (batt_used.last_charger_status == DISCHARGING)
+ batt_used.used_time_sec +=
+ now - batt_used.last_update_time;
+ batt_used.last_charger_status = status;
+ batt_used.last_update_time = now;
+ heart_battery_save_used_time(BATTERY_USED_TIME, &batt_used);
+}
+
+static int heart_battery_get_capacity_history_size(void)
+{
+ int size, ret;
+
+ ret = pthread_mutex_lock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ size = g_slist_length(capacity_history_list);
+ if (!size) {
+ _I("capacity history is empty");
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_NONE;
+ }
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return size;
+}
+
+static void heart_battery_insert_capacity(GSList **history_list, int capacity,
+ int diff_capacity, time_t timestamp, long used_time, long charging_time,
+ enum charger_status_type charger_status, int reset_mark, int clear)
+{
+ static int old_reset_mark = 0;
+ GSList *iter, *next;
+ int ret, count;
+ struct heart_battery_capacity *lbc, *tlbc;
+
+ lbc = malloc(sizeof(struct heart_battery_capacity));
+ if (!lbc) {
+ _E("malloc failed");
+ return;
+ }
+ lbc->capacity = capacity;
+ lbc->diff_capacity = diff_capacity;
+ lbc->used_time = used_time;
+ lbc->charging_time = charging_time;
+ lbc->charger_status = charger_status;
+ lbc->reset_mark = reset_mark;
+ lbc->timestamp = timestamp;
+
+ ret = pthread_mutex_lock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ free(lbc);
+ return;
+ }
+ /* clean all history when reset event */
+ if (clear && *history_list && lbc->reset_mark != old_reset_mark) {
+ g_slist_free_full(*history_list, free);
+ *history_list = NULL;
+ }
+
+ /* history reached maximum limitation number */
+ if (*history_list && g_slist_length(*history_list) > BATTERY_CAPACITY_MAX) {
+ count = 0;
+ gslist_for_each_safe(*history_list, iter, next, tlbc) {
+ *history_list = g_slist_remove(*history_list, (gpointer)tlbc);
+ free(tlbc);
+ if (BATTERY_CLEAN_MAX < count++)
+ break;
+ }
+ }
+ old_reset_mark = lbc->reset_mark;
+ *history_list = g_slist_append(*history_list, (gpointer)lbc);
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret)
+ _E("pthread_mutex_unlock() failed, %d", ret);
+}
+
+/* ======================== Serialization/Deserialization ==================== */
+
+static void heart_battery_status_save_to_db(void)
+{
+ heart_battery_save_used_time(BATTERY_USED_TIME, &batt_used);
+ heart_battery_save_status(BATTERY_STATUS, &batt_stat);
+
+ heart_battery_save_usage(BATTERY_RESET_USAGE, batt_stat.batt_reset_usage, sizeof(batt_stat.batt_reset_usage));
+ heart_battery_save_usage(BATTERY_WEEK_DAY_USAGE, batt_stat.week_day_usage, sizeof(batt_stat.week_day_usage));
+ heart_battery_save_usage(BATTERY_LEVEL_USAGE, batt_stat.batt_lvl_usage, sizeof(batt_stat.batt_lvl_usage));
+
+ heart_battery_save_prediction(BATTERY_PREDICTION, batt_stat.prediction);
+}
+
+static int heart_battery_status_read_from_db(void)
+{
+ bool ok = true;
+
+ ok &= (RESOURCED_ERROR_NONE == heart_battery_load_used_time(BATTERY_USED_TIME, &batt_used));
+ ok &= (RESOURCED_ERROR_NONE == heart_battery_load_status(BATTERY_STATUS, &batt_stat));
+
+ ok &= (RESOURCED_ERROR_NONE == heart_battery_load_usage(BATTERY_RESET_USAGE, batt_stat.batt_reset_usage, sizeof(batt_stat.batt_reset_usage)));
+ ok &= (RESOURCED_ERROR_NONE == heart_battery_load_usage(BATTERY_WEEK_DAY_USAGE, batt_stat.week_day_usage, sizeof(batt_stat.week_day_usage)));
+ ok &= (RESOURCED_ERROR_NONE == heart_battery_load_usage(BATTERY_LEVEL_USAGE, batt_stat.batt_lvl_usage, sizeof(batt_stat.batt_lvl_usage)));
+
+ ok &= (RESOURCED_ERROR_NONE == heart_battery_load_prediction(BATTERY_PREDICTION, batt_stat.prediction));
+
+ return ok ? RESOURCED_ERROR_NONE : RESOURCED_ERROR_FAIL;
+}
+
+static int heart_battery_capacity_save_to_file(char *filename)
+{
+ int size, ret, count, len = 0;
+ struct heart_battery_capacity *lbc;
+ GSList *iter, *next;
+ FILE *fp;
+ char buf[BATTERY_DATA_MAX] = {0, };
+
+ if (!capacity_history_list) {
+ _E("capacity history is NULL!");
+ return RESOURCED_ERROR_NONE;
+ }
+ ret = pthread_mutex_lock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ size = g_slist_length(capacity_history_list);
+ if (!size) {
+ _I("capacity history is empty");
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_NONE;
+ }
+ fp = fopen(filename, "w");
+ if (!fp) {
+ _E("%s fopen failed %d", filename, errno);
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_FAIL;
+ }
+ gslist_for_each_item(iter, capacity_history_list) {
+ lbc = (struct heart_battery_capacity *)iter->data;
+ if (!lbc)
+ break;
+ len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%d %d %ld %ld %ld %d %d\n",
+ lbc->capacity, lbc->diff_capacity, lbc->timestamp, lbc->used_time,
+ lbc->charging_time, lbc->charger_status,
+ lbc->reset_mark);
+ if (BATTERY_DATA_MAX < len + BATTERY_LINE_MAX) {
+ fputs(buf, fp);
+ len = 0;
+ }
+ }
+ fputs(buf, fp);
+ fclose(fp);
+ if (BATTERY_CAPACITY_MAX < size) {
+ count = 0;
+ gslist_for_each_safe(capacity_history_list, iter, next, lbc) {
+ capacity_history_list = g_slist_remove(capacity_history_list, (gpointer)lbc);
+ free(lbc);
+ if (BATTERY_CLEAN_MAX < count++)
+ break;
+ }
+ }
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_battery_capacity_read_from_file(char *filename)
+{
+ int len;
+ int capacity, diff_capacity, charger_status, reset_mark;
+ long used_time, charging_time;
+ time_t timestamp;
+ FILE *fp;
+ char buf[BATTERY_DATA_MAX] = {0, };
+ int ret;
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ if (errno != ENOENT) {
+ _E("Fail to open %s (%d)", buf, errno);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ _D("%s doesn't exist. Make new one.", buf);
+ ret = mkdir(HEART_FILE_PATH, S_IRWXU | S_IRWXG | S_IROTH);
+ if (ret != 0 && errno != EEXIST) {
+ _E("Fail to create %s (%d)", buf, errno);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ fp = fopen(filename, "w+");
+ if (!fp) {
+ _E("Fail to create %s (%d)", buf, errno);
+ return RESOURCED_ERROR_FAIL;
+ }
+ fclose(fp);
+ return RESOURCED_ERROR_NONE;
+ }
+
+ while (fgets(buf, BATTERY_DATA_MAX, fp)) {
+ len = sscanf(buf, "%d %d %ld %ld %ld %d %d", &capacity, &diff_capacity,
+ ×tamp, &used_time, &charging_time,
+ &charger_status, &reset_mark);
+ if (len < 0) {
+ _E("sscanf failed");
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ heart_battery_insert_capacity(&capacity_history_list, capacity, diff_capacity,
+ timestamp, used_time, charging_time,
+ charger_status, reset_mark, true);
+ }
+ fclose(fp);
+ return RESOURCED_ERROR_NONE;
+}
+
+/* ==================== Serialization/Deserialization END ==================== */
+
+static void heart_battery_save_to_file(bool force)
+{
+ int ret;
+ time_t now = logging_get_time(CLOCK_BOOTTIME);
+
+ heart_battery_update_used_time(now, batt_stat.curr_charger_status);
+
+ if (!force &&
+ heart_battery_get_file_commit_timestamp() + HEART_BATTERY_SAVE_INTERVAL >= now)
+ return;
+
+ heart_battery_status_save_to_db();
+
+ ret = heart_battery_capacity_save_to_file(HEART_BATTERY_CAPACITY_DATA_FILE);
+ if (ret)
+ _E("failed to save capacity file");
+ heart_battery_set_file_commit_timestamp(now);
+}
+
+/*
+ * This function will open the '.battery_data.dat' file and write all battery
+ * related data into it.
+ */
+static void heart_battery_write_data_to_file(void)
+{
+ int i;
+ int len = 0;
+ char buff[BATTERY_DATA_MAX] = {0, 0};
+ _cleanup_fclose_ FILE *fp = NULL;
+
+ fp = fopen(HEART_BATTERY_DATA_FILE, "w");
+ if (fp == NULL) {
+ _E("Could not open file battery_data file\n");
+ return;
+ }
+
+ for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+ len += snprintf(buff + len, BATTERY_DATA_MAX - len, "%ld %lf\n", \
+ batt_stat.last_wall_time[i], batt_stat.last_volt_intg[i]);
+
+ if (BATTERY_DATA_MAX < len + BATTERY_LINE_MAX) {
+ fputs(buff, fp);
+ len = 0;
+ }
+ }
+ len += snprintf(buff + len, BATTERY_DATA_MAX - len, "%d %d %d %d %lf %d", \
+ batt_stat.curr_index, batt_stat.last_capacity, batt_stat.remaining_time, \
+ batt_stat.remaining_time_ups, batt_stat.last_pwr_bchg, batt_stat.data_available);
+
+ fputs(buff, fp);
+}
+
+/*
+ * This function will open the '.battery_data.dat' file and read all battery
+ * related data from it and store in variable 'batt_stat'
+ */
+static void heart_battery_read_data_from_file(void)
+{
+ int i;
+ int len = 0;
+ char buff[BATTERY_DATA_MAX] = {0, 0};
+ char *ch;
+ _cleanup_fclose_ FILE *fp = NULL;
+
+ fp = fopen(HEART_BATTERY_DATA_FILE, "r");
+ if (fp == NULL) {
+ _E("Could not open battery_data file\n");
+ return;
+ }
+
+ for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+ ch = fgets(buff, BATTERY_DATA_MAX, fp);
+ if (ch == NULL)
+ /*if file is empty then return from here */
+ return;
+
+ len += sscanf(buff, "%ld %lf", \
+ &batt_stat.last_wall_time[i], &batt_stat.last_volt_intg[i]);
+ }
+
+ ch = fgets(buff, BATTERY_DATA_MAX, fp);
+ if (ch != NULL)
+ len += sscanf(buff, "%d %d %d %d %lf %d", \
+ &batt_stat.curr_index, &batt_stat.last_capacity, &batt_stat.remaining_time, \
+ &batt_stat.remaining_time_ups, &batt_stat.last_pwr_bchg, &batt_stat.data_available);
+}
+
+/*
+ * This function will reject all the battery related data which were stored earlier
+ */
+static void heart_battery_reject_data(void)
+{
+ int i;
+
+ for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+ batt_stat.last_wall_time[i] = 0;
+ batt_stat.last_volt_intg[i] = 0.0;
+ }
+
+ /* Do not reject this, once data available, do not change untill next binary flash */
+ /*batt_stat.data_available = 0; */
+ batt_stat.last_capacity = 0;
+ batt_stat.curr_index = 0;
+ batt_stat.remaining_time = 0;
+ batt_stat.remaining_time_ups = 0;
+ /* do not flush this value. When proper power value is not present, previously
+ calculated power only will be used. */
+ /*batt_stat.last_pwr_bchg = 0.0; */
+
+ heart_battery_write_data_to_file();
+}
+
+/*
+ * This function will calculate the voltage integral(energy) at battery level 100.
+ * We will calculate Pivot using fast discharge and slow discharge rate for
+ * estimating the battery time in normal mode
+ */
+static void heart_battery_calculate_pivot(void)
+{
+ int i;
+
+ for (i = 0; i < ocv_degree; i++)
+ volt_intg_full += (intg[i] /(i+1)) * pow(100 , i+1);
+ volt_intg_full = volt_intg_full/100000.0;
+
+ pivot_nor = ((sqrt(discharge_fast) + sqrt(discharge_slow))/2);
+ pivot_nor = pivot_nor * pivot_nor; // taking square of Tpivot
+
+ pivot_ups = ((sqrt(discharge_fast*UPS_FACTOR) + sqrt(discharge_slow*UPS_FACTOR))/2);
+ pivot_ups = pivot_ups * pivot_ups; // taking square of Tpivot
+}
+
+/* function to return the time(in seconds) since the Epoch*/
+static long heart_battery_logging_get_time_sec_new(void)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ return (tv.tv_sec + tv.tv_usec / 1000000);
+}
+
+/*
+ * This function will read the current time and will compare with previously stored time.
+ * If time difference is more then it is assumed that device was powered off and it will
+ * adjust all stored time values
+ */
+static void heart_battery_power_off_time_adjustment(void)
+{
+ int i;
+ int index;
+ int clock_tick_diff = 0;
+ long int curr_time;
+ long int time_diff = 0;
+
+ curr_time = heart_battery_logging_get_time_sec_new();
+
+ index = BATTERY_WINDOW_INDEX(batt_stat.curr_index - 1);
+ if (batt_stat.last_wall_time[index] == 0)
+ index = 0;
+
+ clock_tick_diff = logging_get_time(CLOCK_BOOTTIME) - batt_stat.last_clock_tick;
+
+ /* check if we have store last time value or not */
+ if (batt_stat.last_wall_time[index] != 0) {
+ time_diff = curr_time - batt_stat.last_wall_time[index];
+ time_diff -= clock_tick_diff;
+ }
+
+ _I("All store time value will be scaled up by %ld secs\n", time_diff);
+
+ /*scale up all stored time value */
+ for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+ if (batt_stat.last_wall_time[i] == 0) {
+ /* we do not have stored time value from this point onwards, stop updating*/
+ break;
+ } else
+ batt_stat.last_wall_time[i] += time_diff;
+ }
+
+ /* update same value in battery data file*/
+ heart_battery_write_data_to_file();
+
+ /*
+ * during charge time
+ */
+ time_diff = curr_time - batt_stat.last_wall_time_chg;
+ time_diff -= clock_tick_diff;
+ /*
+ * update last_wall_time_chg as per previous and new time diff
+ * it will take care of positive of negative difference
+ */
+ batt_stat.last_wall_time_chg += time_diff;
+ _I("last_wall_time_chg got updated by %ld\n", time_diff);
+ /*
+ * make first_level_change as TRUE so that charge remaining time
+ * should not vary much
+ */
+ first_level_change = TRUE;
+
+ /* for pivot data */
+ if (batt_stat.pvt.start_time_dischg != 0) {
+ time_diff = curr_time - batt_stat.pvt.start_time_dischg;
+ clock_tick_diff = logging_get_time(CLOCK_BOOTTIME) - batt_stat.pvt.last_clock_tick;
+ time_diff -= clock_tick_diff;
+ batt_stat.pvt.start_time_dischg += time_diff;
+ }
+}
+
+/*
+ * In case of any time change in the device, this callback get called and it
+ * will do the time adjustment
+ */
+static void time_change_notify_cb(keynode_t *key, void *data)
+{
+ heart_battery_power_off_time_adjustment();
+}
+
+static int get_battery_remaining_time_new(void)
+{
+ return batt_stat.remaining_time;
+}
+
+static int get_battery_remaining_time_ups()
+{
+ return batt_stat.remaining_time_ups;
+}
+
+/*
+ * This function will return the average of stored time diff values
+ */
+static int heart_battery_get_time_diff_avg(int time_diff_avg)
+{
+ int temp_index;
+ int i;
+
+ if (data_avail_chg == true) {
+ /*
+ * calculate the average of last 5(including current) time diff values
+ */
+ temp_index = ((batt_stat.index_chg-1) + BATTERY_LEVEL_GAP) % BATTERY_LEVEL_GAP;
+ for (i = 1; i < BATTERY_LEVEL_GAP; i++) {
+ time_diff_avg += batt_stat.last_wall_time_chg_diff[temp_index];
+ temp_index = ((temp_index-1) + BATTERY_LEVEL_GAP) % BATTERY_LEVEL_GAP;
+ }
+ time_diff_avg = time_diff_avg/BATTERY_LEVEL_GAP;
+ } else {
+ /*
+ * take average of only available data. Do not include 1st value so
+ * i stared from 1.
+ */
+ for (i = 1; i < batt_stat.index_chg; i++)
+ time_diff_avg += batt_stat.last_wall_time_chg_diff[i];
+
+ time_diff_avg = time_diff_avg/i;
+ }
+ /*
+ * to minimize the time diff fluctuation
+ */
+ time_diff_avg = (time_diff_avg+BATTERY_C_RATE)/2;
+ _I("time_diff after averaging= %d seconds\n", time_diff_avg);
+
+ return time_diff_avg;
+}
+
+/*
+ * This function will return the time diff between last and current battery
+ * level change
+ */
+int heart_battery_get_time_diff(long curr_wall_time)
+{
+ if (batt_stat.last_wall_time_chg == 0)
+ /*
+ * First time estimation
+ * In this case charge rate will be considered as time diff
+ */
+ return BATTERY_C_RATE;
+
+ return (curr_wall_time - batt_stat.last_wall_time_chg);
+}
+
+static void heart_battery_print_prev_charge_data(void)
+{
+ int i;
+
+ _I("Charging stored data, current index = %d", batt_stat.index_chg);
+
+ for (i = 0; i < BATTERY_LEVEL_GAP; i++)
+ _I("Index = %d, time_diff = %d", i, batt_stat.last_wall_time_chg_diff[i]);
+}
+
+/*
+ * This function will flush the stored charge data
+ */
+static void heart_battery_flush_charge_data(void)
+{
+ int i;
+
+ _I("Prev and curr battery lvl gap = %d, flush charge data",
+ batt_stat.last_capacity_chg - batt_stat.curr_capacity);
+
+ for (i = 0; i < BATTERY_LEVEL_GAP; i++)
+ batt_stat.last_wall_time_chg_diff[i] = 0;
+
+ batt_stat.last_wall_time_chg = 0;
+ batt_stat.index_chg = 0;
+ data_avail_chg = false;
+}
+
+/*
+ * store the discharge start time and capacity to calculte the
+ * time taken for the discharge period
+ */
+static void heart_battery_collect_discharge_data(void)
+{
+ batt_stat.pvt.start_cap_dischg = batt_stat.curr_capacity;
+ batt_stat.pvt.start_time_dischg = heart_battery_logging_get_time_sec_new();
+ batt_stat.pvt.last_clock_tick = logging_get_time(CLOCK_BOOTTIME);
+}
+
+/*
+ * Read all the stored pivot data from file and keep it in
+ * local variable batt_stat.pvt
+ */
+static void heart_battery_read_pivot_info_from_file(void)
+{
+ int i;
+ char buf[BATTERY_DATA_MAX] = {0, };
+ char *p;
+ _cleanup_fclose_ FILE *fp = NULL;
+
+ fp = fopen(HEART_BATTERY_PIVOT_INFO, "r");
+ if (fp == NULL) {
+ _E("Could not open pivot info file");
+ return;
+ }
+
+ for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+ p = fgets(buf, BATTERY_DATA_MAX, fp);
+ if (p == NULL)
+ return;
+
+ if (sscanf(buf, "%d", &batt_stat.pvt.total_dischg_time[i]) == -1)
+ return;
+ }
+
+ p = fgets(buf, BATTERY_DATA_MAX, fp);
+ if (!p)
+ return;
+ if (sscanf(buf, "%d", &batt_stat.pvt.pvt_data_ind) == -1)
+ return;
+
+}
+
+/*
+ * Store all the local pivot data to a file
+ */
+static void heart_battery_save_pivot_info(void)
+{
+ int len = 0;
+ int i;
+ char buf[BATTERY_DATA_MAX] = {0, };
+ _cleanup_fclose_ FILE *fp = NULL;
+
+ fp = fopen(HEART_BATTERY_PIVOT_INFO, "w");
+ if (fp == NULL) {
+ _E("Could not open pivot info file");
+ return;
+ }
+
+ for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+ len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%d\n",
+ batt_stat.pvt.total_dischg_time[i]);
+
+ if (BATTERY_DATA_MAX < len + BATTERY_LINE_MAX) {
+ fputs(buf, fp);
+ len = 0;
+ }
+ }
+ len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%d",
+ batt_stat.pvt.pvt_data_ind);
+
+ fputs(buf, fp);
+}
+
+/*
+ * Calculate the remaining enery in battery based on current capacity
+ */
+static double heart_battery_get_energy(int capacity)
+{
+ int i;
+ double volt_intg = 0;
+
+ for (i = 0; i < ocv_degree; i++)
+ volt_intg += (intg[i] /(i+1)) * pow(capacity , i+1);
+
+ return (volt_intg /100000.0);
+}
+
+/*
+ * Update the pivot based on device learning data
+ */
+static void heart_battery_update_pivot(void)
+{
+ int i;
+ int avg = 0;
+
+ static int count = 1;
+
+ for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+ if(batt_stat.pvt.total_dischg_time[i] == 0)
+ break;
+ avg += batt_stat.pvt.total_dischg_time[i];
+ }
+
+ if (avg == 0)
+ return;
+ if (i != 0)
+ avg = (avg / i);
+
+ /*
+ * Total 10 discharge cycle data will be stored and based on those values
+ * new pivot will be calculted. Untill 10 cycles data are not available, take
+ * count/10 % from new pivot and 1-count/10 % from existing pivot. By
+ * doing this, sudden jump in pivot can be avoided
+ */
+ if (count <= 10) {
+ avg = NEW_PIVOT_WEIGHTAGE(count) * avg + OLD_PIVOT_WEIGHTAGE(count) * pivot_nor;
+ count++;
+ }
+
+ _I("Old pivot = %lf, New pivot =%d, count = %d", pivot_nor, avg, count);
+
+ pivot_nor = avg;
+ pivot_ups = pivot_nor * UPS_FACTOR;
+}
+
+/*
+ * This function will take the average of last 10 discharge time period and
+ * update the pivot
+ */
+static void heart_battery_collect_pivot_info(void)
+{
+ long curr_time;
+ int time_diff;
+ int cap_diff;
+ int total_time;
+
+ double energy_dis;
+ double energy_chg;
+ double energy_total;
+
+ if (batt_stat.pvt.start_time_dischg == 0)
+ return;
+
+ curr_time = heart_battery_logging_get_time_sec_new();
+ time_diff = curr_time - batt_stat.pvt.start_time_dischg;
+ cap_diff = batt_stat.pvt.start_cap_dischg - batt_stat.curr_capacity;
+
+ /* discharge period is too less so do not consider this period */
+ if (cap_diff < MIN_DISCHARGE_PERIOD)
+ return;
+
+ energy_dis = heart_battery_get_energy(batt_stat.pvt.start_cap_dischg);
+ energy_chg = heart_battery_get_energy(batt_stat.curr_capacity);
+ energy_total = heart_battery_get_energy(FULL_CAPACITY);
+
+ total_time = (energy_total * time_diff) /(energy_dis - energy_chg);
+
+ _I("Energy discharge = %lf, Energy charge = %lf, Energy Total = %lf, Total time = %d",
+ energy_dis, energy_chg, energy_total, total_time);
+
+ batt_stat.pvt.total_dischg_time[batt_stat.pvt.pvt_data_ind] = SEC_TO_MIN(total_time);
+ batt_stat.pvt.pvt_data_ind = (batt_stat.pvt.pvt_data_ind + 1) % INDEX_WINDOW_SIZE;
+
+ /* update the pivot */
+ heart_battery_update_pivot();
+ /* save pivot info into file */
+ heart_battery_save_pivot_info();
+}
+
+/*
+ * This function will calculate the battery charging remaining time
+ */
+static void heart_battery_cal_charging_rem_time(void)
+{
+ long curr_wall_time = 0;
+ int rem_time;
+ int time_diff;
+ int time_diff_avg;
+ double temp_cv;
+
+ if (batt_stat.last_capacity_chg == batt_stat.curr_capacity) {
+ _I("Last capacity %d is same as current capacity %d\n",
+ batt_stat.last_capacity_chg, batt_stat.curr_capacity);
+ return;
+ }
+
+ curr_wall_time = heart_battery_logging_get_time_sec_new();
+
+ time_diff = heart_battery_get_time_diff(curr_wall_time);
+
+ /*
+ * just after inserting the charger, if time diff between two level
+ * is less than MIN_TIME_FOR_LVL_CHANGE value then consider time diff
+ * as BATTERY_C_RATE so that there will not be sudden fall in charge
+ * remaining time
+ */
+ if (time_diff < MIN_TIME_FOR_LVL_CHANGE && first_level_change == TRUE) {
+ /*
+ * first_level_change will be set to TRUE in function
+ * heart_battery_charger_status() and set to FALSE in function
+ * heart_battery_capacity_status()
+ */
+ _I("time diff %d is less than min value of lvl change %d\n",
+ time_diff, MIN_TIME_FOR_LVL_CHANGE);
+ time_diff = BATTERY_C_RATE;
+ }
+
+ _I("data_avail_chg = %d, index_chg = %d\n",
+ data_avail_chg, batt_stat.index_chg);
+ _I("last_wall_time_chg = %ld, curr_wall_time = %ld\n",
+ batt_stat.last_wall_time_chg, curr_wall_time);
+ _I("time diff before averaging = %d seconds\n", time_diff);
+
+ /*
+ * get the average of all time diff values stored including current
+ */
+ time_diff_avg = heart_battery_get_time_diff_avg(time_diff);
+
+ if (time_diff_avg > BATTERY_C_RATE && batt_stat.curr_capacity <= 30)
+ time_diff_avg = BATTERY_C_RATE;
+
+ if (batt_stat.curr_capacity == FULL_CAPACITY) {
+ batt_stat.remaining_time_chg = 0;
+ } else {
+ /*
+ * calculate the remaining charge time based on constant current
+ * and constant votlage(CCCV) logic. 'time_diff_avg' is for CC and
+ * 'temp_cv' is for CV part.
+ */
+ temp_cv = ((double)time_diff_avg)/((double)BATTERY_C_RATE);
+ temp_cv = temp_cv * temp_cv;
+ rem_time = (time_diff_avg + temp_cv)*(FULL_CAPACITY - batt_stat.curr_capacity);
+ batt_stat.remaining_time_chg = SEC_TO_MIN(rem_time);
+ }
+
+ batt_stat.last_wall_time_chg = curr_wall_time;
+ batt_stat.last_wall_time_chg_diff[batt_stat.index_chg] = time_diff;
+ batt_stat.index_chg = (batt_stat.index_chg+1)%BATTERY_LEVEL_GAP;
+ batt_stat.last_capacity_chg = batt_stat.curr_capacity;
+ batt_stat.last_clock_tick = logging_get_time(CLOCK_BOOTTIME);
+
+ _I("Capacity = %d, charging remaining time = %d minutes\n",
+ batt_stat.curr_capacity, batt_stat.remaining_time_chg);
+
+ if (batt_stat.index_chg+1 == BATTERY_LEVEL_GAP)
+ data_avail_chg = true;
+}
+
+/*
+ * This function will calculate the battery estimation time for every battery
+ * level change
+ */
+static void heart_battery_cal_discharge_rem_time(void)
+{
+ double curr_volt_intg = 0;
+ double volt_intg_diff = 0;
+ double ps, pt;
+ double batt_pwr;
+ int rem_time = 0;
+ int index = 0;
+ int temp_index = 0;
+ int index_count;
+ int i;
+ int update_time;
+ long curr_wall_time = 0;
+ long time_diff1, time_diff2;
+
+ _I("last capacity = %d, current capacity = %d\n", batt_stat.last_capacity, batt_stat.curr_capacity);
+
+ /* if battery level change happen then only calculate the new time*/
+ if (batt_stat.last_capacity != batt_stat.curr_capacity) {
+ /* calculate the voltage integral(energy) for current capacity */
+ for (i = 0; i < ocv_degree; i++)
+ curr_volt_intg += (intg[i] /(i+1)) * pow(batt_stat.curr_capacity , i+1);
+ curr_volt_intg = curr_volt_intg /100000.0;
+
+ /*current time*/
+ curr_wall_time = heart_battery_logging_get_time_sec_new();
+
+ _I("curr_volt_intg = %lf, curr_wall_time = %ld\n", curr_volt_intg, curr_wall_time);
+
+ if (batt_stat.last_capacity < batt_stat.curr_capacity) {
+ /*
+ *this indicates that device was put for charging so need to reject
+ *all the previous data except 'batt_stat.data_available' and
+ *'batt_stat.last_pwr_bchg'. Use last available battery power
+ *before connecting the charger as current average power.
+ */
+ batt_pwr = batt_stat.last_pwr_bchg;
+ heart_battery_reject_data();
+ } else {
+ index = BATTERY_WINDOW_INDEX(batt_stat.curr_index - BATTERY_LEVEL_GAP);
+ if (batt_stat.last_wall_time[index] == 0 &&
+ batt_stat.last_volt_intg[index] == 0) {
+ /*
+ *do not have enough previous data so take 1st stored data
+ *as reference
+ */
+ time_diff1 = curr_wall_time - batt_stat.last_wall_time[0];
+ volt_intg_diff = batt_stat.last_volt_intg[0] - curr_volt_intg;
+ if (volt_intg_diff < DOUBLE_ZERO)
+ volt_intg_diff = volt_intg_full - curr_volt_intg;
+ } else {
+ /* time differenc since last battery level change*/
+ time_diff1 = curr_wall_time - batt_stat.last_wall_time[index];
+ /* voltage integral(energy) change since last battery level change */
+ volt_intg_diff = batt_stat.last_volt_intg[index] - curr_volt_intg;
+ }
+ _I("time_diff1 = %ld, volt_intg_diff = %lf\n", time_diff1, volt_intg_diff);
+
+ time_diff1 = SEC_TO_MIN(time_diff1); /*convert second to minute */
+
+ /* calculate short term average power component*/
+ if (time_diff1 != 0)
+ ps = (total_battery_capacity *volt_intg_diff) / time_diff1;
+ else
+ ps = 0;
+
+ _I("ps = %lf\n", ps);
+
+ /* find the voltage integral(energy) of 1 hr back battery level.
+ 1. Place the index at proper location
+ 2. get the time stored at that index
+ 3. if difference between last time and current time is >= 60 then take that voltage integral
+ */
+ index_count = INDEX_WINDOW_SIZE;
+ time_diff2 = 0;
+ temp_index = BATTERY_WINDOW_INDEX(batt_stat.curr_index - 1);
+ while ((index_count > 0) && (time_diff2 < 60)) {
+ if (batt_stat.last_wall_time[temp_index] == 0)
+ /* data not available so break the loop */
+ break;
+
+ time_diff2 = SEC_TO_MIN(curr_wall_time - batt_stat.last_wall_time[temp_index]);
+ temp_index = BATTERY_WINDOW_INDEX(temp_index - 1);
+ index_count--;
+ }
+
+ /* calculate long term average power component*/
+ if (time_diff2 < 60) {
+ pt = 0;
+ } else {
+ temp_index = BATTERY_WINDOW_INDEX(temp_index + 1);
+ volt_intg_diff = batt_stat.last_volt_intg[temp_index] - curr_volt_intg ;
+ if (volt_intg_diff < DOUBLE_ZERO)
+ pt = 0;
+ else
+ pt = (total_battery_capacity * volt_intg_diff) / time_diff2;
+ }
+
+ _I("time_diff2 = %ld, volt_intg_diff = %lf, pt = %lf\n", time_diff2, volt_intg_diff, pt);
+
+ /* calculate the average power from the short component and long component*/
+ if ((pt + ps) != 0)
+ batt_pwr = (((pt * pt) + (ps * ps)) / (pt + ps));
+ else
+ batt_pwr = batt_stat.last_pwr_bchg;
+ }
+
+ /* total remaining time based on current battery level*/
+ rem_time = (total_battery_capacity * curr_volt_intg) / batt_pwr;
+
+ _I("pivot_nor = %lf, curr_volt_intg = %lf , volt_intg_full %lf, batt_pwr = %lf", pivot_nor, curr_volt_intg, volt_intg_full, batt_pwr);
+
+ /* calculate remaining time for normal mode */
+ update_time = (pivot_nor * curr_volt_intg) / volt_intg_full;
+ batt_stat.remaining_time = (LONG_TIME_WEIGHT * update_time + SHORT_TIME_WEIGHT * CAL_MIN(update_time, rem_time));
+
+ /* calculate remaining time for UPS mode */
+ update_time = (pivot_ups * curr_volt_intg) / volt_intg_full;
+ batt_stat.remaining_time_ups = (LONG_TIME_WEIGHT * update_time + SHORT_TIME_WEIGHT * CAL_MIN(update_time, rem_time));
+
+ _I("normal mode remaining time = %d minutes, ups remaining time = %d minutes\n",
+ batt_stat.remaining_time, batt_stat.remaining_time_ups);
+
+ batt_stat.last_volt_intg[batt_stat.curr_index] = curr_volt_intg;
+ batt_stat.last_wall_time[batt_stat.curr_index] = curr_wall_time;
+ batt_stat.last_capacity = batt_stat.curr_capacity;
+ batt_stat.curr_index = (batt_stat.curr_index + 1) % INDEX_WINDOW_SIZE;
+ batt_stat.last_clock_tick = logging_get_time(CLOCK_BOOTTIME);
+
+ if (batt_pwr > DOUBLE_ZERO) {
+ /*
+ *when battery percentage is 0 then available power will be 0 so
+ *do not store this value. keep previous value only.
+ */
+ batt_stat.last_pwr_bchg = batt_pwr;
+ }
+
+ if (batt_stat.curr_index > BATTERY_LEVEL_GAP) {
+ /*
+ *When enough data to estimate the available battery time are
+ *stored, no need to update the status of batt_stat. data_available
+ *untill we are flashing new binary.
+ */
+ batt_stat.data_available = TRUE;
+ }
+
+ /* save all calculated battery data to file*/
+ heart_battery_write_data_to_file();
+ }
+}
+
+void heart_battery_update(struct logging_table_form *data, void *user_data)
+{
+ heart_battery_save_to_file(false);
+}
+
+static int heart_battery_get_level_usage_index(int capacity)
+{
+ return (capacity > 49) ? BATTERY_LEVEL_HIGH :
+ (capacity < 16) ? BATTERY_LEVEL_LOW : BATTERY_LEVEL_MID;
+}
+
+static int heart_battery_get_week_day_usage_index(time_t timestamp)
+{
+ int i;
+
+ for (i = 0; i < BATTERY_HISTORY_DAY_MAX; i++) {
+ if (!heart_battery_get_usage_week_stime(i))
+ return i;
+ else if (abs(timestamp - heart_battery_get_usage_week_stime(i)) < DAY_TO_SEC(1))
+ return i;
+ }
+ for (i = 0; i < BATTERY_HISTORY_DAY_MAX - 1; i++) {
+ batt_stat.week_day_usage[i].start_time =
+ batt_stat.week_day_usage[i + 1].start_time;
+ batt_stat.week_day_usage[i].sec_per_cap[DISCHARGING] =
+ batt_stat.week_day_usage[i + 1].sec_per_cap[DISCHARGING];
+ batt_stat.week_day_usage[i].sec_per_cap[CHARGING] =
+ batt_stat.week_day_usage[i + 1].sec_per_cap[CHARGING];
+ batt_stat.week_day_usage[i].cap_counter[DISCHARGING] =
+ batt_stat.week_day_usage[i + 1].cap_counter[DISCHARGING];
+ batt_stat.week_day_usage[i].cap_counter[CHARGING] =
+ batt_stat.week_day_usage[i + 1].cap_counter[CHARGING];
+ }
+ return BATTERY_HISTORY_DAY_MAX - 1;
+}
+
+static int heart_battery_get_batt_reset_usage_index(void)
+{
+ int i;
+
+ for (i = 0; i < BATTERY_HISTORY_RESET_MAX; i++) {
+ if (heart_battery_get_usage_reset_count(i, DISCHARGING) < BATTERY_HISTORY_COUNT_MAX
+ && heart_battery_get_usage_reset_count(i, CHARGING) < BATTERY_HISTORY_COUNT_MAX)
+ return i;
+ }
+ for (i = 0; i < BATTERY_HISTORY_RESET_MAX - 1; i++) {
+ batt_stat.batt_reset_usage[i].start_time =
+ batt_stat.batt_reset_usage[i + 1].start_time;
+ batt_stat.batt_reset_usage[i].sec_per_cap[DISCHARGING] =
+ batt_stat.batt_reset_usage[i + 1].sec_per_cap[DISCHARGING];
+ batt_stat.batt_reset_usage[i].sec_per_cap[CHARGING] =
+ batt_stat.batt_reset_usage[i + 1].sec_per_cap[CHARGING];
+ batt_stat.batt_reset_usage[i].cap_counter[DISCHARGING] =
+ batt_stat.batt_reset_usage[i + 1].cap_counter[DISCHARGING];
+ batt_stat.batt_reset_usage[i].cap_counter[CHARGING] =
+ batt_stat.batt_reset_usage[i + 1].cap_counter[CHARGING];
+ }
+ return BATTERY_HISTORY_RESET_CURRENT;
+}
+
+static int heart_battery_reset(void *data)
+{
+ int idx;
+ long total_time, total_count, sec_per_cap;
+
+ idx = heart_battery_get_batt_reset_usage_index();
+
+ /* DISCHARGING */
+ total_time = 0; total_count = 0;
+ total_time = heart_battery_get_usage_reset_total_time(idx, DISCHARGING) + batt_stat.curr_run_time_sec[DISCHARGING];
+ total_count = heart_battery_get_usage_reset_count(idx, DISCHARGING) + batt_stat.curr_cap_counter[DISCHARGING];
+
+ if (total_time && total_count) {
+ sec_per_cap = total_time / total_count;
+ if (sec_per_cap < default_sec_per_cap[DISCHARGING][DEFAULT_MIN])
+ sec_per_cap = default_sec_per_cap[DISCHARGING][DEFAULT_MIN];
+ else if (sec_per_cap > default_sec_per_cap[DISCHARGING][DEFAULT_MAX])
+ sec_per_cap = default_sec_per_cap[DISCHARGING][DEFAULT_MAX];
+ heart_battery_set_usage_reset(idx, DISCHARGING, sec_per_cap, total_count);
+ }
+ /* CHARGING */
+ total_time = 0; total_count = 0;
+ total_time = heart_battery_get_usage_reset_total_time(idx, CHARGING)
+ + batt_stat.curr_run_time_sec[CHARGING];
+ total_count = heart_battery_get_usage_reset_count(idx, CHARGING) + batt_stat.curr_cap_counter[CHARGING];
+
+ if (total_time && total_count) {
+ sec_per_cap = total_time / total_count;
+ if (sec_per_cap < default_sec_per_cap[CHARGING][DEFAULT_MIN])
+ sec_per_cap = default_sec_per_cap[CHARGING][DEFAULT_MIN];
+ else if (sec_per_cap > default_sec_per_cap[CHARGING][DEFAULT_MAX])
+ sec_per_cap = default_sec_per_cap[CHARGING][DEFAULT_MAX];
+ heart_battery_set_usage_reset(idx, CHARGING, sec_per_cap, total_count);
+ }
+
+ batt_stat.reset_mark = batt_stat.reset_mark ? 0 : 1; /* Swap reset_mark */
+ batt_stat.reset_mark_timestamp = time(NULL);
+ batt_stat.curr_run_time_sec[DISCHARGING] = 0;
+ batt_stat.curr_run_time_sec[CHARGING] = 0;
+ batt_stat.curr_cap_counter[DISCHARGING] = 0;
+ batt_stat.curr_cap_counter[CHARGING] = 0;
+ batt_used.used_time_sec = 0;
+ batt_used.last_update_time = logging_get_time(CLOCK_BOOTTIME);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static long heart_battery_compute_remaining_time_in_min(int capacity_count, long sec_per_cap)
+{
+ /*
+ * Calculates and returns remaining time in minutes based on number
+ * of capacity changes and time needed for one change.
+ */
+ long time;
+
+ time = (capacity_count * sec_per_cap); /* seconds */
+ time = time + 30; /* add 30s margin */
+ time = time / 60; /* change to minutes */
+ return time;
+}
+
+static void heart_battery_calculate_prediction(enum charger_status_type goal)
+{
+ int i, capacity, level;
+ long total_time, total_count, sec_per_cap, pred_min;
+ long low_count, mid_count, high_count;
+ struct heart_battery_capacity *lbc = NULL;
+ GArray *arrays = NULL;
+
+ if (goal == CHARGING)
+ capacity = REMAIN_CAPACITY(batt_stat.curr_capacity);
+ else {
+ capacity = batt_stat.curr_capacity;
+
+ if (goal != DISCHARGING) {
+ _E("Wrong charging status is written. Suppose discharging");
+ goal = DISCHARGING;
+ }
+ }
+
+ /* PREDICTION METHOD: total average */
+ total_time = 0;
+ total_count = 0;
+ for (i = 0; i < BATTERY_HISTORY_RESET_MAX; i++) {
+ total_time += heart_battery_get_usage_reset_total_time(i, goal);
+ total_count += heart_battery_get_usage_reset_count(i, goal);
+ }
+ total_time += batt_stat.curr_run_time_sec[goal];
+ total_count += batt_stat.curr_cap_counter[goal];
+
+ if (total_time && total_count >= BATTERY_PREDICTION_DATA_MIN) {
+ sec_per_cap = total_time / total_count;
+ if (sec_per_cap < default_sec_per_cap[goal][DEFAULT_MIN])
+ sec_per_cap = default_sec_per_cap[goal][DEFAULT_MIN];
+ else if (sec_per_cap > default_sec_per_cap[goal][DEFAULT_MAX])
+ sec_per_cap = default_sec_per_cap[goal][DEFAULT_MAX];
+ pred_min = heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
+ heart_battery_set_prediction(TA, goal,
+ sec_per_cap, total_count,
+ pred_min);
+ } else {
+ heart_battery_set_prediction(TA, goal, 0, 0, 0);
+ }
+
+
+ /* PREDICTION METHOD:
+ * Prediction of battery remaining usage time
+ * considering users' psychological usage patterns
+ * by batt_lvl_usage of battery charge
+ * */
+ pred_min = 0;
+ sec_per_cap = 0;
+ level = heart_battery_get_level_usage_index(capacity);
+ low_count = heart_battery_get_usage_level_count(BATTERY_LEVEL_LOW, goal);
+ mid_count = heart_battery_get_usage_level_count(BATTERY_LEVEL_MID, goal);
+ high_count = heart_battery_get_usage_level_count(BATTERY_LEVEL_HIGH, goal);
+
+ if (level == BATTERY_LEVEL_LOW && low_count) {
+ sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_LOW, goal);
+ pred_min = heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
+ } else if (level == BATTERY_LEVEL_MID && low_count && mid_count) {
+ sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_LOW, goal);
+ pred_min = heart_battery_compute_remaining_time_in_min(15, sec_per_cap);
+ sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_MID, goal);
+ pred_min +=
+ heart_battery_compute_remaining_time_in_min(capacity - 15, sec_per_cap);
+ } else if (level == BATTERY_LEVEL_HIGH && low_count && mid_count && high_count) {
+ sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_LOW, goal);
+ pred_min = heart_battery_compute_remaining_time_in_min(15, sec_per_cap);
+ sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_MID, goal);
+ pred_min +=
+ heart_battery_compute_remaining_time_in_min(35, sec_per_cap);
+ sec_per_cap = heart_battery_get_usage_level_spc(BATTERY_LEVEL_HIGH, goal);
+ pred_min +=
+ heart_battery_compute_remaining_time_in_min(capacity - 50, sec_per_cap);
+ }
+ heart_battery_set_prediction(PCB, goal, 0, 0, pred_min);
+
+
+ /* PREDICTION METHOD: week average */
+ total_time = 0;
+ total_count = 0;
+ for (i = 0; i < BATTERY_HISTORY_DAY_MAX; i++) {
+ total_time += heart_battery_get_usage_week_total_time(i, goal);
+ total_count += heart_battery_get_usage_week_count(i, goal);
+ }
+ if (total_time && total_count >= BATTERY_PREDICTION_DATA_MIN) {
+ sec_per_cap = total_time / total_count;
+ if (sec_per_cap < default_sec_per_cap[goal][DEFAULT_MIN])
+ sec_per_cap = default_sec_per_cap[goal][DEFAULT_MIN];
+ else if (sec_per_cap > default_sec_per_cap[goal][DEFAULT_MAX])
+ sec_per_cap = default_sec_per_cap[goal][DEFAULT_MAX];
+ pred_min =
+ heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
+ heart_battery_set_prediction(WEEK, goal, sec_per_cap, total_count, pred_min);
+ } else
+ heart_battery_set_prediction(WEEK, goal, 0, 0, 0);
+
+
+ /* PREDICTION METHOD: last BATTERY_PREDICTION_COUNT data average */
+ arrays = g_array_new(FALSE, FALSE, sizeof(struct heart_battery_capacity *));
+ if (!arrays) {
+ _E("Failed to alloc array");
+ return;
+ }
+ if (heart_battery_get_capacity_history_latest(arrays, goal, BATTERY_PREDICTION_LATEST_COUNT)
+ != RESOURCED_ERROR_NONE) {
+ _E("Failed to get battery capacity history");
+ g_array_free(arrays, TRUE);
+ arrays = NULL;
+ return;
+ }
+ total_time = 0;
+ total_count = 0;
+ for (i = 0; i < arrays->len; i++) {
+ lbc = g_array_index(arrays, struct heart_battery_capacity *, i);
+ if (!lbc)
+ break;
+ total_count += lbc->diff_capacity;
+ if (goal == CHARGING)
+ total_time += lbc->charging_time;
+ else
+ total_time += lbc->used_time;
+ free(lbc);
+ }
+ if (total_time && total_count >= BATTERY_PREDICTION_DATA_MIN) {
+ sec_per_cap = total_time / total_count;
+ if (sec_per_cap < default_sec_per_cap[goal][DEFAULT_MIN])
+ sec_per_cap = default_sec_per_cap[goal][DEFAULT_MIN];
+ else if (sec_per_cap > default_sec_per_cap[goal][DEFAULT_MAX])
+ sec_per_cap = default_sec_per_cap[goal][DEFAULT_MAX];
+
+ pred_min =
+ heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
+ heart_battery_set_prediction(COUNT, goal, sec_per_cap, total_count, pred_min);
+ /* check current discharge rate */
+ if (sec_per_cap && goal == DISCHARGING) {
+ batt_stat.discharge_rate_level =
+ heart_battery_calculate_discharge_rate_level(sec_per_cap);
+ _I("discharge rate level : %d", batt_stat.discharge_rate_level);
+ }
+ } else
+ heart_battery_set_prediction(COUNT, goal, 0, 0, 0);
+ g_array_free(arrays, TRUE);
+ arrays = NULL;
+
+
+ /* PREDICTION METHOD: last BATTERY_PREDICTION_PERIOD hours average */
+ arrays = g_array_new(FALSE, FALSE, sizeof(struct heart_battery_capacity *));
+ if (!arrays) {
+ _E("Failed to alloc array");
+ return;
+ }
+ if (heart_battery_get_capacity_history(arrays, BATTERY_PREDICTION_PERIOD) != RESOURCED_ERROR_NONE) {
+ _E("Failed to get battery capacity history");
+ g_array_free(arrays, TRUE);
+ arrays = NULL;
+ return;
+ }
+ total_time = 0;
+ total_count = 0;
+ for (i = 0; i < arrays->len; i++) {
+ lbc = g_array_index(arrays, struct heart_battery_capacity *, i);
+ if (!lbc)
+ break;
+ if (goal == CHARGING) {
+ if (lbc->charger_status != CHARGING) {
+ free(lbc);
+ continue;
+ }
+ total_time += lbc->charging_time;
+ total_count += lbc->diff_capacity;
+ } else {
+ if (lbc->charger_status != DISCHARGING) {
+ free(lbc);
+ continue;
+ }
+ total_time += lbc->used_time;
+ total_count += lbc->diff_capacity;
+ }
+ free(lbc);
+ }
+ g_array_free(arrays, TRUE);
+ arrays = NULL;
+ if (total_time && total_count >= BATTERY_PREDICTION_DATA_MIN) {
+ sec_per_cap = total_time / total_count;
+ if (sec_per_cap < default_sec_per_cap[goal][DEFAULT_MIN])
+ sec_per_cap = default_sec_per_cap[goal][DEFAULT_MIN];
+ else if (sec_per_cap > default_sec_per_cap[goal][DEFAULT_MAX])
+ sec_per_cap = default_sec_per_cap[goal][DEFAULT_MAX];
+ pred_min =
+ heart_battery_compute_remaining_time_in_min(capacity, sec_per_cap);
+ heart_battery_set_prediction(PERIOD, goal, sec_per_cap, total_count, pred_min);
+
+ } else
+ heart_battery_set_prediction(PERIOD, goal, 0, 0, 0);
+
+ /* Log values of all predictions calculated */
+ for (i = 0; i < MAX_STRATEGY; i++) {
+ _I("%s %d %ld %ld %ld",
+ (goal == DISCHARGING) ? "TimeToEmpty:" : "TimeToFull:",
+ batt_stat.curr_capacity,
+ batt_stat.prediction[goal].sec_per_cap[i],
+ batt_stat.prediction[goal].cap_counter[i],
+ batt_stat.prediction[goal].time_pred_min[i]);
+ }
+}
+
+static int heart_battery_add_capacity(int capacity)
+{
+ char info[BATTERY_DATA_MAX];
+ int ret, idx, status;
+ long time_diff_capacity_lvl[MAX_CHARGER_STATE];
+ int diff_capacity_lvl;
+ long total_time, total_count, sec_per_cap;
+ time_t timestamp = time(NULL);
+ time_t curr_wall_time = logging_get_time(CLOCK_BOOTTIME);
+
+ status = batt_stat.curr_charger_status;
+ /* calculate diff */
+ time_diff_capacity_lvl[status] = curr_wall_time - batt_stat.last_event_wall_time;
+
+ if (time_diff_capacity_lvl[status] < 0) {
+ batt_stat.last_event_wall_time = curr_wall_time;
+ return 0;
+ }
+
+ time_diff_capacity_lvl[!status] = 0;
+
+ if (!batt_stat.curr_capacity)
+ diff_capacity_lvl = 1;
+ else
+ diff_capacity_lvl = abs(batt_stat.curr_capacity - capacity);
+
+ _I("%d -> %d %ld %ld", batt_stat.curr_capacity, capacity,
+ timestamp, time_diff_capacity_lvl[status]);
+
+ /* update battery current status */
+ batt_stat.last_event_wall_time = curr_wall_time;
+ batt_stat.curr_capacity = capacity;
+
+ /* Full Charging status */
+ if (status == CHARGING && !REMAIN_CAPACITY(capacity) && !diff_capacity_lvl)
+ return 0;
+
+ /* update run usage */
+ batt_stat.curr_run_time_sec[status] += time_diff_capacity_lvl[status];
+ batt_stat.curr_cap_counter[status] += diff_capacity_lvl;
+
+ /* update batt_lvl_usage usage */
+ total_time = 0;
+ total_count = 0;
+
+ if (status == CHARGING)
+ idx = heart_battery_get_level_usage_index(REMAIN_CAPACITY(capacity));
+ else
+ idx = heart_battery_get_level_usage_index(capacity);
+
+ total_time = heart_battery_get_usage_level_total_time(idx, status) + time_diff_capacity_lvl[status];
+ if (total_time)
+ total_count = heart_battery_get_usage_level_count(idx, status) + diff_capacity_lvl;
+
+ if (total_count) {
+ sec_per_cap = total_time / total_count;
+ if (sec_per_cap == 0)
+ sec_per_cap = default_sec_per_cap[status][DEFAULT_AVG];
+ else if (sec_per_cap < default_sec_per_cap[status][DEFAULT_MIN])
+ sec_per_cap = default_sec_per_cap[status][DEFAULT_MIN];
+ else if (sec_per_cap > default_sec_per_cap[status][DEFAULT_MAX])
+ sec_per_cap = default_sec_per_cap[status][DEFAULT_MAX];
+ /*
+ * If counts reached MAXIMUM number,
+ * counts is divided by 2 to reduce previous data's effect to equation
+ */
+ if (total_count >= BATTERY_HISTORY_COUNT_MAX)
+ total_count = total_count >> 1;
+
+ heart_battery_set_usage_level(idx, status, sec_per_cap, total_count);
+ heart_battery_set_usage_level_stime(idx, timestamp);
+ }
+
+ /* update day usage */
+ total_time = 0;
+ total_count = 0;
+
+ idx = heart_battery_get_week_day_usage_index(timestamp);
+ total_time = heart_battery_get_usage_week_total_time(idx, status) + time_diff_capacity_lvl[status];
+ if (total_time)
+ total_count = heart_battery_get_usage_week_count(idx, status) + diff_capacity_lvl;
+
+ if (total_count) {
+ sec_per_cap = total_time / total_count;
+ if (sec_per_cap == 0)
+ sec_per_cap = default_sec_per_cap[status][DEFAULT_AVG];
+ else if (sec_per_cap < default_sec_per_cap[status][DEFAULT_MIN])
+ sec_per_cap = default_sec_per_cap[status][DEFAULT_MIN];
+ else if (sec_per_cap > default_sec_per_cap[status][DEFAULT_MAX])
+ sec_per_cap = default_sec_per_cap[status][DEFAULT_MAX];
+ heart_battery_set_usage_week(idx, status, sec_per_cap, total_count);
+ heart_battery_set_usage_week_stime(idx, CALCULATE_DAY_BASE_TIME(timestamp));
+ }
+
+ heart_battery_calculate_prediction(batt_stat.curr_charger_status);
+
+ /* db backup */
+ snprintf(info, sizeof(info), "%d %d %ld %ld %d %d ",
+ capacity, diff_capacity_lvl,
+ time_diff_capacity_lvl[DISCHARGING], time_diff_capacity_lvl[CHARGING],
+ batt_stat.curr_charger_status, batt_stat.reset_mark);
+ ret = logging_write(PID_FOR_ROOT, BATTERY_NAME, TIZEN_SYSTEM_BATTERY_APPID,
+ TIZEN_SYSTEM_APPID, timestamp, info);
+ if (ret != RESOURCED_ERROR_NONE)
+ return ret;
+
+ /* insert capacity history list */
+ heart_battery_insert_capacity(&capacity_history_list, capacity, diff_capacity_lvl,
+ timestamp, time_diff_capacity_lvl[DISCHARGING],
+ time_diff_capacity_lvl[CHARGING], batt_stat.curr_charger_status,
+ batt_stat.reset_mark, true);
+
+ _D("battery_heart_capacity_write %d diff_capacity %d, used time %ld, charging time %ld, charger status %d, reset_mark %d",
+ capacity, diff_capacity_lvl,
+ time_diff_capacity_lvl[DISCHARGING], time_diff_capacity_lvl[CHARGING],
+ batt_stat.curr_charger_status, batt_stat.reset_mark);
+
+ resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
+ return RESOURCED_ERROR_NONE;
+}
+
+static void rul_display_state_changed_cb(device_callback_e type, void *value, void *user_data)
+{
+ int display_state = (int) ((intptr_t) value), charger_status;
+ /* 0 : on, 1 : dim, 2: off */
+
+ /*
+ * If charger_status==CHARGING and raw capacity calculation ongoing,
+ * then, handle display_on time for RUL
+ */
+
+ charger_status = heart_battery_get_charger_status();
+ if ((charger_status == CHARGING) && (rul.charging_start_time != 0)) {
+ if (type != DEVICE_CALLBACK_DISPLAY_STATE)
+ return;
+
+ if (display_state == DISPLAY_STATE_NORMAL) {
+ _I("DISPLAY: NORMAL/DIM");
+ rul.lcd_data.state = DISPLAY_STATE_NORMAL;
+ if (rul.lcd_data.on_start_time == 0) {
+ rul.lcd_data.on_start_time = logging_get_time(CLOCK_BOOTTIME);
+ }
+ } else if (display_state == DISPLAY_STATE_SCREEN_OFF) {
+ _I("DISPLAY: OFF");
+ rul.lcd_data.state = DISPLAY_STATE_SCREEN_OFF;
+ if (rul.lcd_data.on_start_time > 0) {
+ rul.lcd_data.on_stop_time = logging_get_time(CLOCK_BOOTTIME);
+ rul.lcd_data.on_time += rul.lcd_data.on_stop_time - rul.lcd_data.on_start_time;
+ rul.lcd_data.on_start_time = 0;
+ rul.lcd_data.on_stop_time = 0;
+ }
+ }
+ }
+}
+
+static void rul_write_data_to_file(void)
+{
+ int len = 0;
+ char buff[RUL_DATA_SIZE] = {0};
+ _cleanup_fclose_ FILE *fp = NULL, *fp1 = NULL;
+ float fullcapnom = 0, fullcapnom_mAh = 0;
+
+ /* Update count of Charging cycles*/
+ rul.charging_cycles += 1;
+
+ /* Calculate normalized capacity, i.e., extrapolate for 0% to 100% */
+ fullcapnom = rul.raw_capacity / ((rul.soc_stop/100.0f) - (rul.soc_start/100.0f));
+ fullcapnom_mAh = fullcapnom / 3.6f;
+ _I("rul : raw_capacity = %.4f As, fullcapnom = %.4f As = %.4f mAh", rul.raw_capacity, fullcapnom, fullcapnom_mAh);
+
+ /* Update RUL data file */
+ fp = fopen(RUL_DATA_FILE, "a");
+ if (fp == NULL) {
+ _E("Could not open file - RUL_DATA_FILE");
+ return;
+ }
+
+ len = snprintf(buff, RUL_DATA_SIZE, "%d %.4f\n", rul.charging_cycles, fullcapnom_mAh);
+
+ if (len < RUL_DATA_SIZE)
+ fputs(buff, fp);
+
+ /* Write Charging cycles count to file */
+ fp1 = fopen(RUL_CHARGING_CYCLES_FILE, "w");
+ if (fp1 == NULL) {
+ _E("Could not open file for write - RUL_CHARGING_CYCLES_FILE");
+ return;
+ }
+ fprintf(fp1, "%d", rul.charging_cycles);
+
+}
+
+static void rul_charging_cycle_end_work(void)
+{
+ int capacity;
+ long total_charging_time;
+ bool lcd_on_time_check;
+ float lcd_on_ratio = 1.0f;
+
+ capacity = heart_battery_get_capacity();
+
+ rul.soc_stop = capacity;
+ rul.charging_stop_time = logging_get_time(CLOCK_BOOTTIME);
+
+ /* If LCD was on before disconnecting charger, update display_on time */
+ if (rul.lcd_data.on_start_time != 0) {
+ rul.lcd_data.on_stop_time = logging_get_time(CLOCK_BOOTTIME);
+ rul.lcd_data.on_time += rul.lcd_data.on_stop_time - rul.lcd_data.on_start_time;
+ }
+
+ /* Max LCD ON Time ratio criteria met ? */
+ total_charging_time = rul.charging_stop_time - rul.charging_start_time;
+ if (total_charging_time != 0)
+ lcd_on_ratio = (rul.lcd_data.on_time / (total_charging_time * 1.0f));
+ lcd_on_time_check = lcd_on_ratio <= RUL_DISPLAY_ON_CUTOFF_RATIO;
+
+ /* write data to file if condititons met*/
+ if ((rul.charging_start_time != 0) && (lcd_on_time_check == true) &&
+ (rul.soc_stop - rul.soc_start >= RUL_MIN_CAPACITY_DIFF))
+ rul_write_data_to_file();
+
+ /* init for next charging cycle */
+ rul.soc_start = 0;
+ rul.soc_stop = 0;
+ rul.charging_start_time = 0;
+ rul.charging_stop_time = 0;
+ rul.lcd_data.on_start_time = 0;
+ rul.lcd_data.on_stop_time = 0;
+ rul.lcd_data.on_time = 0;
+}
+
+static void rul_calculate_raw_capacity(void)
+{
+ /*
+ * This function updates Raw Capacity every 1% SoC change.
+ *
+ * Upon first time 1% SoC change, initialize rul_info variables.
+ *
+ * Subsequently, Update Raw Capacity using time interval and
+ * current_now sys node values.
+ *
+ * If capacity = 100%, dump collected data
+ */
+
+ long rul_curr_time, rul_time_interval;
+ static long prev_charging_time;
+ int fg_curr_inst, capacity, ret;
+ float fg_curr_inst_f;
+ static float prev_fg_curr_inst_f = 0.0f;
+
+ capacity = heart_battery_get_capacity();
+
+ if (rul.charging_start_time == 0) {
+ rul.charging_start_time = logging_get_time(CLOCK_BOOTTIME);
+ rul.soc_start = capacity;
+ rul.raw_capacity = 0.0f;
+ prev_charging_time = rul.charging_start_time;
+ prev_fg_curr_inst_f = 0.0f;
+ rul.lcd_data.on_start_time = 0;
+ rul.lcd_data.on_stop_time = 0;
+ rul.lcd_data.on_time = 0;
+
+ /* Get display status at time of initiating RUL calculations */
+ ret = device_display_get_state(&rul.lcd_data.state);
+ if (ret != DEVICE_ERROR_NONE) {
+ _E("Failed to get device display state with err = %d", ret);
+ return;
+ }
+ if ((rul.lcd_data.state == DISPLAY_STATE_NORMAL) || (rul.lcd_data.state == DISPLAY_STATE_SCREEN_DIM))
+ rul.lcd_data.on_start_time = logging_get_time(CLOCK_BOOTTIME);
+ } else {
+ rul_curr_time = logging_get_time(CLOCK_BOOTTIME);
+ rul_time_interval = rul_curr_time - prev_charging_time;
+ prev_charging_time = rul_curr_time;
+
+ ret = fread_int("/sys/class/power_supply/battery/current_now", &fg_curr_inst);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("This device doesn't support FG CURRENT_NOW information. Disable LOGIC_RUL");
+ return;
+ }
+
+ fg_curr_inst_f = fg_curr_inst / 1000.0f;
+ rul.raw_capacity += ((fg_curr_inst_f + prev_fg_curr_inst_f) / 2.0f)*rul_time_interval;
+ prev_fg_curr_inst_f = fg_curr_inst_f;
+ }
+
+ if (capacity == 100) {
+ rul_charging_cycle_end_work();
+ }
+}
+
+/* ============================ DBUS -> DEVICED on demand ==================== */
+
+static int heart_battery_direct_get_capacity(void)
+{
+ int capacity;
+
+ capacity = d_bus_call_method_sync_gvariant(DEVICED_BUS_NAME, DEVICED_PATH_BATTERY,
+ DEVICED_INTERFACE_BATTERY,
+ GET_BATTERY_CAPACITY,
+ NULL);
+ if (capacity < 0) {
+ _E("Failed to sync DBUS message.");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ return capacity;
+}
+
+static enum charger_status_type heart_battery_direct_get_charger_status(void)
+{
+ int status;
+
+ status = d_bus_call_method_sync_gvariant(DEVICED_BUS_NAME, DEVICED_PATH_BATTERY,
+ DEVICED_INTERFACE_BATTERY,
+ GET_CHARGER_STATUS,
+ NULL);
+ if (status < 0) {
+ _E("Failed to sync DBUS message.");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (status > 0)
+ return CHARGING;
+ return DISCHARGING;
+}
+
+/* ========================= DBUS -> DEVICED on demand END ================= */
+
+/* ============================ DBUS -> DEVICED handler ====================== */
+static void heart_battery_capacity_status(GVariant *params)
+{
+ /*
+ * This handler is called when battery capacity value change in 1%
+ *
+ * The message have current percent value of capacity
+ *
+ * (This requires deviced with commit at least:
+ * "f1ae1d1f270e9 battery: add battery capacity dbus signal broadcast")
+ */
+
+ int capacity = -1;
+ int bat_trigger = -1;
+ int bat_ups_est = -1;
+ int bat_normal_est = -1;
+
+ do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &capacity);
+ if (capacity < 0) {
+ _E("Failed: dbus_message_get_args()");
+ return;
+ }
+ heart_battery_add_capacity(capacity);
+ heart_battery_update_used_time(logging_get_time(CLOCK_BOOTTIME),
+ batt_stat.curr_charger_status);
+
+ if (logic_v2) {
+ /* get the device mode */
+ if (vconf_get_int(VCONFKEY_HEART_BATTERY_DEVICE_MODE, &device_mode))
+ _E("failed to get VCONFKEY_HEART_BATTERY_DEVICE_MODE\n");
+
+ /* for every battery level change, calculate the battery estimation time using new logic*/
+ heart_battery_cal_discharge_rem_time();
+
+ if (batt_stat.curr_charger_status == CHARGING &&
+ batt_stat.last_capacity_chg < batt_stat.curr_capacity) {
+ heart_battery_cal_charging_rem_time();
+ first_level_change = FALSE;
+ } else {
+ /*
+ * if battery is very very low then update the pivot before power off
+ */
+ if (batt_stat.curr_capacity == LOW_CAPACITY)
+ heart_battery_collect_pivot_info();
+ }
+ }
+ if (logic_rul) {
+ /* Update prev_soc, curr_soc */
+ rul.prev_soc = rul.curr_soc;
+ rul.curr_soc = capacity;
+
+ /*
+ * If charger_status==CHARGING and SOC_INCREASING, start/continue raw capacity calculation.
+ * Else, if raw capacity calculation was ongoing, then dump collected data.
+ */
+ if ((batt_stat.curr_charger_status == CHARGING) && (rul.curr_soc >= rul.prev_soc))
+ rul_calculate_raw_capacity();
+ else if (rul.charging_start_time != 0)
+ rul_charging_cycle_end_work();
+ }
+
+ /* Get the UPSM trigger value and remaining estimate */
+ if (vconf_get_int(VCONFKEY_SETAPPL_MANAGE_BATTERY_TRIGGER_TIME, &bat_trigger)) {
+ _E("failed to get VCONFKEY_SETAPPL_MANAGE_BATTERY_TRIGGER_TIME\n");
+ return;
+ }
+ if (bat_trigger > 0) { /* Battery planner is enabled*/
+ bat_ups_est = get_battery_remaining_time(ULTRA_SAVING_MODE, DISCHARGING);
+ bat_normal_est = get_battery_remaining_time(POWER_NORMAL_MODE, DISCHARGING);
+ _I(" trigger time: %d, ups est:%d, normal est:%d", bat_trigger, bat_ups_est, bat_normal_est);
+ if (bat_ups_est > 0 && bat_trigger >= bat_ups_est) {
+ char *args[4] = { "_SYSPOPUP_CONTENT_", "manage_battery",
+ "_BAT_POPUP_TYPE_", "enable_mbp"};
+
+ d_bus_call_method_sync(SYSTEM_POPUP_BUS_NAME,
+ SYSTEM_POPUP_PATH_SYSTEM, SYSTEM_POPUP_IFACE_SYSTEM,
+ "PopupLaunch", "ssss", args);
+ }
+ if (bat_normal_est > 0 && bat_normal_est >= bat_trigger) {
+ char *args[4] = { "_SYSPOPUP_CONTENT_", "manage_battery",\
+ "_BAT_POPUP_TYPE_", "disable_mbp"};
+
+ d_bus_call_method_sync(SYSTEM_POPUP_BUS_NAME,
+ SYSTEM_POPUP_PATH_SYSTEM, SYSTEM_POPUP_IFACE_SYSTEM,
+ "PopupLaunch", "ssss", args);
+ }
+ }
+}
+
+static void heart_battery_charger_status(GVariant *params)
+{
+ /*
+ * This handler is called when USB cable with charging capabilities
+ * is connected or disconnected from the device.
+ *
+ * The message have current status of charger connection.
+ * STATUSES:
+ * 0 - charger was disconnected
+ * 1 - charger was connected
+ */
+ int charger_status = -1, cap_history_size;
+
+ do_expr_unless_g_variant_get_typechecked(return, params, "(i)", &charger_status);
+ if (charger_status < 0) {
+ _E("Failed: dbus_message_get_args()");
+ return;
+ }
+
+ /* Update the statistics with capacity when charger state was changed */
+ heart_battery_add_capacity(batt_stat.curr_capacity);
+
+ cap_history_size = heart_battery_get_capacity_history_size();
+
+ if (charger_status == DISCHARGING && batt_stat.curr_capacity >= 90) {
+ /*
+ * If battery is charged over 90 and charger was disconnected.
+ * So most probably the phone was "charged".
+ * Let's reset the statistics.
+ */
+ resourced_notify(RESOURCED_NOTIFIER_DATA_RESET, NULL);
+ } else if (charger_status == DISCHARGING && cap_history_size >= BATTERY_CAPACITY_MAX) {
+ /*
+ * Charger is not connected and the battery history is over limit.
+ * Let's reset the statistics.
+ */
+ resourced_notify(RESOURCED_NOTIFIER_DATA_RESET, NULL);
+ }
+ /* Update current charger connection status */
+ batt_stat.curr_charger_status = charger_status;
+ heart_battery_update_used_time(logging_get_time(CLOCK_BOOTTIME),
+ batt_stat.curr_charger_status);
+ heart_battery_calculate_prediction(batt_stat.curr_charger_status);
+
+ if (logic_v2) {
+ /*
+ * If charger removed/inserted then update the battery estimation time
+ */
+ heart_battery_cal_discharge_rem_time();
+
+ if (charger_status == CHARGING) {
+ /*
+ * if diff is more than 10% then flush the previous charge data
+ */
+ if ((batt_stat.last_capacity_chg > 0) &&
+ (batt_stat.last_capacity_chg - batt_stat.curr_capacity > BATT_CHG_FLUSH_DATA))
+ heart_battery_flush_charge_data();
+
+ /* collect the data for pivot update */
+ heart_battery_collect_pivot_info();
+
+ batt_stat.last_wall_time_chg = 0;
+ first_level_change = TRUE;
+ heart_battery_print_prev_charge_data();
+ heart_battery_cal_charging_rem_time();
+ } else {
+ heart_battery_collect_discharge_data();
+ }
+ }
+ if (logic_rul) {
+ /*
+ * If charger disconnected and raw capacity calculation was ongoing,
+ * then dump collected data.
+ */
+ if ((charger_status == DISCHARGING) && (rul.charging_start_time != 0))
+ rul_charging_cycle_end_work();
+ }
+}
+
+/* ========================= DBUS -> DEVICED handler END ==================== */
+
+int heart_battery_get_capacity_history_latest(GArray *arrays, int charge, int max_size)
+{
+ int ret, size, count;
+ struct heart_battery_capacity *lbc, *lbci;
+ GSList *iter, *rlist;
+
+ if (!capacity_history_list) {
+ _E("empty capacity history list");
+ return RESOURCED_ERROR_FAIL;
+ }
+ size = g_slist_length(capacity_history_list);
+ if (!size) {
+ _I("capacity history is empty");
+ return RESOURCED_ERROR_NONE;
+ }
+ ret = pthread_mutex_lock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ count = 0;
+
+ rlist = g_slist_copy(capacity_history_list);
+
+ rlist = g_slist_reverse(rlist);
+
+ gslist_for_each_item(iter, rlist) {
+ lbc = (struct heart_battery_capacity *)iter->data;
+ if (!lbc)
+ break;
+ if (charge < MAX_CHARGER_STATE && charge != lbc->charger_status)
+ continue;
+ count++;
+ if (max_size < count)
+ break;
+ lbci = malloc(sizeof(struct heart_battery_capacity));
+ if (!lbci) {
+ _E("malloc failed");
+ goto unlock_exit;
+ }
+ lbci->capacity = lbc->capacity;
+ lbci->diff_capacity = lbc->diff_capacity;
+ if (!lbc->diff_capacity)
+ count--;
+ lbci->used_time = lbc->used_time;
+ lbci->charging_time = lbc->charging_time;
+ lbci->charger_status = lbc->charger_status;
+ g_array_prepend_val(arrays, lbci);
+ }
+unlock_exit:
+ g_slist_free(rlist);
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
+int heart_battery_get_capacity_history(GArray *arrays, enum heart_data_period period)
+{
+ int ret, index, size;
+ struct heart_battery_capacity *lbc, *lbci;
+ GSList *iter;
+ time_t curr = time(NULL);
+
+ switch (period) {
+ case DATA_LATEST:
+ index = 0;
+ break;
+ case DATA_3HOUR:
+ index = 3;
+ break;
+ case DATA_6HOUR:
+ index = 6;
+ break;
+ case DATA_12HOUR:
+ index = 12;
+ break;
+ case DATA_1DAY:
+ index = 24;
+ break;
+ default:
+ _E("Wrong message arguments! %d", period);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!capacity_history_list) {
+ _E("empty capacity history list");
+ return RESOURCED_ERROR_FAIL;
+ }
+ size = g_slist_length(capacity_history_list);
+ if (!size) {
+ _I("capacity history is empty");
+ return RESOURCED_ERROR_NONE;
+ }
+ ret = pthread_mutex_lock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ gslist_for_each_item(iter, capacity_history_list) {
+ lbc = (struct heart_battery_capacity *)iter->data;
+ if (!lbc)
+ break;
+ if (index && (lbc->timestamp < curr - (index * 3600)))
+ continue;
+ lbci = malloc(sizeof(struct heart_battery_capacity));
+ if (!lbci) {
+ _E("malloc failed");
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ lbci->capacity = lbc->capacity;
+ lbci->diff_capacity = lbc->diff_capacity;
+ lbci->used_time = lbc->used_time;
+ lbci->charging_time = lbc->charging_time;
+ lbci->charger_status = lbc->charger_status;
+ g_array_append_val(arrays, lbci);
+ }
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
+/* ============================ DBUS interface ====================== */
+
+static void dbus_get_battery_capacity_history_latest(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int i, size, charge, max_size;
+ GArray *arrays = NULL;
+ GVariantBuilder builder, *sub_builder;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(ii)", &charge, &max_size);
+ if (charge < 0 || max_size < 0) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+
+ size = g_slist_length(capacity_history_list);
+ if (!size) {
+ _I("capacity history is empty");
+ goto failure;
+ }
+ arrays = g_array_new(FALSE, FALSE, sizeof(struct heart_battery_capacity *));
+ if (!arrays) {
+ _E("Failed to alloc array");
+ goto failure;
+ }
+ if (heart_battery_get_capacity_history_latest(arrays, charge, max_size) != RESOURCED_ERROR_NONE) {
+ _E("Failed to get capacity history latest");
+ D_BUS_REPLY_ERR(invocation);
+ return;
+ }
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(iii)"));
+ if (!arrays->len) {
+ _E("No battery capacity history data");
+ goto exit;
+ }
+
+ for (i = 0; i < arrays->len; i++) {
+ struct heart_battery_capacity *lbc;
+ lbc = g_array_index(arrays, struct heart_battery_capacity *, i);
+ if (!lbc)
+ break;
+
+ g_variant_builder_add(sub_builder, "(iii)", lbc->capacity,
+ lbc->used_time, lbc->charging_time);
+ free(lbc);
+ }
+exit:
+ g_variant_builder_add_value(&builder, g_variant_new("a(iii)", sub_builder));
+ g_variant_builder_unref(sub_builder);
+ g_array_free(arrays, TRUE);
+ g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_get_battery_capacity_history(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret, size, period = -1, index;
+ struct heart_battery_capacity *lbc;
+ GSList *iter;
+ time_t curr = time(NULL);
+ GVariantBuilder builder, *sub_builder;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &period);
+ if (period < 0) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+ switch (period) {
+ case DATA_LATEST:
+ index = 0;
+ break;
+ case DATA_3HOUR:
+ index = 3;
+ break;
+ case DATA_6HOUR:
+ index = 6;
+ break;
+ case DATA_12HOUR:
+ index = 12;
+ break;
+ case DATA_1DAY:
+ index = 24;
+ break;
+ default:
+ _E("Wrong message arguments! %d", period);
+ goto failure;
+ }
+ size = g_slist_length(capacity_history_list);
+ if (!size) {
+ _I("capacity history is empty");
+ goto failure;
+ }
+ ret = pthread_mutex_lock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ goto failure;
+ }
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(su)"));
+
+ gslist_for_each_item(iter, capacity_history_list) {
+ lbc = (struct heart_battery_capacity *)iter->data;
+ if (!lbc)
+ break;
+ if (index && (lbc->timestamp < curr - (index * 3600)))
+ continue;
+
+ g_variant_builder_add(sub_builder, "(iii)", lbc->capacity,
+ lbc->used_time, lbc->charging_time);
+ }
+
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ g_variant_builder_unref(sub_builder);
+ goto failure;
+ }
+
+ g_variant_builder_add_value(&builder, g_variant_new("a(iii)", sub_builder));
+ g_variant_builder_unref(sub_builder);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_get_battery_used_time(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ heart_battery_update_used_time(logging_get_time(CLOCK_BOOTTIME),
+ batt_stat.curr_charger_status);
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(i)", batt_used.used_time_sec));
+}
+
+static int get_battery_remaining_time(int mode, enum charger_status_type status)
+{
+ int i, ret, count;
+ long sum, time, cumul_average, trend_average;
+ double result;
+
+ ret = count = 0;
+ sum = time = 0;
+ cumul_average = trend_average = 0;
+ /* get prediction time of cumulative value */
+ for (i = 0; i <= WEEK; i++) {
+ time = heart_battery_get_prediction_time(i, status);
+ if (time) {
+ sum += time;
+ count++;
+ }
+ }
+ if (count)
+ cumul_average = sum / count;
+
+ count = 0;
+ sum = 0;
+ /* get prediction time of trend value */
+ for (i = COUNT; i < MAX_STRATEGY; i++) {
+ time = heart_battery_get_prediction_time(i, status);
+ if (time) {
+ sum += time;
+ count++;
+ }
+ }
+ if (count)
+ trend_average = sum / count;
+
+ /* failed to get prediction so return learning mode */
+ if (!cumul_average && !trend_average) {
+ if (batt_stat.curr_capacity != 100 && batt_stat.curr_capacity != 0)
+ ret = BATTERY_USAGE_LEARNING;
+ } else if (cumul_average && !trend_average) {
+ /* failed to get prediction of trend average */
+ ret = cumul_average;
+ } else if (!cumul_average && trend_average) {
+ /* failed to get prediction of cumulative average */
+ ret = trend_average;
+ } else
+ ret = ((cumul_average * CUMUL_WEIGHT) + (trend_average * TREND_WEIGHT));
+
+ if (status == CHARGING) {
+ if (logic_v2) /* new logic */
+ return batt_stat.remaining_time_chg;
+ return ret; /* old logic */
+ }
+
+ if (logic_v2) { /* new logic */
+ switch (mode) {
+ case POWER_SAVING_MODE:
+ /* Fall through */
+ case ULTRA_SAVING_MODE:
+ ret = get_battery_remaining_time_ups();
+ break;
+ case POWER_NORMAL_MODE:
+ ret = get_battery_remaining_time_new();
+ break;
+ default:
+ break;
+ }
+ return ret;
+ }
+
+ if (ret <= 0)
+ return BATTERY_USAGE_LEARNING;
+
+ /* old logic */
+ switch (mode) {
+ case ULTRA_SAVING_MODE:
+ /* Fall through */
+ case POWER_SAVING_MODE:
+ result = (double)ret * default_mode_factor[mode];
+ return (int)result;
+ case POWER_NORMAL_MODE:
+ /* Fall through */
+ default:
+ return ret;
+ }
+}
+
+static void dbus_get_battery_remaining_time(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret, mode = -1;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &mode);
+ if (mode < 0) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+
+ if (!battery_learning_mode)
+ battery_learning_mode = heart_battery_get_learning_mode();
+
+ if (!battery_learning_mode) {
+ _E("data is not enough to calculate prediction");
+ ret = BATTERY_USAGE_LEARNING;
+ } else {
+ if (batt_stat.curr_capacity <= 0) {
+ _I("Last capacity read may not be proper so read again");
+ batt_stat.curr_capacity = heart_battery_direct_get_capacity();
+ if (batt_stat.curr_capacity <= 0) {
+ /*
+ * still not proper ? return learning mode
+ */
+ ret = BATTERY_USAGE_LEARNING;
+ } else {
+ heart_battery_cal_discharge_rem_time();
+ ret = get_battery_remaining_time(mode, DISCHARGING);
+ }
+ } else {
+ ret = get_battery_remaining_time(mode, DISCHARGING);
+ }
+ }
+
+ _I("Remaining_time %d (mode: %d)", ret, mode);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_get_battery_charging_time(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret = get_battery_remaining_time(POWER_NORMAL_MODE, CHARGING);
+ _I("Remaining_charging_time %d", ret);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
+}
+
+static void dbus_get_battery_discharge_rate_level(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret = batt_stat.discharge_rate_level;
+ _I("discharge_rate_level %d", ret);
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
+}
+
+static void dbus_battery_save_to_file(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ heart_battery_status_save_to_db();
+
+ int ret = heart_battery_capacity_save_to_file(HEART_BATTERY_CAPACITY_DATA_FILE);
+ if (ret) {
+ _E("save to file failed");
+ D_BUS_REPLY_ERR(invocation)
+ return;
+ }
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
+}
+
+static const char dbus_methods_xml[] =
+" <method name='GetBatteryCapacityHistory'>"
+" <arg type='i' name='Period' direction='in'/>"
+" <arg type='a(iii)' name='CapacityHistory' direction='out'/>"
+" </method>"
+" <method name='GetBatteryCapacityHistoryLatest'>"
+" <arg type='i' name='Charge' direction='in'/>"
+" <arg type='i' name='MaxSize' direction='in'/>"
+" <arg type='a(iii)' name='CapacityHistory' direction='out'/>"
+" </method>"
+" <method name='GetBatteryUsedTime'>"
+" <arg type='i' name='UsedTime' direction='out'/>"
+" </method>"
+" <method name='GetBatteryRemainingTime'>"
+" <arg type='i' name='Mode' direction='in'/>"
+" <arg type='i' name='RemainingTime' direction='out'/>"
+" </method>"
+" <method name='GetBatteryChargingTime'>"
+" <arg type='i' name='ChargingTime' direction='out'/>"
+" </method>"
+" <method name='GetBatteryDischargeRateLevel'>"
+" <arg type='i' name='DischargeRateLevel' direction='out'/>"
+" </method>"
+" <method name='SaveBatteryData'>"
+" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
+" </method>";
+
+static struct d_bus_method dbus_methods[] = {
+ { "GetBatteryCapacityHistory", dbus_get_battery_capacity_history },
+ { "GetBatteryCapacityHistoryLatest", dbus_get_battery_capacity_history_latest },
+ { "GetBatteryUsedTime", dbus_get_battery_used_time },
+ { "GetBatteryRemainingTime", dbus_get_battery_remaining_time },
+ { "GetBatteryChargingTime", dbus_get_battery_charging_time },
+ { "GetBatteryDischargeRateLevel", dbus_get_battery_discharge_rate_level },
+ { "SaveBatteryData", dbus_battery_save_to_file },
+};
+
+/* ========================= DBUS interface END ==================== */
+static void heart_battery_used_time_init(enum charger_status_type status)
+{
+ batt_used.last_charger_status = status;
+ batt_used.last_update_time = logging_get_time(CLOCK_BOOTTIME);
+}
+
+static void heart_battery_status_init(void)
+{
+ int i, ret, status, capacity;
+
+ batt_stat.curr_capacity = 0;
+ batt_stat.curr_run_time_sec[DISCHARGING] = 0;
+ batt_stat.curr_run_time_sec[CHARGING] = 0;
+ batt_stat.curr_cap_counter[DISCHARGING] = 0;
+ batt_stat.curr_cap_counter[CHARGING] = 0;
+ batt_stat.curr_charger_status = 0;
+ batt_stat.reset_mark = 0;
+
+ for (i = 0; i < BATTERY_HISTORY_RESET_MAX; i++) {
+ heart_battery_set_usage_reset_stime(i, 0);
+ heart_battery_set_usage_reset(i, DISCHARGING, 0, 0);
+ heart_battery_set_usage_reset(i, CHARGING, 0, 0);
+ }
+
+
+ for (i = 0; i < BATTERY_LEVEL_MAX; i++) {
+ heart_battery_set_usage_level_stime(i, 0);
+ heart_battery_set_usage_level(i, DISCHARGING, default_sec_per_cap[DISCHARGING][DEFAULT_AVG], 0);
+ heart_battery_set_usage_level(i, CHARGING, default_sec_per_cap[CHARGING][DEFAULT_AVG], 0);
+ }
+
+ for (i = 0; i < BATTERY_HISTORY_DAY_MAX; i++) {
+ heart_battery_set_usage_week_stime(i, 0);
+ heart_battery_set_usage_week(i, DISCHARGING, 0, 0);
+ heart_battery_set_usage_week(i, CHARGING, 0, 0);
+ }
+
+ for (i = 0; i < MAX_STRATEGY; i++) {
+ heart_battery_set_prediction(i, DISCHARGING, 0, 0, 0);
+ heart_battery_set_prediction(i, CHARGING, 0, 0, 0);
+ }
+
+ ret = heart_battery_status_read_from_db();
+ if (ret < 0)
+ _E("Failed to read battery status data");
+
+ if (logic_v2) {
+ for (i = 0; i < INDEX_WINDOW_SIZE; i++) {
+ batt_stat.last_wall_time[i] = 0;
+ batt_stat.last_volt_intg[i] = 0.0;
+ }
+ for (i = 0; i < BATTERY_LEVEL_GAP; i++)
+ batt_stat.last_wall_time_chg_diff[i] = 0;
+
+ batt_stat.data_available = 0;
+ batt_stat.last_capacity = 0;
+ batt_stat.last_capacity_chg = 0;
+ first_level_change = FALSE;
+ batt_stat.curr_index = 0;
+ batt_stat.remaining_time = 0;
+ batt_stat.remaining_time_ups = 0;
+ batt_stat.last_pwr_bchg = average_pwr;
+ batt_stat.last_wall_time_chg = 0;
+ batt_stat.index_chg = 0;
+ batt_stat.remaining_time_chg = 0;
+ batt_stat.last_clock_tick = logging_get_time(CLOCK_BOOTTIME);
+ for (i = 0; i < INDEX_WINDOW_SIZE; i++)
+ batt_stat.pvt.total_dischg_time[i] = 0;
+ batt_stat.pvt.pvt_data_ind = 0;
+ batt_stat.pvt.start_cap_dischg = 0;
+ batt_stat.pvt.start_time_dischg = 0;
+ batt_stat.pvt.last_clock_tick = 0;
+
+ /* During the device boot-up, calculate energy for 100% battery and calcuate
+ pivot(norma and UPS mode) for time remaining time estimation*/
+ heart_battery_calculate_pivot();
+ /*get all the previousely stored data from file to program variable*/
+ heart_battery_read_data_from_file();
+ /* get all the previosly stored pivot info */
+ heart_battery_read_pivot_info_from_file();
+ /* if enough pivot data present then update the pivot */
+ heart_battery_update_pivot();
+ /*
+ * check whether was device power off for long time. If yes then adjust
+ * our stored time values
+ */
+ heart_battery_power_off_time_adjustment();
+ /*
+ * register callback for any time change from user side.
+ * If any time change happen then adjust whole data as per new time
+ */
+ vconf_notify_key_changed(VCONFKEY_SETAPPL_TIMEZONE_INT, time_change_notify_cb, NULL);
+ vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, time_change_notify_cb, NULL);
+ vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, time_change_notify_cb, NULL);
+ }
+
+ battery_learning_mode = heart_battery_get_learning_mode();
+
+ ret = heart_battery_capacity_read_from_file(HEART_BATTERY_CAPACITY_DATA_FILE);
+ if (ret < 0)
+ _E("Failed to read battery capacity data");
+
+ capacity = heart_battery_direct_get_capacity();
+ status = heart_battery_direct_get_charger_status();
+
+ /*
+ * Consider power off charing mode
+ * If new capacity is higher than old capacity and it is full, reset heart data
+ */
+ if (capacity > batt_stat.curr_capacity && status == DISCHARGING && capacity >= 90)
+ heart_battery_reset(NULL);
+ else
+ heart_battery_used_time_init(batt_stat.curr_charger_status);
+
+ if (capacity > 0)
+ batt_stat.curr_capacity = capacity;
+ if (status >= 0)
+ batt_stat.curr_charger_status = status;
+
+ heart_battery_calculate_prediction(batt_stat.curr_charger_status);
+ batt_stat.last_event_wall_time = logging_get_time(CLOCK_BOOTTIME);
+ batt_stat.discharge_rate_level = BATTERY_DISCHARGE_NONE;
+
+ if (logic_v2) {
+ heart_battery_cal_discharge_rem_time();
+
+ if (batt_stat.curr_charger_status == CHARGING) {
+ heart_battery_cal_charging_rem_time();
+ first_level_change = TRUE;
+ } else {
+ heart_battery_collect_discharge_data();
+ }
+ }
+}
+
+static int low_battery_handler(void *data)
+{
+ heart_battery_save_to_file(false);
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_battery_config(struct parse_result *result, void *user_data)
+{
+ int val;
+ int battery_capacity = 0;
+
+ if (!result)
+ return -EINVAL;
+
+ if (!strncmp(result->section, HEART_BATTERY_CONF_SECTION, sizeof(HEART_BATTERY_CONF_SECTION) + 1)) {
+ if (!strncmp(result->name, "POWER_NORMAL_MODE", sizeof("POWER_NORMAL_MODE") + 1)) {
+ val = atoi(result->value);
+ if (val > 0)
+ default_mode_spc[POWER_NORMAL_MODE] = val;
+ _D("POWER_NORMAL_MODE SPC: %d", val);
+ } else if (!strncmp(result->name, "POWER_SAVING_MODE", sizeof("POWER_SAVING_MODE") + 1)) {
+ val = atoi(result->value);
+ if (val > 0)
+ default_mode_spc[POWER_SAVING_MODE] = val;
+ _D("POWER_SAVING_MODE SPC: %d", val);
+ } else if (!strncmp(result->name, "ULTRA_SAVING_MODE", sizeof("ULTRA_SAVING_MODE") + 1)) {
+ val = atoi(result->value);
+ if (val > 0)
+ default_mode_spc[ULTRA_SAVING_MODE] = val;
+ _D("ULTRA_POWER_SAVING_MODE SPC: %d", val);
+ }
+ } else if (!strncmp(result->section, battery_header, sizeof(battery_header) + 1)) {
+ if (!strncmp(result->name, "LOGIC_V2", sizeof("LOGIC_V2") + 1)) {
+ logic_v2 = atoi(result->value);
+ _I("logic_v2 : %d", logic_v2);
+ } else if (!strncmp(result->name, "LOGIC_RUL", sizeof("LOGIC_RUL") + 1)) {
+ logic_rul = atoi(result->value);
+ _I("logic_rul : %d", logic_rul);
+ } else if (!strncmp(result->name, "BATTERY_CAPACITY", sizeof("BATTERY_CAPACITY") + 1)) {
+ battery_capacity = atoi(result->value);
+ _I("total battery capacity: %d", battery_capacity);
+
+ if(total_battery_capacity == 0 && !battery_capacity) {
+ /* sys interface battery capacity path not found, read from conf file */
+ total_battery_capacity = battery_capacity * 60; /* mAm */
+ }
+ } else if (!strncmp(result->name, "DISCHARGE_FAST", sizeof("DISCHARGE_FAST") + 1)) {
+ discharge_fast = atoi(result->value);
+ _I("discharge_fast: %d", discharge_fast);
+ } else if (!strncmp(result->name, "DISCHARGE_SLOW", sizeof("DISCHARGE_SLOW") + 1)) {
+ discharge_slow = atoi(result->value);
+ _I("discharge_slow: %d", discharge_slow);
+ } else if (!strncmp(result->name, "AVERAGE_PWR", sizeof("AVERAGE_PWR") + 1)) {
+ average_pwr = atof(result->value);
+ _I("average_power: %lf", average_pwr);
+ } else if (!strncmp(result->name, "OCV_SOC_POLY_COEF", sizeof("OCV_SOC_POLY_COEF") + 1)) {
+ char *token, *saveptr = NULL;
+ int i;
+ token = strtok_r(result->value, " ", &saveptr);
+ if (token) {
+ ocv_degree = atoi(token);
+ if (ocv_degree <= 0) {
+ _E("ocv_degree should be positive if you decide to use logic_v2");
+ return -EINVAL;
+ }
+ intg = calloc(ocv_degree, sizeof(double));
+ if (!intg) {
+ _E("Out of memory");
+ return -ENOMEM;
+ }
+ _I("Degree of OCV_SOC_POLY = %d", ocv_degree);
+
+ for (i = 0; i < ocv_degree; i++) {
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ _E("There is no OCV_SOC_POLY_COEF_%d", i + 1);
+ return -EINVAL;
+ }
+ intg[i] = atof(token);
+ _I("OCV_SOC_POLY_COEF_%d = %.9g", i + 1, intg[i]);
+ }
+ }
+ }
+ } else if (!strncmp(result->section, "POWER_PROFILE", sizeof("POWER_PROFILE") + 1)) {
+ if (!strncmp(result->name, "WIFI_ACTIVE", sizeof("WIFI_ACTIVE") + 1)) {
+ power_profile.wifi_active = atof(result->value);
+ _D("HEART WIFI_ACTIVE: %f", power_profile.wifi_active);
+ } else if (!strncmp(result->name, "WIFI_ON", sizeof("WIFI_ON") + 1)) {
+ power_profile.wifi_on = atof(result->value);
+ _D("HEART WIFI_ON: %f", power_profile.wifi_on);
+ }
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
+static void heart_battery_mode_factor_init(void)
+{
+ double val;
+
+ val = default_mode_spc[POWER_SAVING_MODE]/default_mode_spc[POWER_NORMAL_MODE];
+
+ if (1.0 < val)
+ default_mode_factor[POWER_SAVING_MODE] = val;
+ _I("POWER_SAVING_MODE factor: %f", val);
+
+ val = default_mode_spc[ULTRA_SAVING_MODE]/default_mode_spc[POWER_NORMAL_MODE];
+
+ if (1.0 < val)
+ default_mode_factor[ULTRA_SAVING_MODE] = val;
+ _I("ULTRA_POWER_SAVING_MODE factor: %f", val);
+}
+
+/*
+ * This function will read total battery capacity from sys interface
+ * example - 1500mAh or 2600mAh
+ */
+static void heart_read_battery_total_capacity(void)
+{
+ u_int32_t batt_capacity;
+
+ /*
+ * read the battery total capacity from sys interface path
+ * "/sys/class/power_supply/battery/batt_capacity"
+ * which is provided by kernel
+ */
+ if (fread_uint("/sys/class/power_supply/battery/batt_capacity",
+ &batt_capacity) != RESOURCED_ERROR_NONE) {
+ _D("This device doesn't support battery capacity information. Disable LOGIC_V2");
+ return;
+ }
+
+ snprintf(battery_header, sizeof(battery_header), "BATTERY_%d",
+ batt_capacity);
+
+ /*
+ * convert battery capacity from mAh to mAm
+ */
+ total_battery_capacity = batt_capacity * 60;
+ _I("battery capacity = %d, battery header = %s",
+ batt_capacity, battery_header);
+}
+
+/* Database related operations for heart-battery tables */
+
+static int heart_battery_stats_init_db(void)
+{
+ sqlite3 *battery_stats_db;
+ char *err_msg = NULL;
+ char buf[HEART_BATTERY_STATS_MAX] = {0, };
+ int ret;
+
+ ret = sqlite3_open(BATTERY_STATS_DB_FILE_NAME, &battery_stats_db);
+ if (ret != SQLITE_OK) {
+ _E("Can't open database %s: %s", BATTERY_STATS_DB_FILE_NAME,
+ sqlite3_errmsg(battery_stats_db));
+ goto error_db_open;
+ }
+
+ snprintf(buf, HEART_BATTERY_STATS_MAX, "%s", QUERY_CREATE_BATTERY_STATS);
+ ret = sqlite3_exec(battery_stats_db, buf, NULL, NULL, &err_msg);
+ if (ret != SQLITE_OK) {
+ _E("create failed: %s", err_msg);
+ sqlite3_free(err_msg);
+ goto error_db_open;
+ }
+ _I("Create db Success");
+
+error_db_open:
+ sqlite3_close(battery_stats_db);
+ return ret;
+}
+
+static int heart_battery_stats_db_open_transaction(sqlite3 *db)
+{
+ char *err_msg = NULL;
+
+ if (sqlite3_exec(db, "PRAGMA journal_mode = PERSIST", NULL, NULL, &err_msg) != SQLITE_OK) {
+ _E("sqlite3_exec(\"PRAGMA journal_mode = PERSIST\") failed! -> %s", err_msg);
+ sqlite3_free(err_msg);
+ return RESOURCED_ERROR_DB_FAILED;
+ }
+
+ if (sqlite3_exec(db, "BEGIN EXCLUSIVE", NULL, NULL, &err_msg) != SQLITE_OK) {
+ _E("sqlite3_exec(\"BEGIN EXCLUSIVE\") failed! -> %s", err_msg);
+ sqlite3_free(err_msg);
+ return RESOURCED_ERROR_DB_FAILED;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int heart_battery_stats_execute_insert_db(char buf[])
+{
+ sqlite3 *battery_stats_db;
+ char *err_msg = NULL;
+ int ret;
+
+ if (sqlite3_open(BATTERY_STATS_DB_FILE_NAME, &battery_stats_db) != SQLITE_OK) {
+ _E("Can't open database %s: %s", BATTERY_STATS_DB_FILE_NAME,
+ sqlite3_errmsg(battery_stats_db));
+ return RESOURCED_ERROR_DB_FAILED;
+ }
+ ret = heart_battery_stats_db_open_transaction(battery_stats_db);
+ if (ret != RESOURCED_ERROR_NONE)
+ goto error_close;
+
+ if (sqlite3_exec(battery_stats_db, buf, NULL, NULL, &err_msg) != SQLITE_OK) {
+ _E("sqlite3_exec(\"%s\") failed! -> %s", buf, err_msg);
+ sqlite3_free(err_msg);
+ goto error_db;
+ }
+
+ if (sqlite3_exec(battery_stats_db, "COMMIT", NULL, NULL, NULL) != SQLITE_OK) {
+ _E("sqlite3_exec(\"COMMIT\") failed!");
+ goto error_db;
+ }
+ _I("QUERY: %s SUCCESS", buf);
+
+ sqlite3_close(battery_stats_db);
+ return RESOURCED_ERROR_NONE;
+
+error_db:
+ if (sqlite3_exec(battery_stats_db, "ROLLBACK", NULL, NULL, NULL) != SQLITE_OK)
+ _E("sqlite3_exec(\"ROLLBACK\") failed!");
+ _I("QUERY: %s FAILED", buf);
+error_close:
+ sqlite3_close(battery_stats_db);
+ return RESOURCED_ERROR_DB_FAILED;
+}
+
+long heart_battery_stats_execute_select_total_db(char buf[])
+{
+ sqlite3 *battery_stats_db;
+ sqlite3_stmt *stmt;
+ long totaltime = 0;
+ int ret;
+
+ if (sqlite3_open(BATTERY_STATS_DB_FILE_NAME, &battery_stats_db) != SQLITE_OK) {
+ _E("Can't open database %s: %s", BATTERY_STATS_DB_FILE_NAME,
+ sqlite3_errmsg(battery_stats_db));
+ return 0;
+ }
+
+ ret = sqlite3_prepare_v2(battery_stats_db, buf, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ _E("Failed to prepare query %s", sqlite3_errmsg(battery_stats_db));
+ goto error_db;
+ }
+
+ ret = sqlite3_step(stmt);
+ switch (ret) {
+ case SQLITE_ROW:
+ _I("QUERY: %s SUCCESS", buf);
+ totaltime = (long)sqlite3_column_int(stmt, 0);
+ _D("totaltime: (%ld)", totaltime);
+ break;
+ case SQLITE_DONE:
+ _D("SQLITE_DONE");
+ break;
+ case SQLITE_ERROR:
+ /* FALLTHROUGH */
+ _E("sqlite3_step failed %s", sqlite3_errmsg(battery_stats_db));
+ default:
+ _E("RESOURCED_ERROR_DB_FAILED");
+ break;
+ }
+ sqlite3_finalize(stmt);
+error_db:
+ sqlite3_close(battery_stats_db);
+ return totaltime;
+}
+
+static void rul_data_init(void)
+{
+ _cleanup_fclose_ FILE *fp = NULL;
+ int ret, check;
+
+ rul.charging_start_time = 0;
+ rul.charging_stop_time = 0;
+ rul.raw_capacity = 0;
+ rul.soc_start = 0;
+ rul.soc_stop = 0;
+ rul.curr_soc = heart_battery_direct_get_capacity();
+ rul.prev_soc = rul.curr_soc;
+
+ /* Init LCD related data */
+ rul.lcd_data.on_start_time = 0;
+ rul.lcd_data.on_stop_time = 0;
+ rul.lcd_data.on_time = 0;
+ ret = device_display_get_state(&rul.lcd_data.state);
+ if (ret != DEVICE_ERROR_NONE) {
+ _E("Failed to get device display state with err = %d", ret);
+ return;
+ }
+
+ /* Register callback for LCD state change */
+ check = device_add_callback(DEVICE_CALLBACK_DISPLAY_STATE, rul_display_state_changed_cb, NULL);
+ if (check != DEVICE_ERROR_NONE) {
+ _E("Failed to add calback with err = %d", check);
+ //TODO: consider "rul.charging_cycles = 0;"
+ return;
+ }
+
+ /* Read Charging cycles count from file */
+ fp = fopen(RUL_CHARGING_CYCLES_FILE, "r");
+ if (fp == NULL) {
+ _E("Can't open RUL_CHARGING_CYCLES_FILE");
+ rul.charging_cycles = 0;
+ return;
+ }
+
+ if (fscanf(fp, "%d", &rul.charging_cycles) != 1) {
+ _E("Unable to assign charging cycles from file");
+ rul.charging_cycles = 0;
+ return;
+ }
+}
+
+static int heart_battery_init(void *data)
+{
+ int ret;
+ bool supported;
+
+ ret = system_info_get_platform_bool("tizen.org/feature/battery", &supported);
+ if (ret != SYSTEM_INFO_ERROR_NONE || !supported) {
+ return RESOURCED_ERROR_NOTIMPL;
+ }
+
+ ret = heart_battery_stats_init_db();
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("heart module init failed at db creation");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
+
+ ret = d_bus_register_signal(DEVICED_PATH_BATTERY,
+ DEVICED_INTERFACE_BATTERY, GET_BATTERY_CAPACITY,
+ heart_battery_capacity_status, NULL);
+ if (ret < 0)
+ _E("heart module failed to add a capacity status signal handler");
+
+ ret = d_bus_register_signal(DEVICED_PATH_BATTERY,
+ DEVICED_INTERFACE_BATTERY, GET_CHARGER_STATUS,
+ heart_battery_charger_status, NULL);
+ if (ret < 0)
+ _E("heart module failed to add a charger status signal handler");
+
+ heart_read_battery_total_capacity();
+
+ config_parse(HEART_CONF_FILE_PATH, heart_battery_config, NULL);
+ _I("heart config init");
+
+
+ heart_battery_mode_factor_init();
+
+ heart_battery_status_init();
+
+ if (logic_rul)
+ rul_data_init();
+
+ register_notifier(RESOURCED_NOTIFIER_LOW_BATTERY, low_battery_handler);
+ register_notifier(RESOURCED_NOTIFIER_DATA_RESET, heart_battery_reset);
+
+ heart_battery_set_file_commit_timestamp(logging_get_time(CLOCK_BOOTTIME));
+
+ ret = logging_module_init(BATTERY_NAME, ONE_DAY, TEN_MINUTE, heart_battery_update,
+ HEART_BATTERY_UPDATE_INTERVAL, SYSTEM_DEFAULT);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("logging module init failed");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ _D("heart battery init finished");
+ return RESOURCED_ERROR_NONE;
+}
+
+void heart_capacity_history_update(struct logging_table_form *data, void *user_data)
+{
+ int status, reset, capacity, diff;
+ unsigned long discharging = 0, charging = 0;
+ GSList **history_list = NULL;
+
+ if (user_data)
+ history_list = (GSList **)user_data;
+ else
+ history_list = &capacity_history_list;
+
+ _D("%s %s %ld %s", data->appid, data->pkgid, data->time, data->data);
+ if (sscanf(data->data, "%d %d %ld %ld %d %d ",
+ &capacity, &diff,
+ &discharging, &charging,
+ &status, &reset) < 0) {
+ _E("sscanf failed");
+ return;
+ }
+ heart_battery_insert_capacity(history_list, capacity,
+ diff, data->time, discharging, charging, status,
+ reset, false);
+}
+
+static int heart_battery_dump(FILE *fp, int mode, void *data)
+{
+ struct heart_battery_capacity *lbc;
+ GSList *iter;
+ char buf[BATTERY_DATA_MAX] = {0, };
+ int ret, size, len = 0;
+ time_t starttime;
+ char timestr[80];
+ struct tm loc_tm;
+ GSList *history_list = NULL;
+
+ starttime = time(NULL);
+ starttime -= mode;
+ localtime_r(&starttime, &loc_tm);
+ /* print timestamp */
+ strftime(timestr, sizeof(timestr),
+ "%Y-%m-%d %H:%M:%S%z", &loc_tm);
+
+ logging_read_foreach(BATTERY_NAME, NULL, NULL, starttime, 0,
+ heart_capacity_history_update, &history_list);
+
+ if (!history_list) {
+ _E("capacity history is NULL!");
+ return RESOURCED_ERROR_NONE;
+ }
+ LOG_DUMP(fp, "[BATTERY CAPACITY HISTORY] since %s\n", timestr);
+ LOG_DUMP(fp, "capacity diff timestamp used_time charging_time charger_status, reset_mark\n");
+ ret = pthread_mutex_lock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ size = g_slist_length(history_list);
+ if (!size) {
+ _I("capacity history is empty");
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_NONE;
+ }
+ gslist_for_each_item(iter, history_list) {
+ lbc = (struct heart_battery_capacity *)iter->data;
+ if (!lbc)
+ break;
+ len += snprintf(buf + len, BATTERY_DATA_MAX - len, "%d %d %ld %ld %ld %d %d\n",
+ lbc->capacity, lbc->diff_capacity, lbc->timestamp, lbc->used_time,
+ lbc->charging_time, lbc->charger_status,
+ lbc->reset_mark);
+ if (BATTERY_DATA_MAX < len + BATTERY_LINE_MAX) {
+ LOG_DUMP(fp, "%s\n", buf);
+ len = 0;
+ }
+ }
+ LOG_DUMP(fp, "%s\n", buf);
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ fflush(fp);
+ if (history_list) {
+ g_slist_free_full(history_list, free);
+ history_list = NULL;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_battery_exit(void *data)
+{
+ int ret;
+ GSList *iter, *next;
+ struct heart_battery_capacity *lbc;
+
+ heart_battery_save_to_file(true);
+ ret = pthread_mutex_lock(&heart_battery_mutex);
+ if (ret)
+ _E("pthread_mutex_lock() failed, %d", ret);
+
+ gslist_for_each_safe(capacity_history_list, iter, next, lbc) {
+ capacity_history_list = g_slist_remove(capacity_history_list, lbc);
+ free(lbc);
+ }
+ capacity_history_list = NULL;
+
+ ret = pthread_mutex_unlock(&heart_battery_mutex);
+ if (ret)
+ _E("pthread_mutex_unlock() failed, %d", ret);
+
+ unregister_notifier(RESOURCED_NOTIFIER_LOW_BATTERY, low_battery_handler);
+ unregister_notifier(RESOURCED_NOTIFIER_DATA_RESET, heart_battery_reset);
+
+ logging_module_exit();
+
+ _D("heart battery exit");
+ return RESOURCED_ERROR_NONE;
+}
+
+static const struct heart_module_ops heart_battery_ops = {
+ .name = "BATTERY",
+ .init = heart_battery_init,
+ .dump = heart_battery_dump,
+ .exit = heart_battery_exit,
+};
+HEART_MODULE_REGISTER(&heart_battery_ops)
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * @file heart-cpu.c
+ *
+ * @desc heart cpu module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <math.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "proc-common.h"
+#include "notifier.h"
+#include "resourced.h"
+#include "dbus-handler.h"
+#include "heart.h"
+#include "logging.h"
+#include "heart-common.h"
+#include "trace.h"
+#include "module.h"
+#include "macro.h"
+#include "userinfo-list.h"
+#include "proc-main.h"
+
+#define PROC_PATH "/proc/%d"
+#define PROC_STAT_PATH "/proc/%d/stat"
+#define CPU_NAME "cpu"
+#define CPU_DATA_MAX 1024
+#define CPU_ARRAY_MAX 24
+#define HEART_CPU_SAVE_INTERVAL 3600
+#define HEART_CPU_DATA_FILE HEART_USER_FILE_PATH"/.cpu.dat"
+
+enum {
+ SERVICE = 0,
+ FOREG = 1,
+ BACKG = 2
+};
+
+struct heart_cpu_info {
+ unsigned long utime;
+ unsigned long stime;
+ int state;
+ pid_t pid;
+};
+
+struct heart_cpu_table {
+ char appid[MAX_APPID_LENGTH];
+ char pkgid[MAX_PKGNAME_LENGTH];
+ unsigned long total_utime;
+ unsigned long total_stime;
+ unsigned long utime;
+ unsigned long stime;
+ int fg_count;
+ unsigned long fg_time;
+ unsigned long bg_time;
+ GSList *last_pid_info;
+ pid_t last_pid;
+ time_t last_renew_time;
+ GArray *cpu_info;
+};
+
+struct heart_cpu_dat_cache {
+ char *path;
+ GHashTable *list;
+ time_t last_file_commit_time;
+};
+
+static GHashTable *heart_cpu_app_list;
+static pthread_mutex_t heart_cpu_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void heart_cpu_remove_last_pid_info_exited(struct heart_cpu_table *table)
+{
+ char proc_path[sizeof(PROC_PATH) + MAX_DEC_SIZE(int)];
+ GSList *iter, *next;
+ struct heart_cpu_info *ci = NULL;
+
+ if (!table || !table->last_pid_info)
+ return;
+
+ gslist_for_each_safe(table->last_pid_info, iter, next, ci) {
+ snprintf(proc_path, sizeof(proc_path), PROC_PATH, ci->pid);
+ if (!access(proc_path, F_OK))
+ continue;
+ table->last_pid_info = g_slist_remove(table->last_pid_info, ci);
+ free(ci);
+ }
+}
+
+static struct heart_cpu_info *find_pid_info(struct heart_cpu_table *table, pid_t pid)
+{
+ GSList *iter = NULL;
+ struct heart_cpu_info *ci = NULL;
+
+ if (!table || !table->last_pid_info)
+ return NULL;
+
+ gslist_for_each_item(iter, table->last_pid_info) {
+ ci = (struct heart_cpu_info *)iter->data;
+ if (ci && ci->pid == pid)
+ return ci;
+ }
+ return NULL;
+}
+
+static int heart_cpu_get_cpu_time(pid_t pid, unsigned long *utime,
+ unsigned long *stime)
+{
+ char proc_path[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
+ FILE *fp;
+
+ assert(utime != NULL);
+ assert(stime != NULL);
+
+ snprintf(proc_path, sizeof(proc_path), PROC_STAT_PATH, pid);
+ fp = fopen(proc_path, "r");
+ if (fp == NULL)
+ return RESOURCED_ERROR_FAIL;
+
+ if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s") < 0) {
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (fscanf(fp, "%lu %lu", utime, stime) < 1) {
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ fclose(fp);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static GHashTable* heart_cpu_get_user_app_list(int uid)
+{
+ struct heart_cpu_dat_cache *cache;
+
+ cache = (struct heart_cpu_dat_cache*)g_hash_table_lookup(heart_cpu_app_list, (gconstpointer)&uid);
+ if (!cache) {
+ _E("There is no table of uid %d", uid);
+ return NULL;
+ }
+
+ return cache->list;
+}
+
+static int heart_cpu_write_data(struct proc_status *ps, pid_t pid, int type)
+{
+ int ret;
+ unsigned long utime, stime;
+ char info[CPU_DATA_MAX];
+ char *appid, *pkgid;
+
+ ret = heart_cpu_get_cpu_time(pid, &utime, &stime);
+ if (ret != RESOURCED_ERROR_NONE)
+ return ret;
+
+ snprintf(info, sizeof(info), "%lu %lu %d %d ", utime, stime, pid, type);
+
+ ret = proc_get_id_info(ps, &appid, &pkgid);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to proc_get_id_info");
+ return ret;
+ }
+ ret = logging_write(pid, CPU_NAME, appid, pkgid, time(NULL), info);
+ _D("heart_cpu_write_data : pid = %d, appname = %s, pkgname = %s, type=%d",
+ pid, appid, pkgid, type);
+ return ret;
+}
+
+static int heart_cpu_service_launch(void *data)
+{
+ int ret;
+ struct proc_status *ps = (struct proc_status *)data;
+
+ ret = heart_cpu_write_data(ps, ps->pid, SERVICE);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to write cpu info %d", ps->pid);
+ return ret;
+ }
+ resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_cpu_foreground_state(void *data)
+{
+ int ret;
+ struct proc_status *ps = (struct proc_status *)data;
+
+ ret = heart_cpu_write_data(ps, ps->pid, FOREG);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to write cpu info %d", ps->pid);
+ return ret;
+ }
+ resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_cpu_background_state(void *data)
+{
+ int ret;
+ GSList *giter = NULL;
+ struct proc_status *ps = (struct proc_status *)data;
+
+ ret = heart_cpu_write_data(ps, ps->pid, BACKG);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to write cpu info %d", ps->pid);
+ return ret;
+ }
+ if (!ps->pai->childs)
+ return RESOURCED_ERROR_NONE;
+ gslist_for_each_item(giter, ps->pai->childs) {
+ pid_t child = GPOINTER_TO_PID(giter->data);
+ ret = heart_cpu_write_data(ps, child, BACKG);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to write child cpu info %d", child);
+ return ret;
+ }
+ }
+ resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_cpu_update_state(void *data)
+{
+ int ret, state;
+ GSList *giter = NULL;
+ struct proc_status *ps = (struct proc_status *)data;
+
+ if (!ps->pai) {
+ _E("Invalid parameter");
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+ }
+ if (ps->pai->lru_state == PROC_FOREGROUND)
+ state = FOREG;
+ else
+ state = BACKG;
+
+ ret = heart_cpu_write_data(ps, ps->pid, state);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to write cpu info %d", ps->pid);
+ return ret;
+ }
+ _D("heart_cpu_update_state : pid = %d, state = %d",
+ ps->pid, state);
+ if (!ps->pai->childs)
+ return RESOURCED_ERROR_NONE;
+ gslist_for_each_item(giter, ps->pai->childs) {
+ pid_t child = GPOINTER_TO_PID(giter->data);
+ ret = heart_cpu_write_data(ps, child, state);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to write cpu info %d", child);
+ return ret;
+ }
+ }
+ resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_cpu_update_app_list(void *data)
+{
+ _cleanup_app_list_close_ GSList *proc_app_list = PAL_INIT_VALUE;
+ GSList *giter = NULL;
+ struct proc_app_info *pai = NULL;
+
+ proc_app_list = proc_app_list_open();
+ gslist_for_each_item(giter, proc_app_list) {
+ struct proc_status ps;
+ pai = (struct proc_app_info *)giter->data;
+ if (!pai->ai)
+ continue;
+ ps.pid = pai->main_pid;
+ ps.pai = pai;
+ heart_cpu_update_state(&ps);
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
+static void heart_cpu_free_uid(gpointer data)
+{
+ if (data)
+ free(data);
+}
+
+static void heart_cpu_free_dat_cache(gpointer data)
+{
+ struct heart_cpu_dat_cache *cache = (struct heart_cpu_dat_cache*)data;
+ if (cache) {
+ free(cache->path);
+ g_hash_table_destroy(cache->list);
+ free(cache);
+ }
+}
+
+static void heart_free_value(gpointer value)
+{
+ int i;
+ struct heart_cpu_info *info;
+ struct heart_cpu_table *table = (struct heart_cpu_table *)value;
+
+ if (!table)
+ return;
+
+ if (table->last_pid_info)
+ g_slist_free_full(table->last_pid_info, free);
+
+ if (table->cpu_info) {
+ for (i = 0; i < table->cpu_info->len; i++) {
+ info = g_array_index(table->cpu_info,
+ struct heart_cpu_info *, i);
+ free(info);
+ }
+ g_array_free(table->cpu_info, TRUE);
+ }
+
+ free(table);
+}
+
+static int heart_cpu_read_length(char *buf, int count)
+{
+ int i, find = 0;
+ int len = strlen(buf);
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] == ' ')
+ find++;
+ if (find == count)
+ return i + 1;
+ }
+ return RESOURCED_ERROR_FAIL;
+}
+
+static int heart_cpu_read_from_file(struct heart_cpu_dat_cache *cache)
+{
+ int i, len, ret, fg_count, state;
+ unsigned long total_utime, total_stime;
+ unsigned long utime, stime;
+ unsigned long fg_time, bg_time;
+ pid_t pid;
+ FILE *fp;
+ struct heart_cpu_table *table;
+ char appid[MAX_APPID_LENGTH] = {0, };
+ char pkgid[MAX_PKGNAME_LENGTH] = {0, };
+ char buf[CPU_DATA_MAX] = {0, };
+
+ if (!cache) {
+ _E("Cache doesn't exist");
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+ }
+
+ snprintf(buf, CPU_DATA_MAX, HEART_CPU_DATA_FILE, cache->path);
+ fp = fopen(buf, "r");
+ if (!fp) {
+ if (errno != ENOENT) {
+ _E("Fail to open %s (%d)", buf, errno);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ _D("%s doesn't exist. Make new one.", buf);
+ snprintf(buf, CPU_DATA_MAX, HEART_USER_FILE_PATH, cache->path);
+ ret = mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH);
+ if (ret != 0 && errno != EEXIST) {
+ _E("Fail to create %s (%d)", buf, errno);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ snprintf(buf, CPU_DATA_MAX, HEART_CPU_DATA_FILE, cache->path);
+ fp = fopen(buf, "w+");
+ if (!fp) {
+ _E("Fail to create %s (%d)", buf, errno);
+ return RESOURCED_ERROR_FAIL;
+ }
+ fclose(fp);
+ return RESOURCED_ERROR_NONE;
+ }
+
+ while (fgets(buf, CPU_DATA_MAX, fp)) {
+ table = malloc(sizeof(struct heart_cpu_table));
+
+ if (!table) {
+ _E("malloc failed");
+ fclose(fp);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* make return values */
+ ret = sscanf(buf, STR_FS(MAX_APPID_LENGTH_M1)" "STR_FS(MAX_PKGNAME_LENGTH_M1)" %lu %lu %lu %lu %lu %lu %d ",
+ appid, pkgid,
+ &total_utime, &total_stime,
+ &utime, &stime,
+ &fg_time, &bg_time, &fg_count);
+
+ if (ret <= 0) {
+ _E("sscanf failed");
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", appid) < 0) {
+ _E("sprintf failed");
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", pkgid) < 0) {
+ _E("snprintf failed");
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ len = heart_cpu_read_length(buf, 9);
+ if (len <= 0) {
+ _E("sscanf failed");
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ table->total_utime = total_utime;
+ table->total_stime = total_stime;
+ table->utime = utime;
+ table->stime = stime;
+ table->last_pid_info = NULL;
+ table->last_pid = 0;
+ table->fg_time = fg_time;
+ table->bg_time = bg_time;
+ table->fg_count = fg_count;
+ table->last_renew_time = 0;
+ table->cpu_info =
+ g_array_new(FALSE, FALSE, sizeof(struct heart_cpu_info *));
+
+ for (i = 0; i < CPU_ARRAY_MAX; i++) {
+ struct heart_cpu_info *ci;
+
+ ret = sscanf(buf + len, "%lu %lu %d %d ", &utime, &stime, &pid, &state);
+ if (ret <= 0) {
+ _E("file read fail %s", buf + len);
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ ci = malloc(sizeof(struct heart_cpu_info));
+ if (!ci) {
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+ ci->utime = utime;
+ ci->stime = stime;
+ ci->pid = pid;
+ ci->state = state;
+ len += heart_cpu_read_length(buf + len, 4);
+ g_array_append_val(table->cpu_info, ci);
+ }
+
+ ret = pthread_mutex_lock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ g_array_free(table->cpu_info, TRUE);
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ g_hash_table_insert(cache->list, (gpointer)table->appid, (gpointer)table);
+ ret = pthread_mutex_unlock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ }
+
+ fclose(fp);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_cpu_save_to_file(struct heart_cpu_dat_cache *cache)
+{
+ int i, len, ret, array_len;
+ gpointer value;
+ gpointer key;
+ GHashTableIter iter;
+ struct heart_cpu_table *table;
+ FILE *fp;
+ char buf[CPU_DATA_MAX] = {0, };
+
+ if (!cache) {
+ _D("Cache is empty. Do nothing.");
+ return RESOURCED_ERROR_NONE;
+ }
+
+ snprintf(buf, CPU_DATA_MAX, HEART_CPU_DATA_FILE, cache->path);
+ fp = fopen(buf, "w");
+ if (!fp) {
+ _E("%s fopen failed %d", buf, errno);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!(cache->list)) {
+ _E("empty app list");
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!g_hash_table_size(cache->list)) {
+ _E("hash table is empty");
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ ret = pthread_mutex_lock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ g_hash_table_iter_init(&iter, cache->list);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ table = (struct heart_cpu_table *)value;
+ array_len = table->cpu_info->len;
+ len = snprintf(buf, CPU_DATA_MAX, "%s %s %lu %lu %lu %lu %lu %lu %d ",
+ table->appid, table->pkgid,
+ table->total_utime,
+ table->total_stime,
+ table->utime,
+ table->stime,
+ table->fg_time,
+ table->bg_time,
+ table->fg_count);
+
+ for (i = 0; i < CPU_ARRAY_MAX; i++) {
+ struct heart_cpu_info *ci;
+ if (array_len <= i) {
+ len += snprintf(buf + len, CPU_DATA_MAX - len, "0 0 0 0 ");
+ } else {
+ ci = g_array_index(table->cpu_info, struct heart_cpu_info *, i);
+ if (!ci)
+ break;
+ len += snprintf(buf + len, CPU_DATA_MAX - len, "%lu %lu %d %d ",
+ ci->utime,
+ ci->stime,
+ ci->pid,
+ ci->state);
+ }
+ }
+ snprintf(buf + len, CPU_DATA_MAX - len, "\n");
+ fputs(buf, fp);
+ }
+ ret = pthread_mutex_unlock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ fclose(fp);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_cpu_hashtable_renew(GHashTable *hashtable, time_t now)
+{
+ int ret;
+ gpointer value;
+ gpointer key;
+ GHashTableIter iter;
+ struct heart_cpu_table *table;
+
+ if (!hashtable) {
+ _E("empty app list");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!g_hash_table_size(hashtable)) {
+ _E("hash table is empty");
+ return RESOURCED_ERROR_FAIL;
+ }
+ ret = pthread_mutex_lock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ g_hash_table_iter_init(&iter, hashtable);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ table = (struct heart_cpu_table *)value;
+ table->total_utime = 0;
+ table->total_stime = 0;
+ table->last_renew_time = now;
+ table->fg_count = 0;
+ table->fg_time = 0;
+ table->bg_time = 0;
+ }
+ ret = pthread_mutex_unlock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
+void heart_cpu_update(struct logging_table_form *data, void *user_data)
+{
+ const char *path;
+ int ret;
+ pid_t pid;
+ uid_t *uid;
+ int state;
+ unsigned long utime, stime;
+ unsigned long utime_diff = 0, stime_diff = 0;
+ time_t curr_time = logging_get_time(CLOCK_BOOTTIME);
+ struct heart_cpu_table *table;
+ struct heart_cpu_info *ci = NULL;
+ struct heart_cpu_dat_cache *cache;
+ GHashTable *cpu_usage_list = NULL;
+
+ cache = (struct heart_cpu_dat_cache*)g_hash_table_lookup(
+ heart_cpu_app_list, (gpointer)(&(data->uid)));
+ if (!cache) {
+ path = userinfo_find_home_dir((uid_t)data->uid);
+ if (!path) {
+ _E("uid %d doesn't existed", data->uid);
+ return;
+ }
+
+ cache = (struct heart_cpu_dat_cache*)malloc(sizeof(struct heart_cpu_dat_cache));
+ if (!cache) {
+ _E("malloc failed");
+ return;
+ }
+
+ cache->path = strndup(path, strlen(path));
+ if (!cache->path) {
+ _E("strndup failed");
+ free(cache);
+ return;
+ }
+
+ cache->list = g_hash_table_new_full(
+ g_str_hash,
+ g_str_equal,
+ NULL,
+ heart_free_value);
+ if (!cache->list) {
+ _E("g_hash_table_new_full failed");
+ free(cache->path);
+ free(cache);
+ return;
+ }
+
+ uid = malloc(sizeof(uid_t));
+ if (!uid) {
+ _E("malloc failed");
+ g_hash_table_unref(cache->list);
+ free(cache->path);
+ free(cache);
+ return;
+ }
+ *uid = (uid_t)data->uid;
+
+ g_hash_table_insert(heart_cpu_app_list, (gpointer)uid, (gpointer)cache);
+ }
+ cpu_usage_list = cache->list;
+
+ _D("%d %s %s %ld %s", data->uid, data->appid, data->pkgid, data->time, data->data);
+ if (sscanf(data->data, "%lu %lu %d %d ", &utime, &stime, &pid, &state) < 0) {
+ _E("sscanf failed");
+ return;
+ }
+
+ ret = pthread_mutex_lock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return;
+ }
+
+ /* update */
+ table = g_hash_table_lookup(cpu_usage_list, data->appid);
+ if (table) {
+
+ if (table->last_renew_time > data->time)
+ goto unlock_exit;
+
+ ci = find_pid_info(table, pid);
+ if (table->last_pid_info && ci) {
+ utime_diff = utime - ci->utime;
+ table->utime += utime_diff;
+ table->total_utime += utime_diff;
+ stime_diff = stime - ci->stime;
+ table->stime += stime_diff;
+ table->total_stime += stime_diff;
+ ci->utime = utime;
+ ci->stime = stime;
+ if (ci->state == BACKG || ci->state == SERVICE) {
+ table->bg_time += utime_diff + stime_diff;
+ if (state == FOREG)
+ table->fg_count++;
+ } else
+ table->fg_time += utime_diff + stime_diff;
+ ci->state = state;
+ } else {
+ table->utime += utime;
+ table->total_utime += utime;
+ table->stime += stime;
+ table->total_stime += stime;
+ if (table->last_pid_info)
+ heart_cpu_remove_last_pid_info_exited(table);
+ ci = malloc(sizeof(struct heart_cpu_info));
+ if (!ci) {
+ _E("malloc failed");
+ goto unlock_exit;
+ }
+ ci->pid = pid;
+ ci->utime = utime;
+ ci->stime = stime;
+ ci->state = state;
+ if (ci->state == FOREG)
+ table->fg_count++;
+ table->last_pid_info = g_slist_prepend(table->last_pid_info, ci);
+ table->last_pid = pid;
+ }
+ } else {
+ table = calloc(1, sizeof(struct heart_cpu_table));
+
+ if (!table) {
+ _E("malloc failed");
+ goto unlock_exit;
+ }
+
+ if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", data->appid) < 0) {
+ free(table);
+ _E("snprintf failed");
+ goto unlock_exit;
+ }
+
+ if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", data->pkgid) < 0) {
+ free(table);
+ _E("snprintf failed");
+ goto unlock_exit;
+ }
+ table->total_utime = utime;
+ table->total_stime = stime;
+ table->utime = utime;
+ table->stime = stime;
+ table->fg_count = 0;
+ table->fg_time = 0;
+ table->bg_time = 0;
+ if (state == FOREG)
+ table->fg_count = 1;
+
+ table->cpu_info =
+ g_array_new(FALSE, FALSE, sizeof(struct heart_cpu_info *));
+ if (!table->cpu_info) {
+ free(table);
+ _E("g_array_new failed");
+ goto unlock_exit;
+ }
+
+ ci = malloc(sizeof(struct heart_cpu_info));
+ if (!ci) {
+ _E("malloc failed");
+ free(table);
+ goto unlock_exit;
+ }
+ ci->pid = pid;
+ ci->utime = utime;
+ ci->stime = stime;
+ ci->state = state;
+ table->last_pid_info = g_slist_prepend(NULL, ci);
+ table->last_pid = pid;
+
+ g_hash_table_insert(cpu_usage_list, (gpointer)table->appid, (gpointer)table);
+ }
+ ret = pthread_mutex_unlock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return;
+ }
+
+ if (cache->last_file_commit_time + HEART_CPU_SAVE_INTERVAL < curr_time) {
+ /* all hash table update and make new array */
+ gpointer value;
+ gpointer key;
+ GHashTableIter iter;
+ struct heart_cpu_table *search;
+ struct heart_cpu_info *ci;
+
+ ret = pthread_mutex_lock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return;
+ }
+
+ g_hash_table_iter_init(&iter, cpu_usage_list);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ search = (struct heart_cpu_table *)value;
+
+ ci = malloc(sizeof(struct heart_cpu_info));
+
+ if (!ci) {
+ _E("malloc failed");
+ goto unlock_exit;
+ }
+ /* make new array node */
+ ci->pid = search->last_pid;
+ ci->utime = search->utime;
+ ci->stime = search->stime;
+ search->utime = 0;
+ search->stime = 0;
+ /* hashtable sliding : remove last node and make new one */
+ if (search->cpu_info->len == CPU_ARRAY_MAX)
+ g_array_remove_index(search->cpu_info, CPU_ARRAY_MAX - 1);
+ g_array_prepend_val(search->cpu_info, ci);
+ }
+ ret = pthread_mutex_unlock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return;
+ }
+ /* rewrite hashtable list file */
+ ret = heart_cpu_save_to_file(cache);
+ if (ret) {
+ _E("save to file failed");
+ goto unlock_exit;
+ }
+
+ cache->last_file_commit_time = curr_time;
+ }
+
+ return;
+
+unlock_exit:
+ ret = pthread_mutex_unlock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return;
+ }
+}
+
+struct heart_cpu_data *heart_cpu_get_data(int uid, char *appid, enum heart_data_period period, struct heart_cpu_data *data)
+{
+ int index, i, ret;
+ struct heart_cpu_table *table;
+ GHashTable *hashtable;
+
+ if (!appid) {
+ _E("Wrong arguments!");
+ return NULL;
+ }
+
+ hashtable = heart_cpu_get_user_app_list(uid);
+ if (!hashtable) {
+ _E("Fail to get app list");
+ return NULL;
+ }
+
+ if (!g_hash_table_size(hashtable)) {
+ _D("hash table is empty");
+ return NULL;
+ }
+
+ switch (period) {
+ case DATA_LATEST:
+ index = 0;
+ break;
+ case DATA_3HOUR:
+ index = 3;
+ break;
+ case DATA_6HOUR:
+ index = 6;
+ break;
+ case DATA_12HOUR:
+ index = 12;
+ break;
+ case DATA_1DAY:
+ index = 24;
+ break;
+ default:
+ _E("Wrong message arguments! %d", period);
+ return NULL;
+ }
+
+ ret = pthread_mutex_lock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return NULL;
+ }
+
+ table = g_hash_table_lookup(hashtable, (gconstpointer)appid);
+ if (!table) {
+ data = NULL;
+ goto unlock_exit;
+ }
+ if (snprintf(data->appid, MAX_APPID_LENGTH, "%s", table->appid) < 0) {
+ _E("snprintf failed");
+ data = NULL;
+ goto unlock_exit;
+ }
+ if (snprintf(data->pkgid, MAX_PKGNAME_LENGTH, "%s", table->pkgid) < 0) {
+ _E("snprintf failed");
+ data = NULL;
+ goto unlock_exit;
+ }
+ if (period == DATA_LATEST) {
+ data->utime = table->total_utime;
+ data->stime = table->total_stime;
+ } else {
+ data->utime = table->utime;
+ data->stime = table->stime;
+ i = table->cpu_info->len;
+ if (i == 0) {
+ data = NULL;
+ goto unlock_exit;
+ }
+ if (i < index)
+ index = i;
+ for (i = 0; i < index; i++) {
+ struct heart_cpu_info *cpu_info;
+ cpu_info =
+ g_array_index(table->cpu_info, struct heart_cpu_info *, i);
+ if (!cpu_info)
+ break;
+ data->utime += cpu_info->utime;
+ data->stime += cpu_info->stime;
+ }
+ }
+unlock_exit:
+ ret = pthread_mutex_unlock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return NULL;
+ }
+ return data;
+}
+
+static int compare_usage(const struct heart_app_usage *lau_a,
+ const struct heart_app_usage *lau_b)
+{
+ if (lau_a->point != lau_b->point)
+ return (lau_b->point - lau_a->point);
+
+ return 0;
+}
+
+/*
+ * Calculate application usage using frequency and time
+ */
+static double heart_cpu_get_point(int freq, int time)
+{
+ double weightForFrequence = 3;
+ double point = 0;
+ point = sqrt(time + (freq*weightForFrequence));
+ return point;
+}
+
+int heart_cpu_get_appusage_list(int uid, GHashTable *lists, int top)
+{
+ int index = top, i, ret;
+ gpointer value;
+ gpointer key;
+ GHashTableIter h_iter;
+ struct heart_cpu_table *table;
+ struct heart_app_usage lau;
+ GArray *app_lists = NULL;
+ GHashTable *hashtable;
+
+ hashtable = heart_cpu_get_user_app_list(uid);
+ if (!hashtable) {
+ _E("Fail to get app list");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!g_hash_table_size(hashtable)) {
+ _E("hash table is empty");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ app_lists = g_array_new(false, false, sizeof(struct heart_app_usage));
+ ret = pthread_mutex_lock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ g_array_free(app_lists, true);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ g_hash_table_iter_init(&h_iter, hashtable);
+
+ while (g_hash_table_iter_next(&h_iter, &key, &value)) {
+
+ table = (struct heart_cpu_table *)value;
+ if (!table->fg_count)
+ continue;
+
+ lau.appid = table->appid;
+ lau.pkgid = table->pkgid;
+ lau.fg_count = table->fg_count;
+ lau.used_time = table->fg_time;
+ lau.point = (int)heart_cpu_get_point(lau.fg_count, lau.used_time);
+ /*
+ * make all application lists with weighted point value excepting service application
+ */
+ g_array_append_val(app_lists, lau);
+ }
+ ret = pthread_mutex_unlock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ g_array_free(app_lists, true);
+ return RESOURCED_ERROR_FAIL;
+ }
+ if (app_lists->len < top) {
+ _I("too small data for making app usage lists");
+ g_array_free(app_lists, true);
+ return RESOURCED_ERROR_NO_DATA;
+ }
+
+ g_array_sort(app_lists, (GCompareFunc)compare_usage);
+
+ if (!top)
+ index = app_lists->len;
+
+ /*
+ * replace application usage lists with sorted usage arrays
+ */
+ g_hash_table_remove_all(lists);
+ for (i = 0; i < index; i++) {
+ struct heart_app_usage *usage = &g_array_index(app_lists, struct heart_app_usage, i);
+ _D("appid : %s, point : %d", usage->appid, usage->point);
+ g_hash_table_insert(lists, g_strndup(usage->appid, strlen(usage->appid)), GINT_TO_POINTER(1));
+ }
+ g_array_free(app_lists, true);
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_cpu_update_appid(void *data)
+{
+ int pid;
+ char old_appid[MAX_APPID_LENGTH], new_appid[MAX_APPID_LENGTH];
+ char *info;
+
+ if (!data) {
+ _E("Invalid parameter");
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+ }
+
+ info = (char*)data;
+ if (sscanf(info, "%d "STR_FS(MAX_APPID_LENGTH_M1)" "STR_FS(MAX_APPID_LENGTH_M1),
+ &pid, old_appid, new_appid) < 0) {
+ _E("sscanf failed, %m");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ return logging_modify_appid(CPU_NAME, old_appid, new_appid, pid);
+}
+
+static void dbus_heart_get_cpu_data(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int period = -1;
+ char *appid = NULL;
+ struct heart_cpu_data *data = NULL;
+
+ int uid = -1;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i&si)", &uid, &appid, &period);
+ if (uid < 0 || !appid || period < 0) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+
+ data = malloc(sizeof(struct heart_cpu_data));
+ if (!data) {
+ _E("malloc failed");
+ goto failure;
+ }
+
+ if (heart_cpu_get_data(uid, appid, period, data) == NULL)
+ goto failure;
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(ii)",
+ data->utime, data->stime));
+ free(data);
+ return;
+
+failure:
+ if (data)
+ free(data);
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_heart_get_cpu_data_list(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int period = -1, index, i, ret;
+ gpointer value;
+ gpointer key;
+ GHashTableIter h_iter;
+ struct heart_cpu_table *table;
+
+ char *appid;
+ unsigned long utime, stime, ftime, total;
+
+ int uid = -1;
+ GHashTable *hashtable;
+
+ GVariantBuilder builder, *sub_builder;
+
+ utime = stime = ftime = total = 0;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(ii)", &uid, &period);
+ if (uid < 0 || period < 0) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+
+ heart_cpu_update_app_list(NULL);
+
+ logging_save_to_storage(true);
+ /* update data list from db */
+ logging_update(true);
+
+ switch (period) {
+ case DATA_LATEST:
+ index = 0;
+ break;
+ case DATA_3HOUR:
+ index = 3;
+ break;
+ case DATA_6HOUR:
+ index = 6;
+ break;
+ case DATA_12HOUR:
+ index = 12;
+ break;
+ case DATA_1DAY:
+ index = 24;
+ break;
+ default:
+ _E("Wrong message arguments! %d", period);
+ goto failure;
+ }
+
+ hashtable = heart_cpu_get_user_app_list(uid);
+ if (!hashtable) {
+ _E("Fail to get app list");
+ goto failure;
+ }
+
+ if (!g_hash_table_size(hashtable)) {
+ _E("hash table is empty");
+ goto failure;
+ }
+
+ ret = pthread_mutex_lock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ goto failure;
+ }
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(sii)"));
+
+ g_hash_table_iter_init(&h_iter, hashtable);
+ while (g_hash_table_iter_next(&h_iter, &key, &value)) {
+ table = (struct heart_cpu_table *)value;
+ if (!table)
+ break;
+ if (period == DATA_LATEST) {
+ utime = table->total_utime;
+ stime = table->total_stime;
+ } else {
+ utime = table->utime;
+ stime = table->stime;
+ i = table->cpu_info->len;
+ if (i < index)
+ index = i;
+ for (i = 0; i < index; i++) {
+ struct heart_cpu_info *ci;
+ ci = g_array_index(table->cpu_info, struct heart_cpu_info *, i);
+ if (!ci)
+ break;
+ utime += ci->utime;
+ stime += ci->stime;
+ }
+ }
+ ftime = table->fg_time;
+ total = utime + stime;
+ if (total == 0)
+ continue;
+ appid = table->appid;
+
+ g_variant_builder_add(sub_builder, "(sii)", appid, total, ftime);
+ }
+
+ ret = pthread_mutex_unlock(&heart_cpu_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ g_variant_builder_unref(sub_builder);
+ goto failure;
+ }
+
+ g_variant_builder_add_value(&builder, g_variant_new("a(sii)", sub_builder));
+ g_variant_builder_unref(sub_builder);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_heart_reset_cpu_data(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret = -1;
+
+ GHashTableIter iter_table;
+ gpointer key, value;
+
+ g_hash_table_iter_init(&iter_table, heart_cpu_app_list);
+ while (g_hash_table_iter_next(&iter_table, &key, &value))
+ ret = heart_cpu_hashtable_renew(((struct heart_cpu_dat_cache*)value)->list, time(NULL));
+
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
+}
+
+static void dbus_heart_update_cpu_data(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ heart_cpu_update_app_list(NULL);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", 0));
+}
+
+static void dbus_heart_sync_cpu_data(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret = 0;
+
+ heart_cpu_update_app_list(NULL);
+
+ ret = logging_sync(invocation);
+ if (ret)
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
+}
+
+static void dbus_heart_save_to_file(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret;
+
+ GHashTableIter iter_table;
+ gpointer key, value;
+ struct heart_cpu_dat_cache *cache;
+
+ g_hash_table_iter_init(&iter_table, heart_cpu_app_list);
+ while (g_hash_table_iter_next(&iter_table, &key, &value)) {
+ cache = (struct heart_cpu_dat_cache*)value;
+ ret = heart_cpu_save_to_file(cache);
+ if (ret) {
+ _E("save to file failed");
+ D_BUS_REPLY_ERR(invocation);
+ return;
+ }
+ cache->last_file_commit_time = logging_get_time(CLOCK_BOOTTIME);
+ }
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
+}
+
+static const char dbus_methods_xml[] =
+" <method name='GetCpuData'>"
+" <arg type='i' name='Uid' direction='in'/>"
+" <arg type='s' name='Appid' direction='in'/>"
+" <arg type='i' name='Period' direction='in'/>"
+" <arg type='i' name='Utime' direction='out'/>"
+" <arg type='i' name='Stime' direction='out'/>"
+" </method>"
+" <method name='GetCpuDataList'>"
+" <arg type='i' name='Uid' direction='in'/>"
+" <arg type='i' name='Period' direction='in'/>"
+" <arg type='a(sii)' name='CpuTimePerApp' direction='out'/>"
+" </method>"
+" <method name='ResetCpuData'>"
+" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
+" </method>"
+" <method name='UpdateCpuData'>"
+" <arg type='i' name='Zero' direction='out'/>"
+" </method>"
+" <method name='SyncCpuData'>"
+" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
+" </method>"
+" <method name='SaveCpuData'>"
+" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
+" </method>";
+
+static struct d_bus_method dbus_methods[] = {
+ { "GetCpuData", dbus_heart_get_cpu_data },
+ { "GetCpuDataList", dbus_heart_get_cpu_data_list },
+ { "ResetCpuData", dbus_heart_reset_cpu_data },
+ { "UpdateCpuData", dbus_heart_update_cpu_data },
+ { "SyncCpuData", dbus_heart_sync_cpu_data },
+ { "SaveCpuData", dbus_heart_save_to_file },
+};
+
+static int heart_cpu_reset(void *data)
+{
+ GHashTableIter iter_table;
+ gpointer key, value;
+ int ret = RESOURCED_ERROR_FAIL;
+
+ g_hash_table_iter_init(&iter_table, heart_cpu_app_list);
+ while (g_hash_table_iter_next(&iter_table, &key, &value))
+ ret = heart_cpu_hashtable_renew(((struct heart_cpu_dat_cache*)value)->list, time(NULL));
+
+ return ret;
+}
+
+static int heart_cpu_init(void *data)
+{
+ const GArray *user_list = NULL;
+ int ret;
+ uid_t *uid;
+ struct heart_cpu_dat_cache *cache;
+
+ ret = logging_module_init(CPU_NAME, ONE_DAY, TEN_MINUTE, heart_cpu_update, TEN_MINUTE, USER_DEFAULT);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("logging module init failed");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ user_list = userinfo_get_list();
+ if (!user_list) {
+ _E("Fail to get user table");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!heart_cpu_app_list) {
+ heart_cpu_app_list = g_hash_table_new_full(
+ g_int_hash,
+ g_int_equal,
+ heart_cpu_free_uid,
+ heart_cpu_free_dat_cache);
+
+ userinfo_for_each(elem, user_list) {
+ cache = (struct heart_cpu_dat_cache*)malloc(sizeof(struct heart_cpu_dat_cache));
+ assert(cache);
+
+ cache->path = strndup(elem->home_dir, strlen(elem->home_dir));
+ cache->list = g_hash_table_new_full(
+ g_str_hash,
+ g_str_equal,
+ NULL,
+ heart_free_value);
+
+ ret = heart_cpu_read_from_file(cache);
+ assert(ret == RESOURCED_ERROR_NONE);
+
+ cache->last_file_commit_time = logging_get_time(CLOCK_BOOTTIME);
+
+ uid = malloc(sizeof(uid_t));
+ assert(uid);
+
+ *uid = elem->uid;
+ g_hash_table_insert(heart_cpu_app_list, (gpointer)uid, (gpointer)cache);
+ }
+ }
+
+ heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
+
+ register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, heart_cpu_service_launch);
+ register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, heart_cpu_foreground_state);
+ register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, heart_cpu_background_state);
+ register_notifier(RESOURCED_NOTIFIER_APP_GROUP, heart_cpu_update_appid);
+ register_notifier(RESOURCED_NOTIFIER_DATA_UPDATE, heart_cpu_update_app_list);
+ register_notifier(RESOURCED_NOTIFIER_DATA_RESET, heart_cpu_reset);
+
+ heart_cpu_get_appusage_list_func = heart_cpu_get_appusage_list;
+
+ _D("heart cpu init finished");
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_cpu_exit(void *data)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ struct heart_cpu_dat_cache *cache;
+
+ unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, heart_cpu_service_launch);
+ unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, heart_cpu_foreground_state);
+ unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, heart_cpu_background_state);
+ unregister_notifier(RESOURCED_NOTIFIER_APP_GROUP, heart_cpu_update_appid);
+ unregister_notifier(RESOURCED_NOTIFIER_DATA_UPDATE, heart_cpu_update_app_list);
+ unregister_notifier(RESOURCED_NOTIFIER_DATA_RESET, heart_cpu_reset);
+
+ if (heart_cpu_app_list) {
+ g_hash_table_iter_init(&iter, heart_cpu_app_list);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ cache = (struct heart_cpu_dat_cache*)value;
+ heart_cpu_save_to_file(cache);
+ }
+ g_hash_table_destroy(heart_cpu_app_list);
+ }
+
+ logging_module_exit();
+
+ heart_cpu_get_appusage_list_func = NULL;
+
+ _D("heart cpu exit");
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_cpu_dump(FILE *fp, int mode, void *data)
+{
+ time_t starttime;
+ char timestr[80];
+ struct tm loc_tm;
+ static GHashTable *cpu_usage_list;
+ gpointer value;
+ gpointer key;
+ GHashTableIter h_iter;
+ struct heart_cpu_table *table;
+
+ starttime = time(NULL);
+
+ starttime -= mode;
+ localtime_r(&starttime, &loc_tm);
+ /* print timestamp */
+ strftime(timestr, sizeof(timestr),
+ "%Y-%m-%d %H:%M:%S%z", &loc_tm);
+
+ cpu_usage_list = g_hash_table_new_full(
+ g_str_hash,
+ g_str_equal,
+ NULL,
+ free);
+
+
+ logging_read_foreach(CPU_NAME, NULL, NULL, starttime, 0,
+ heart_cpu_update, cpu_usage_list);
+
+ if (!g_hash_table_size(cpu_usage_list)) {
+ _E("hash table is empty");
+ return 0;
+ }
+
+ LOG_DUMP(fp, "[CPU USAGE LISTS] since %s\n", timestr);
+ LOG_DUMP(fp, "appid pkgid total fg_count fg_time\n");
+ g_hash_table_iter_init(&h_iter, cpu_usage_list);
+
+ while (g_hash_table_iter_next(&h_iter, &key, &value)) {
+
+ table = (struct heart_cpu_table *)value;
+ if (!table)
+ break;
+ LOG_DUMP(fp, "%s %s %ld %d %ld\n", table->appid, table->pkgid,
+ table->total_utime + table->total_stime,
+ table->fg_count, table->fg_time);
+ }
+ fflush(fp);
+ g_hash_table_destroy(cpu_usage_list);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static const struct heart_module_ops heart_cpu_ops = {
+ .name = "CPU",
+ .init = heart_cpu_init,
+ .dump = heart_cpu_dump,
+ .exit = heart_cpu_exit,
+};
+HEART_MODULE_REGISTER(&heart_cpu_ops)
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * @file heart-memory.c
+ *
+ * @desc heart memory module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <glib.h>
+
+#include "resourced.h"
+#include "trace.h"
+#include "module.h"
+#include "macro.h"
+#include "notifier.h"
+#include "proc-common.h"
+#include "heart.h"
+#include "logging.h"
+#include "heart-common.h"
+#include "dbus-handler.h"
+#include "procfs.h"
+#include "util.h"
+
+#include <sqlite3.h>
+#include <time.h>
+
+struct heart_memory_info {
+ unsigned int max_rss;
+ unsigned int avg_rss;
+};
+
+struct heart_memory_table {
+ char appid[MAX_APPID_LENGTH];
+ char pkgid[MAX_PKGNAME_LENGTH];
+ unsigned int total_rss;
+ unsigned int max_rss;
+ unsigned int latest_rss;
+ unsigned int count;
+ int renew;
+ GArray *memory_info;
+};
+
+static GHashTable *heart_memory_app_list;
+static pthread_mutex_t heart_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
+static time_t last_file_update_time;
+static GSource *heart_memory_update_timer = NULL;
+
+struct heart_memory_table *heart_memory_find_info(GHashTable *hashtable, char *appid)
+{
+ int ret;
+ struct heart_memory_table *table;
+
+ if (!hashtable) {
+ _E("hashtable is NULL");
+ return NULL;
+ }
+
+ ret = pthread_mutex_lock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return NULL;
+ }
+
+ table = g_hash_table_lookup(hashtable, (gconstpointer)appid);
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return NULL;
+ }
+
+ return table;
+}
+
+static void heart_memory_free_value(gpointer value)
+{
+ struct heart_memory_table * table = (struct heart_memory_table *)value;
+
+ if (table)
+ free(table);
+}
+
+static int heart_memory_read_length(char *buf, int count)
+{
+ int i, find = 0;
+ int len = strlen(buf);
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] == ' ')
+ find++;
+
+ if (find == count)
+ return i+1;
+ }
+
+ return RESOURCED_ERROR_FAIL;
+}
+
+static int heart_memory_read_from_file(GHashTable *hashtable, char *filename)
+{
+ int i, len, ret, result;
+ unsigned int total_rss, max_rss, avg_rss;
+ unsigned int count;
+ FILE *fp;
+ struct heart_memory_table *table;
+ char appid[MAX_APPID_LENGTH] = {0, };
+ char pkgid[MAX_PKGNAME_LENGTH] = {0, };
+ char buf[MEM_DATA_MAX] = {0, };
+
+ fp = fopen(filename, "r");
+
+ if (!fp) {
+ _E("%s fopen failed %d", filename, errno);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ while (fgets(buf, MEM_DATA_MAX, fp)) {
+ table = malloc(sizeof(struct heart_memory_table));
+
+ if (!table) {
+ _E("malloc failed");
+ fclose(fp);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* make return values */
+ result = sscanf(buf, STR_FS(MAX_APPID_LENGTH_M1)" "STR_FS(MAX_PKGNAME_LENGTH_M1)" %u %u %u ",
+ appid, pkgid, &total_rss, &max_rss, &count);
+
+ if (result < 0) {
+ _E("sscanf failed");
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", appid) < 0) {
+ _E("snprintf failed");
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", pkgid) < 0) {
+ _E("snprintf failed");
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ len = heart_memory_read_length(buf, 7);
+
+ if (len < 0) {
+ _E("7 space read length failed %s", buf);
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ table->total_rss = total_rss;
+ table->max_rss = max_rss;
+ table->latest_rss = 0;
+ table->count = count;
+ table->memory_info =
+ g_array_new(false, false, sizeof(struct heart_memory_info *));
+
+ for (i = 0; i < MEM_ARRAY_MAX; i++) {
+ struct heart_memory_info *mi;
+
+ result = sscanf(buf + len, "%u %u ",
+ &max_rss, &avg_rss);
+
+ if (result <= 0) {
+ _E("file read fail %s", buf + len);
+ g_array_free(table->memory_info, true);
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ mi = malloc(sizeof(struct heart_memory_info));
+
+ if (!mi) {
+ _E("malloc failed");
+ g_array_free(table->memory_info, true);
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ mi->max_rss = max_rss;
+ mi->avg_rss = avg_rss;
+
+ len += heart_memory_read_length(buf + len, 4);
+
+ g_array_append_val(table->memory_info, mi);
+ }
+
+ ret = pthread_mutex_lock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ g_array_free(table->memory_info, true);
+ free(table);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ g_hash_table_insert(hashtable, (gpointer)table->appid, (gpointer)table);
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ }
+
+ fclose(fp);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_memory_save_to_file(GHashTable *hashtable, char *filename)
+{
+ int i, len, ret, array_len;
+ gpointer value;
+ gpointer key;
+ GHashTableIter iter;
+ struct heart_memory_table *table;
+ FILE *fp;
+ char buf[MEM_DATA_MAX] = {0, };
+
+ fp = fopen(filename, "w");
+ if (!fp) {
+ _E("%s fopen failed %d", filename, errno);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ ret = pthread_mutex_lock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ g_hash_table_iter_init(&iter, hashtable);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ table = (struct heart_memory_table *)value;
+
+ len = snprintf(buf, MEM_DATA_MAX, "%s %s %u %u %u ",
+ table->appid, table->pkgid,
+ table->total_rss, table->max_rss,
+ table->count);
+
+ array_len = table->memory_info->len;
+
+ for (i = 0; i < MEM_ARRAY_MAX; i++) {
+ struct heart_memory_info *mi;
+
+ if (array_len <= i)
+ len += snprintf(buf + len, MEM_DATA_MAX - len, "0 0 0 0 ");
+ else {
+ mi = g_array_index(table->memory_info, struct heart_memory_info *, i);
+
+ len += snprintf(buf + len, MEM_DATA_MAX - len, "%u %u ",
+ mi->max_rss, mi->avg_rss);
+ }
+ }
+
+ snprintf(buf + len, MEM_DATA_MAX - len, "%c\n", MEM_FILE_SEPERATOR);
+
+ fputs(buf, fp);
+ }
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ fclose(fp);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+void heart_memory_fill_array(struct logging_table_form *data, void *user_data)
+{
+ int i;
+ unsigned int rss;
+ struct heart_memory_data *md = NULL;
+ GArray *send = NULL;
+
+ _E("data : %s %s %d %s", data->appid, data->pkgid, (int)data->time, data->data);
+ send = (GArray *)user_data;
+
+ for (i = 0; i < send->len; i++) {
+ struct heart_memory_data *loop;
+ loop = g_array_index(send, struct heart_memory_data *, i);
+
+ if (!strncmp(loop->appid, data->appid, strlen(data->appid)+1)) {
+ md = loop;
+ break;
+ }
+ }
+
+ if (sscanf(data->data, "%u", &rss) < 0) {
+ _E("sscanf failed");
+ return;
+ }
+
+ if (!md) {
+ md = malloc(sizeof(struct heart_memory_data));
+
+ if (!md) {
+ _E("malloc failed");
+ return;
+ }
+
+ if (snprintf(md->appid, MAX_APPID_LENGTH, "%s", data->appid) < 0) {
+ _E("snprintf failed");
+ free(md);
+ return;
+ }
+
+ if (snprintf(md->pkgid, MAX_PKGNAME_LENGTH, "%s", data->pkgid) < 0) {
+ _E("snprintf failed");
+ free(md);
+ return;
+ }
+
+ md->max_rss = rss;
+ md->avg_rss = rss;
+
+ g_array_append_val(send, md);
+ } else {
+ if (md->max_rss < rss)
+ md->max_rss = rss;
+
+ md->avg_rss = (md->avg_rss + rss) / 2;
+ }
+}
+
+int logging_memory_get_foreach(GArray *arrays, enum heart_data_period period)
+{
+ int ret;
+ time_t curr_time = time(NULL);
+
+ switch (period) {
+ case DATA_LATEST:
+ break;
+ case DATA_3HOUR:
+ curr_time -= 10800;
+ break;
+ case DATA_6HOUR:
+ curr_time -= 21600;
+ break;
+ case DATA_12HOUR:
+ curr_time -= 43200;
+ break;
+ case DATA_1DAY:
+ curr_time -= 86400;
+ break;
+ default:
+ _E("Wrong message arguments! %d", period);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ ret = logging_read_foreach(MEM_NAME, NULL, NULL, curr_time, 0, heart_memory_fill_array, arrays);
+
+ if (ret) {
+ _E("failed logging_read_foreach");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int heart_memory_get_query(GArray *arrays, enum heart_data_period period)
+{
+ int count, result;
+ time_t curr_time = time(NULL);
+ sqlite3 *heart_db = NULL;
+ sqlite3_stmt *stmt = NULL;
+ gpointer value;
+ gpointer key;
+ char *data;
+ unsigned int rss;
+ GHashTableIter h_iter;
+ struct heart_memory_data *md;
+ struct heart_memory_table *table;
+ char buf[MEM_DATA_MAX] = {0, };
+
+ switch (period) {
+ case DATA_LATEST:
+ break;
+ case DATA_3HOUR:
+ curr_time -= 10800;
+ break;
+ case DATA_6HOUR:
+ curr_time -= 21600;
+ break;
+ case DATA_12HOUR:
+ curr_time -= 43200;
+ break;
+ case DATA_1DAY:
+ curr_time -= 86400;
+ break;
+ default:
+ _E("Wrong message arguments! %d", period);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (logging_get_default_db(MEM_NAME, &heart_db) != RESOURCED_ERROR_NONE) {
+ _E("Fail to get DB path");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ g_hash_table_iter_init(&h_iter, heart_memory_app_list);
+
+ while (g_hash_table_iter_next(&h_iter, &key, &value)) {
+ table = (struct heart_memory_table *)value;
+
+ md = malloc(sizeof(struct heart_memory_data));
+
+ if (!md) {
+ _E("malloc failed");
+ sqlite3_finalize(stmt);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (snprintf(md->appid, MAX_APPID_LENGTH, "%s", table->appid) < 0) {
+ _E("snprintf failed");
+ free(md);
+ sqlite3_finalize(stmt);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (snprintf(md->pkgid, MAX_PKGNAME_LENGTH, "%s", table->pkgid) < 0) {
+ _E("asprintf failed");
+ free(md);
+ sqlite3_finalize(stmt);
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ count = 0;
+ md->max_rss = 0;
+ md->avg_rss = 0;
+
+ snprintf(buf, MEM_DATA_MAX, "select * from memory where appid = \'%s\' AND time > %d",
+ table->appid, (int)curr_time);
+
+ /* search from db */
+ if (sqlite3_prepare_v2(heart_db, buf, -1, &stmt, NULL) != SQLITE_OK) {
+ _E("select failed");
+ free(md);
+ sqlite3_finalize(stmt);
+ return RESOURCED_ERROR_DB_FAILED;
+ }
+
+ do {
+ result = sqlite3_step(stmt);
+ switch (result) {
+ case SQLITE_ROW:
+ data = (char *)sqlite3_column_text(stmt, 3);
+
+ if (sscanf(data, "%u", &rss) < 0) {
+ _E("sscanf failed");
+ free(md);
+ sqlite3_finalize(stmt);
+ return RESOURCED_ERROR_DB_FAILED;
+ }
+
+ if (md->max_rss < rss)
+ md->max_rss = rss;
+
+ md->avg_rss += rss;
+ count++;
+ break;
+ case SQLITE_DONE:
+ break;
+ case SQLITE_ERROR:
+ _E("select %s table failed %s",
+ MEM_NAME, sqlite3_errmsg(heart_db));
+ /* FALLTHROUGH */
+ default:
+ free(md);
+ sqlite3_finalize(stmt);
+ return RESOURCED_ERROR_DB_FAILED;
+ }
+ } while (result == SQLITE_ROW);
+ if (count)
+ md->avg_rss /= count;
+
+ g_array_append_val(arrays, md);
+ }
+
+ sqlite3_finalize(stmt);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+struct heart_memory_data *heart_memory_get_data(char *appid, enum heart_data_period period)
+{
+ int index, i, ret, count, time;
+ unsigned int max_rss = 0, avg_rss = 0, total_rss = 0;
+ struct heart_memory_table *table;
+ struct heart_memory_data *md;
+
+ if (!heart_memory_app_list)
+ return NULL;
+
+ if (!appid) {
+ _E("Wrong message arguments!");
+ return NULL;
+ }
+
+ switch (period) {
+ case DATA_LATEST:
+ index = 0;
+ break;
+ case DATA_3HOUR:
+ index = 3;
+ break;
+ case DATA_6HOUR:
+ index = 6;
+ break;
+ case DATA_12HOUR:
+ index = 12;
+ break;
+ case DATA_1DAY:
+ index = 24;
+ break;
+ default:
+ _E("Wrong message arguments! %d", period);
+ return NULL;
+ }
+
+ /* read from hash and make reply hash */
+ /* loop in file read and make reply */
+ ret = pthread_mutex_lock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return NULL;
+ }
+
+ table = g_hash_table_lookup(heart_memory_app_list, (gconstpointer)appid);
+ if (!table)
+ goto unlock_exit;
+ md = malloc(sizeof(struct heart_memory_data));
+ if (!md) {
+ _E("malloc failed");
+ goto unlock_exit;
+ }
+
+ if (snprintf(md->appid, MAX_APPID_LENGTH, "%s", table->appid) < 0) {
+ _E("snprintf failed");
+ free(md);
+ goto unlock_exit;
+ }
+
+ if (snprintf(md->pkgid, MAX_PKGNAME_LENGTH, "%s", table->pkgid) < 0) {
+ _E("snprintf failed");
+ free(md);
+ goto unlock_exit;
+ }
+
+ count = table->count;
+ total_rss = table->total_rss;
+ max_rss = table->max_rss;
+ avg_rss = total_rss / count;
+ time = 1;
+
+ if (period != DATA_LATEST) {
+ i = table->memory_info->len;
+
+ if (i < index)
+ index = i;
+
+ for (i = 0; i < index; i++) {
+ struct heart_memory_info *mi;
+
+ mi = g_array_index(table->memory_info, struct heart_memory_info *, i);
+
+ if (mi->max_rss || mi->avg_rss)
+ time++;
+
+ if (max_rss < mi->max_rss)
+ max_rss = mi->max_rss;
+
+ avg_rss += mi->avg_rss;
+ }
+
+ if (time)
+ avg_rss /= time;
+
+ }
+
+ md->max_rss = max_rss;
+ md->avg_rss = avg_rss;
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ free(md);
+ return NULL;
+ }
+ return md;
+
+unlock_exit:
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return NULL;
+ }
+ return NULL;
+}
+
+int heart_memory_get_latest_data(char *appid, unsigned int *rss)
+{
+ int ret;
+ char *data;
+ struct heart_memory_table *table;
+
+ if (!appid) {
+ _E("Wrong message arguments!");
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!heart_memory_app_list) {
+ _E("hashtable heart_memory_app_list is NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ /* read from hash and make reply hash */
+ /* loop in file read and make reply */
+ ret = pthread_mutex_lock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ table = g_hash_table_lookup(heart_memory_app_list, (gconstpointer)appid);
+ if (!table) {
+ _E("NOT found in table %s", appid);
+
+ ret = logging_get_latest_in_cache(MEM_NAME, appid, &data);
+
+ if (ret) {
+ _E("logging_get_latest_in_cache failed");
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (sscanf(data, "%u", rss) < 0) {
+ _E("sscanf failed");
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_NONE;
+ }
+
+ if (table->latest_rss) {
+ *rss = table->latest_rss;
+ } else {
+ ret = logging_get_latest_in_cache(MEM_NAME, appid, &data);
+
+ if (ret) {
+ _E("logging_get_latest_in_cache failed");
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (sscanf(data, "%u", rss) < 0) {
+ _E("sscanf failed");
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_FAIL;
+ }
+ }
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int heart_memory_get_table(GArray *arrays, enum heart_data_period period)
+{
+ int index, i, ret, count, time;
+ gpointer value;
+ gpointer key;
+ unsigned int max_rss = 0, avg_rss = 0, total_rss = 0;
+ GHashTableIter h_iter;
+ struct heart_memory_table *table;
+ struct heart_memory_data *md;
+
+ switch (period) {
+ case DATA_LATEST:
+ index = 0;
+ break;
+ case DATA_3HOUR:
+ index = 3;
+ break;
+ case DATA_6HOUR:
+ index = 6;
+ break;
+ case DATA_12HOUR:
+ index = 12;
+ break;
+ case DATA_1DAY:
+ index = 24;
+ break;
+ default:
+ _E("Wrong message arguments! %d", period);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ /* read from hash and make reply hash */
+ /* loop in file read and make reply */
+ ret = pthread_mutex_lock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ g_hash_table_iter_init(&h_iter, heart_memory_app_list);
+
+ while (g_hash_table_iter_next(&h_iter, &key, &value)) {
+ table = (struct heart_memory_table *)value;
+
+ md = malloc(sizeof(struct heart_memory_data));
+ if (!md) {
+ _E("malloc failed");
+ goto unlock_out_of_memory_exit;
+ }
+
+ if (snprintf(md->appid, MAX_APPID_LENGTH, "%s", table->appid) < 0) {
+ _E("snprintf failed");
+ free(md);
+ goto unlock_out_of_memory_exit;
+ }
+
+ if (snprintf(md->pkgid, MAX_PKGNAME_LENGTH, "%s", table->pkgid) < 0) {
+ _E("snprintf failed");
+ free(md);
+ goto unlock_out_of_memory_exit;
+ }
+
+ count = table->count;
+ total_rss = table->total_rss;
+ max_rss = table->max_rss;
+ avg_rss = total_rss / count;
+ time = 1;
+
+ if (period != DATA_LATEST) {
+ i = table->memory_info->len;
+
+ if (i < index)
+ index = i;
+
+ for (i = 0; i < index; i++) {
+ struct heart_memory_info *mi;
+
+ mi = g_array_index(table->memory_info, struct heart_memory_info *, i);
+
+ if (mi->max_rss || mi->avg_rss)
+ time++;
+
+ if (max_rss < mi->max_rss)
+ max_rss = mi->max_rss;
+
+ avg_rss += mi->avg_rss;
+ }
+
+ if (time)
+ avg_rss /= time;
+ }
+
+ md->max_rss = max_rss;
+ md->avg_rss = avg_rss;
+ g_array_append_val(arrays, md);
+ }
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ return RESOURCED_ERROR_NONE;
+
+unlock_out_of_memory_exit:
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+}
+
+void heart_memory_update(struct logging_table_form *data, void *user_data)
+{
+ int ret;
+ unsigned int rss;
+ time_t curr_time = logging_get_time(CLOCK_BOOTTIME);
+ struct heart_memory_table *find;
+ struct heart_memory_table *table;
+
+ if (sscanf(data->data, "%u", &rss) < 0) {
+ _E("sscanf failed");
+ return;
+ }
+
+ find = heart_memory_find_info(heart_memory_app_list, data->appid);
+
+ /* get last node and update it & re-insert to hash table */
+ /* update */
+ if (find) {
+ ret = pthread_mutex_lock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return;
+ }
+
+ if (find->renew) {
+ find->count = 0;
+ find->max_rss = 0;
+ find->total_rss = 0;
+ find->renew = 0;
+ }
+
+ find->total_rss += rss;
+
+ if (find->max_rss < rss)
+ find->max_rss = rss;
+
+ find->latest_rss = rss;
+
+ find->count++;
+
+ table = find;
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return;
+ }
+ } else {
+ table = malloc(sizeof(struct heart_memory_table));
+
+ if (!table) {
+ _E("malloc failed");
+ return;
+ }
+
+ if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", data->appid) < 0) {
+ free(table);
+ _E("snprintf failed");
+ return;
+ }
+
+ if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", data->pkgid) < 0) {
+ free(table);
+ _E("snprintf failed");
+ return;
+ }
+
+ table->memory_info =
+ g_array_new(false, false, sizeof(struct heart_memory_info *));
+
+ table->total_rss = rss;
+
+ table->max_rss = rss;
+
+ table->latest_rss = rss;
+
+ table->count = 1;
+
+ ret = pthread_mutex_lock(&heart_memory_mutex);
+ if (ret) {
+ free(table);
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return;
+ }
+
+ g_hash_table_insert(heart_memory_app_list, (gpointer)table->appid, (gpointer)table);
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return;
+ }
+ }
+
+ if (last_file_update_time + HEART_MEMORY_SAVE_INTERVAL < curr_time) {
+ /* all hash table update and make new array */
+ gpointer value;
+ gpointer key;
+ GHashTableIter iter;
+ struct heart_memory_table *search;
+ struct heart_memory_info *new_memory_info;
+
+ ret = pthread_mutex_lock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return;
+ }
+
+ g_hash_table_iter_init(&iter, heart_memory_app_list);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ search = (struct heart_memory_table *)value;
+
+ new_memory_info = malloc(sizeof(struct heart_memory_info));
+
+ if (!new_memory_info) {
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_lock() failed, %d", ret);
+ return;
+ }
+ _E("malloc failed");
+ return;
+ }
+
+ /* make new array node */
+ new_memory_info->max_rss = search->max_rss;
+
+ if (search->count)
+ new_memory_info->avg_rss = search->total_rss / search->count;
+ else
+ new_memory_info->avg_rss = search->total_rss;
+
+ new_memory_info->max_rss = search->max_rss;
+
+ search->renew = 1;
+
+ /* hashtable sliding : remove last node and make new one */
+ g_array_remove_index(search->memory_info, MEM_ARRAY_MAX-1);
+ g_array_prepend_val(search->memory_info, new_memory_info);
+ }
+
+ ret = pthread_mutex_unlock(&heart_memory_mutex);
+ if (ret) {
+ _E("pthread_mutex_unlock() failed, %d", ret);
+ return;
+ }
+ /* rewrite hashtable list file */
+ ret = heart_memory_save_to_file(heart_memory_app_list, HEART_MEMORY_FILE);
+ if (ret) {
+ _E("save to file failed");
+ return;
+ }
+
+ last_file_update_time = curr_time;
+ }
+}
+
+static int heart_memory_write(char *appid, char *pkgid, struct proc_status *p_data)
+{
+ _cleanup_free_ char *info = NULL;
+ unsigned int usage = 0;
+ int ret;
+ struct proc_app_info *pai = p_data->pai;
+
+ /* For write to data crud during period */
+ /* write memory usage in proc_list */
+ ret = proc_get_mem_usage(p_data->pid, &usage);
+ if (ret < 0) {
+ _E("Failed to get PID(%d) rss: %m", p_data->pid);
+ return ret;
+ }
+
+ if (pai && pai->childs) {
+ unsigned int child_usage;
+ GSList *iterchild;
+
+ gslist_for_each_item(iterchild, pai->childs) {
+ pid_t child = GPOINTER_TO_PID(iterchild->data);
+ ret = proc_get_mem_usage(child, &child_usage);
+ if (ret < 0) {
+ _E("Failed to get PID(%d) rss: %m", child);
+ continue;
+ }
+ usage += child_usage;
+ }
+ }
+
+ _SD("memory write : %s(%d), usage %u", appid, p_data->pid, usage);
+ ret = asprintf(&info, "%u", usage);
+ if (ret < 0) {
+ _E("Failed to allocate memory");
+ return -ENOMEM;
+ }
+
+ ret = logging_write(p_data->pid, MEM_NAME, appid, pkgid, time(NULL), info);
+
+ if (ret)
+ _E("logging_write failed %d", ret);
+
+ return ret;
+}
+
+static int heart_memory_state_cb(void *data)
+{
+ int ret;
+ char *appid, *pkgid;
+ struct proc_status *ps = (struct proc_status *)data;
+
+ ret = proc_get_id_info(ps, &appid, &pkgid);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Failed to proc_get_id_info");
+ return ret;
+ }
+
+ heart_memory_write(appid, pkgid, ps);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static gboolean heart_memory_notify(gpointer data)
+{
+ resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
+
+ return true;
+}
+
+static void dbus_get_memory_latest(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret;
+ char *appid = NULL;
+ unsigned int rss = 0;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(&s)", &appid);
+ if (!appid) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+
+ ret = heart_memory_get_latest_data(appid, &rss);
+
+ if (ret) {
+ _E("heart_memory_get_latest_data failed %d", ret);
+ goto failure;
+ }
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", rss));
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_get_memory_data(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int period = -1;
+ char *appid = NULL;
+ struct heart_memory_data *md;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(&si)", &appid, &period);
+ if (!appid || period < 0) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+
+ md = heart_memory_get_data(appid, period);
+ if (!md) {
+ _E("heart_memory_get_data failed");
+ goto failure;
+ }
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(uu)", md->max_rss, md->avg_rss));
+
+ free(md);
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_get_memory_data_list(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int i, ret, period = -1;
+ char *appid, *pkgid;
+ GArray *temp_array;
+ GVariantBuilder builder, *sub_builder;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &period);
+ if (period < 0) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+
+ temp_array = g_array_new(false, false, sizeof(struct heart_memory_data *));
+
+ ret = heart_memory_get_table(temp_array, period);
+
+ if (ret) {
+ _E("heart_memory_get_table failed %d", ret);
+ goto failure;
+ }
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(ssuu)"));
+
+ for (i = 0; i < temp_array->len; i++) {
+ struct heart_memory_data *md;
+
+ md = g_array_index(temp_array, struct heart_memory_data *, i);
+
+ appid = md->appid;
+ pkgid = md->pkgid;
+
+ g_variant_builder_add(sub_builder, "(ssuu)", appid, pkgid, md->max_rss, md->avg_rss);
+ }
+ g_variant_builder_add_value(&builder, g_variant_new("a(ssuu)", sub_builder));
+ g_variant_builder_unref(sub_builder);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
+
+ g_array_free(temp_array, true);
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_get_memorydb(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int i, period = -1;
+ char *appid, *pkgid;
+ GArray *temp_array;
+ GVariantBuilder builder, *sub_builder;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &period);
+ if (period < 0) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+
+ temp_array = g_array_new(false, false, sizeof(struct heart_memory_data *));
+ _E("start get read query!!! %ld", time(NULL));
+ heart_memory_get_query(temp_array, period);
+ _E("end get read query!!! %ld", time(NULL));
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(ssuu)"));
+
+ for (i = 0; i < temp_array->len; i++) {
+ struct heart_memory_data *md;
+
+ md = g_array_index(temp_array, struct heart_memory_data *, i);
+
+ appid = md->appid;
+ pkgid = md->pkgid;
+
+ g_variant_builder_add(sub_builder, "(ssuu)", appid, pkgid, md->max_rss, md->avg_rss);
+ }
+ g_variant_builder_add_value(&builder, g_variant_new("a(ssuu)", sub_builder));
+ g_variant_builder_unref(sub_builder);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
+
+ g_array_free(temp_array, true);
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_get_memoryforeach(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int i, period = -1;
+ char *appid, *pkgid;
+ GArray *temp_array;
+ GVariantBuilder builder, *sub_builder;
+
+ do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &period);
+ if (period < 0) {
+ _E("Wrong message arguments!");
+ goto failure;
+ }
+
+ /* read from query */
+ temp_array = g_array_new(false, false, sizeof(struct heart_memory_data *));
+ _E("start get read foreach!!! %ld", time(NULL));
+ logging_memory_get_foreach(temp_array, period);
+ _E("end get read foreach!!! %ld", time(NULL));
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
+ sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(ssuu)"));
+
+ for (i = 0; i < temp_array->len; i++) {
+ struct heart_memory_data *md;
+
+ md = g_array_index(temp_array, struct heart_memory_data *, i);
+
+ appid = md->appid;
+ pkgid = md->pkgid;
+
+ g_variant_builder_add(sub_builder, "(ssuu)", appid, pkgid, md->max_rss, md->avg_rss);
+ }
+ g_variant_builder_add_value(&builder, g_variant_new("a(ssuu)", sub_builder));
+ g_variant_builder_unref(sub_builder);
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
+
+ g_array_free(temp_array, true);
+ return;
+
+failure:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void dbus_memory_save_to_file(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret;
+
+ ret = heart_memory_save_to_file(heart_memory_app_list, HEART_MEMORY_FILE);
+
+ if (ret) {
+ _E("save to file failed");
+ D_BUS_REPLY_ERR(invocation);
+ return;
+ }
+
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
+}
+
+static const char dbus_methods_xml[] =
+" <method name='GetMemoryLatest'>"
+" <arg type='s' name='Appid' direction='in'/>"
+" <arg type='u' name='Rss' direction='out'/>"
+" </method>"
+" <method name='GetMemoryData'>"
+" <arg type='s' name='Appid' direction='in'/>"
+" <arg type='i' name='Period' direction='in'/>"
+" <arg type='u' name='MaxRss' direction='out'/>"
+" <arg type='u' name='AvgRss' direction='out'/>"
+" </method>"
+" <method name='GetMemoryDataList'>"
+" <arg type='i' name='Period' direction='in'/>"
+" <arg type='a(ssuu)' name='MemoryUsagePerApp' direction='out'/>"
+" </method>"
+" <method name='GetMemoryDB'>"
+" <arg type='i' name='Period' direction='in'/>"
+" <arg type='a(ssuu)' name='MemoryUsagePerApp' direction='out'/>"
+" </method>"
+" <method name='GetMemoryforeach'>"
+" <arg type='i' name='Period' direction='in'/>"
+" <arg type='a(ssuu)' name='MemoryUsagePerApp' direction='out'/>"
+" </method>"
+" <method name='SaveMemoryData'>"
+" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
+" </method>";
+
+static struct d_bus_method dbus_methods[] = {
+ { "GetMemoryLatest", dbus_get_memory_latest },
+ { "GetMemoryData", dbus_get_memory_data },
+ { "GetMemoryDataList", dbus_get_memory_data_list },
+ { "GetMemoryDB", dbus_get_memorydb },
+ { "GetMemoryforeach", dbus_get_memoryforeach },
+ { "SaveMemoryData", dbus_memory_save_to_file },
+};
+
+static int heart_memory_init(void *data)
+{
+ int ret;
+
+ ret = logging_module_init(MEM_NAME, ONE_DAY, TEN_MINUTE, heart_memory_update, TEN_MINUTE, USER_DEFAULT);
+
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("logging module init failed");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!heart_memory_app_list) {
+ heart_memory_app_list = g_hash_table_new_full(
+ g_str_hash,
+ g_str_equal,
+ NULL,
+ heart_memory_free_value);
+
+ /* make hash from file */
+ ret = heart_memory_read_from_file(heart_memory_app_list, HEART_MEMORY_FILE);
+
+ if (ret == RESOURCED_ERROR_OUT_OF_MEMORY) {
+ _E("heart_memory_init failed");
+ return ret;
+ }
+ }
+
+ register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, heart_memory_state_cb);
+ register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, heart_memory_state_cb);
+ register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, heart_memory_state_cb);
+
+ heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
+
+ last_file_update_time = logging_get_time(CLOCK_BOOTTIME);
+
+ if (heart_memory_update_timer == NULL) {
+ _D("logging memory update timer start");
+ heart_memory_update_timer = g_timeout_source_new_seconds(TEN_MINUTE);
+ g_source_set_callback(heart_memory_update_timer, heart_memory_notify, NULL, NULL);
+ g_source_attach(heart_memory_update_timer, NULL);
+ }
+
+ heart_memory_get_data_func = heart_memory_get_data;
+
+ _D("heart memory init finished");
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_memory_exit(void *data)
+{
+ int ret;
+
+ /* update timer delete */
+ g_source_destroy(heart_memory_update_timer);
+ heart_memory_update_timer = NULL;
+
+ unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, heart_memory_state_cb);
+ unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, heart_memory_state_cb);
+ unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, heart_memory_state_cb);
+
+ if (heart_memory_app_list) {
+ ret = heart_memory_save_to_file(heart_memory_app_list, HEART_MEMORY_FILE);
+
+ if (ret)
+ _E("save file failed %d", ret);
+
+ if (heart_memory_app_list) {
+ gpointer value;
+ gpointer key;
+ GHashTableIter iter;
+
+ g_hash_table_iter_init(&iter, heart_memory_app_list);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ struct heart_memory_table *table = (struct heart_memory_table *)value;
+
+ if (table->memory_info)
+ g_array_free(table->memory_info, true);
+ }
+
+ g_hash_table_destroy(heart_memory_app_list);
+ }
+ }
+
+ heart_memory_get_data_func = NULL;
+
+ logging_module_exit();
+ _D("heart memory exit");
+ return RESOURCED_ERROR_NONE;
+}
+
+static const struct heart_module_ops heart_memory_ops = {
+ .name = "MEMORY",
+ .init = heart_memory_init,
+ .exit = heart_memory_exit,
+};
+HEART_MODULE_REGISTER(&heart_memory_ops)
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * @file heart-storage.c
+ *
+ * @desc heart storage module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <stdbool.h>
+#include <time.h>
+
+#include "resourced.h"
+#include "trace.h"
+#include "module.h"
+#include "macro.h"
+#include "notifier.h"
+#include "heart.h"
+#include "logging.h"
+#include "heart-common.h"
+#include "dbus-handler.h"
+#include "proc-common.h"
+
+#include <sqlite3.h>
+
+#define STORAGE_NAME "storage"
+
+static bool heart_storage_initailized = false;
+
+static void dbus_insert_log(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int ret;
+ int pid = 0;
+ char *pkgid = NULL;
+ char *data = NULL;
+ struct proc_app_info *pai;
+
+ do_expr_unless_g_variant_get_typechecked(goto finish, params, "(&s&s)", &pkgid, &data);
+ if (!pkgid) {
+ _E("Wrong message arguments!");
+ goto finish;
+ }
+
+ pai = find_app_info_by_appid(pkgid);
+ if (!pai) {
+ _E("Failed to find the app info of %s", pkgid);
+ goto finish;
+ }
+
+ pid = pai->main_pid;
+
+ _SD("Insert record (%s, %s)", pkgid, data);
+ ret = logging_write(pid, STORAGE_NAME, pkgid, pkgid, time(NULL), data);
+ if (ret != RESOURCED_ERROR_NONE)
+ _E("Write request failed");
+
+finish:
+ g_dbus_method_invocation_return_value(invocation, NULL);
+}
+
+static const char dbus_methods_xml[] =
+" <method name='Insert'>"
+" <arg type='s' name='Pkgid' direction='in'/>"
+" <arg type='s' name='UserData' direction='in'/>"
+" </method>";
+
+static struct d_bus_method dbus_methods[] = {
+ { "Insert", dbus_insert_log },
+};
+
+static bool is_storage_logging(void)
+{
+ static const struct module_ops *block;
+
+ if (!block) {
+ block = find_module("block");
+ if (block)
+ heart_storage_initailized = true;
+ }
+
+ return heart_storage_initailized;
+}
+
+static int heart_storage_write(void *data)
+{
+ int ret;
+ struct logging_data *ld = (struct logging_data *)data;
+
+ ret = logging_write(ld->pid, STORAGE_NAME, ld->appid, ld->pkgid, time(NULL), ld->data);
+ return ret;
+}
+
+static int heart_storage_init(void *data)
+{
+ int ret;
+
+ if (!is_storage_logging())
+ return RESOURCED_ERROR_UNINITIALIZED;
+
+ ret = logging_module_init(STORAGE_NAME, FOUR_MONTH, FIVE_MINUTE, NULL, 0, USER_OWN);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("logging module init failed");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
+
+ register_notifier(RESOURCED_NOTIFIER_LOGGING_WRITE, heart_storage_write);
+ return RESOURCED_ERROR_NONE;
+}
+
+static int heart_storage_exit(void *data)
+{
+ if (!heart_storage_initailized)
+ return RESOURCED_ERROR_NONE;
+
+ _D("heart_storage exit");
+ unregister_notifier(RESOURCED_NOTIFIER_LOGGING_WRITE, heart_storage_write);
+ logging_module_exit();
+ return RESOURCED_ERROR_NONE;
+}
+
+static const struct heart_module_ops heart_storage_ops = {
+ .name = "STORAGE",
+ .init = heart_storage_init,
+ .exit = heart_storage_exit,
+};
+HEART_MODULE_REGISTER(&heart_storage_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- */
-
-/*
- * @file heart-memory.c
- *
- * @desc heart memory module
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <glib.h>
-
-#include "resourced.h"
-#include "trace.h"
-#include "module.h"
-#include "macro.h"
-#include "notifier.h"
-#include "proc-common.h"
-#include "heart.h"
-#include "logging.h"
-#include "heart-common.h"
-#include "dbus-handler.h"
-#include "procfs.h"
-#include "util.h"
-
-#include <sqlite3.h>
-#include <time.h>
-
-struct heart_memory_info {
- unsigned int max_rss;
- unsigned int avg_rss;
-};
-
-struct heart_memory_table {
- char appid[MAX_APPID_LENGTH];
- char pkgid[MAX_PKGNAME_LENGTH];
- unsigned int total_rss;
- unsigned int max_rss;
- unsigned int latest_rss;
- unsigned int count;
- int renew;
- GArray *memory_info;
-};
-
-static GHashTable *heart_memory_app_list;
-static pthread_mutex_t heart_memory_mutex = PTHREAD_MUTEX_INITIALIZER;
-static time_t last_file_update_time;
-static GSource *heart_memory_update_timer = NULL;
-
-struct heart_memory_table *heart_memory_find_info(GHashTable *hashtable, char *appid)
-{
- int ret;
- struct heart_memory_table *table;
-
- if (!hashtable) {
- _E("hashtable is NULL");
- return NULL;
- }
-
- ret = pthread_mutex_lock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return NULL;
- }
-
- table = g_hash_table_lookup(hashtable, (gconstpointer)appid);
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return NULL;
- }
-
- return table;
-}
-
-static void heart_memory_free_value(gpointer value)
-{
- struct heart_memory_table * table = (struct heart_memory_table *)value;
-
- if (table)
- free(table);
-}
-
-static int heart_memory_read_length(char *buf, int count)
-{
- int i, find = 0;
- int len = strlen(buf);
-
- for (i = 0; i < len; i++) {
- if (buf[i] == ' ')
- find++;
-
- if (find == count)
- return i+1;
- }
-
- return RESOURCED_ERROR_FAIL;
-}
-
-static int heart_memory_read_from_file(GHashTable *hashtable, char *filename)
-{
- int i, len, ret, result;
- unsigned int total_rss, max_rss, avg_rss;
- unsigned int count;
- FILE *fp;
- struct heart_memory_table *table;
- char appid[MAX_APPID_LENGTH] = {0, };
- char pkgid[MAX_PKGNAME_LENGTH] = {0, };
- char buf[MEM_DATA_MAX] = {0, };
-
- fp = fopen(filename, "r");
-
- if (!fp) {
- _E("%s fopen failed %d", filename, errno);
- return RESOURCED_ERROR_FAIL;
- }
-
- while (fgets(buf, MEM_DATA_MAX, fp)) {
- table = malloc(sizeof(struct heart_memory_table));
-
- if (!table) {
- _E("malloc failed");
- fclose(fp);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- /* make return values */
- result = sscanf(buf, STR_FS(MAX_APPID_LENGTH_M1)" "STR_FS(MAX_PKGNAME_LENGTH_M1)" %u %u %u ",
- appid, pkgid, &total_rss, &max_rss, &count);
-
- if (result < 0) {
- _E("sscanf failed");
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", appid) < 0) {
- _E("snprintf failed");
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", pkgid) < 0) {
- _E("snprintf failed");
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- len = heart_memory_read_length(buf, 7);
-
- if (len < 0) {
- _E("7 space read length failed %s", buf);
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- table->total_rss = total_rss;
- table->max_rss = max_rss;
- table->latest_rss = 0;
- table->count = count;
- table->memory_info =
- g_array_new(false, false, sizeof(struct heart_memory_info *));
-
- for (i = 0; i < MEM_ARRAY_MAX; i++) {
- struct heart_memory_info *mi;
-
- result = sscanf(buf + len, "%u %u ",
- &max_rss, &avg_rss);
-
- if (result <= 0) {
- _E("file read fail %s", buf + len);
- g_array_free(table->memory_info, true);
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- mi = malloc(sizeof(struct heart_memory_info));
-
- if (!mi) {
- _E("malloc failed");
- g_array_free(table->memory_info, true);
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- mi->max_rss = max_rss;
- mi->avg_rss = avg_rss;
-
- len += heart_memory_read_length(buf + len, 4);
-
- g_array_append_val(table->memory_info, mi);
- }
-
- ret = pthread_mutex_lock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- g_array_free(table->memory_info, true);
- free(table);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- g_hash_table_insert(hashtable, (gpointer)table->appid, (gpointer)table);
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
- }
-
- fclose(fp);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_memory_save_to_file(GHashTable *hashtable, char *filename)
-{
- int i, len, ret, array_len;
- gpointer value;
- gpointer key;
- GHashTableIter iter;
- struct heart_memory_table *table;
- FILE *fp;
- char buf[MEM_DATA_MAX] = {0, };
-
- fp = fopen(filename, "w");
- if (!fp) {
- _E("%s fopen failed %d", filename, errno);
- return RESOURCED_ERROR_FAIL;
- }
-
- ret = pthread_mutex_lock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- g_hash_table_iter_init(&iter, hashtable);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- table = (struct heart_memory_table *)value;
-
- len = snprintf(buf, MEM_DATA_MAX, "%s %s %u %u %u ",
- table->appid, table->pkgid,
- table->total_rss, table->max_rss,
- table->count);
-
- array_len = table->memory_info->len;
-
- for (i = 0; i < MEM_ARRAY_MAX; i++) {
- struct heart_memory_info *mi;
-
- if (array_len <= i)
- len += snprintf(buf + len, MEM_DATA_MAX - len, "0 0 0 0 ");
- else {
- mi = g_array_index(table->memory_info, struct heart_memory_info *, i);
-
- len += snprintf(buf + len, MEM_DATA_MAX - len, "%u %u ",
- mi->max_rss, mi->avg_rss);
- }
- }
-
- snprintf(buf + len, MEM_DATA_MAX - len, "%c\n", MEM_FILE_SEPERATOR);
-
- fputs(buf, fp);
- }
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- fclose(fp);
- return RESOURCED_ERROR_FAIL;
- }
-
- fclose(fp);
-
- return RESOURCED_ERROR_NONE;
-}
-
-void heart_memory_fill_array(struct logging_table_form *data, void *user_data)
-{
- int i;
- unsigned int rss;
- struct heart_memory_data *md = NULL;
- GArray *send = NULL;
-
- _E("data : %s %s %d %s", data->appid, data->pkgid, (int)data->time, data->data);
- send = (GArray *)user_data;
-
- for (i = 0; i < send->len; i++) {
- struct heart_memory_data *loop;
- loop = g_array_index(send, struct heart_memory_data *, i);
-
- if (!strncmp(loop->appid, data->appid, strlen(data->appid)+1)) {
- md = loop;
- break;
- }
- }
-
- if (sscanf(data->data, "%u", &rss) < 0) {
- _E("sscanf failed");
- return;
- }
-
- if (!md) {
- md = malloc(sizeof(struct heart_memory_data));
-
- if (!md) {
- _E("malloc failed");
- return;
- }
-
- if (snprintf(md->appid, MAX_APPID_LENGTH, "%s", data->appid) < 0) {
- _E("snprintf failed");
- free(md);
- return;
- }
-
- if (snprintf(md->pkgid, MAX_PKGNAME_LENGTH, "%s", data->pkgid) < 0) {
- _E("snprintf failed");
- free(md);
- return;
- }
-
- md->max_rss = rss;
- md->avg_rss = rss;
-
- g_array_append_val(send, md);
- } else {
- if (md->max_rss < rss)
- md->max_rss = rss;
-
- md->avg_rss = (md->avg_rss + rss) / 2;
- }
-}
-
-int logging_memory_get_foreach(GArray *arrays, enum heart_data_period period)
-{
- int ret;
- time_t curr_time = time(NULL);
-
- switch (period) {
- case DATA_LATEST:
- break;
- case DATA_3HOUR:
- curr_time -= 10800;
- break;
- case DATA_6HOUR:
- curr_time -= 21600;
- break;
- case DATA_12HOUR:
- curr_time -= 43200;
- break;
- case DATA_1DAY:
- curr_time -= 86400;
- break;
- default:
- _E("Wrong message arguments! %d", period);
- return RESOURCED_ERROR_FAIL;
- }
-
- ret = logging_read_foreach(MEM_NAME, NULL, NULL, curr_time, 0, heart_memory_fill_array, arrays);
-
- if (ret) {
- _E("failed logging_read_foreach");
- return RESOURCED_ERROR_FAIL;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-int heart_memory_get_query(GArray *arrays, enum heart_data_period period)
-{
- int count, result;
- time_t curr_time = time(NULL);
- sqlite3 *heart_db = NULL;
- sqlite3_stmt *stmt = NULL;
- gpointer value;
- gpointer key;
- char *data;
- unsigned int rss;
- GHashTableIter h_iter;
- struct heart_memory_data *md;
- struct heart_memory_table *table;
- char buf[MEM_DATA_MAX] = {0, };
-
- switch (period) {
- case DATA_LATEST:
- break;
- case DATA_3HOUR:
- curr_time -= 10800;
- break;
- case DATA_6HOUR:
- curr_time -= 21600;
- break;
- case DATA_12HOUR:
- curr_time -= 43200;
- break;
- case DATA_1DAY:
- curr_time -= 86400;
- break;
- default:
- _E("Wrong message arguments! %d", period);
- return RESOURCED_ERROR_FAIL;
- }
-
- if (logging_get_default_db(MEM_NAME, &heart_db) != RESOURCED_ERROR_NONE) {
- _E("Fail to get DB path");
- return RESOURCED_ERROR_FAIL;
- }
-
- g_hash_table_iter_init(&h_iter, heart_memory_app_list);
-
- while (g_hash_table_iter_next(&h_iter, &key, &value)) {
- table = (struct heart_memory_table *)value;
-
- md = malloc(sizeof(struct heart_memory_data));
-
- if (!md) {
- _E("malloc failed");
- sqlite3_finalize(stmt);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- if (snprintf(md->appid, MAX_APPID_LENGTH, "%s", table->appid) < 0) {
- _E("snprintf failed");
- free(md);
- sqlite3_finalize(stmt);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- if (snprintf(md->pkgid, MAX_PKGNAME_LENGTH, "%s", table->pkgid) < 0) {
- _E("asprintf failed");
- free(md);
- sqlite3_finalize(stmt);
- return RESOURCED_ERROR_OUT_OF_MEMORY;
- }
-
- count = 0;
- md->max_rss = 0;
- md->avg_rss = 0;
-
- snprintf(buf, MEM_DATA_MAX, "select * from memory where appid = \'%s\' AND time > %d",
- table->appid, (int)curr_time);
-
- /* search from db */
- if (sqlite3_prepare_v2(heart_db, buf, -1, &stmt, NULL) != SQLITE_OK) {
- _E("select failed");
- free(md);
- sqlite3_finalize(stmt);
- return RESOURCED_ERROR_DB_FAILED;
- }
-
- do {
- result = sqlite3_step(stmt);
- switch (result) {
- case SQLITE_ROW:
- data = (char *)sqlite3_column_text(stmt, 3);
-
- if (sscanf(data, "%u", &rss) < 0) {
- _E("sscanf failed");
- free(md);
- sqlite3_finalize(stmt);
- return RESOURCED_ERROR_DB_FAILED;
- }
-
- if (md->max_rss < rss)
- md->max_rss = rss;
-
- md->avg_rss += rss;
- count++;
- break;
- case SQLITE_DONE:
- break;
- case SQLITE_ERROR:
- _E("select %s table failed %s",
- MEM_NAME, sqlite3_errmsg(heart_db));
- /* FALLTHROUGH */
- default:
- free(md);
- sqlite3_finalize(stmt);
- return RESOURCED_ERROR_DB_FAILED;
- }
- } while (result == SQLITE_ROW);
- if (count)
- md->avg_rss /= count;
-
- g_array_append_val(arrays, md);
- }
-
- sqlite3_finalize(stmt);
-
- return RESOURCED_ERROR_NONE;
-}
-
-struct heart_memory_data *heart_memory_get_data(char *appid, enum heart_data_period period)
-{
- int index, i, ret, count, time;
- unsigned int max_rss = 0, avg_rss = 0, total_rss = 0;
- struct heart_memory_table *table;
- struct heart_memory_data *md;
-
- if (!heart_memory_app_list)
- return NULL;
-
- if (!appid) {
- _E("Wrong message arguments!");
- return NULL;
- }
-
- switch (period) {
- case DATA_LATEST:
- index = 0;
- break;
- case DATA_3HOUR:
- index = 3;
- break;
- case DATA_6HOUR:
- index = 6;
- break;
- case DATA_12HOUR:
- index = 12;
- break;
- case DATA_1DAY:
- index = 24;
- break;
- default:
- _E("Wrong message arguments! %d", period);
- return NULL;
- }
-
- /* read from hash and make reply hash */
- /* loop in file read and make reply */
- ret = pthread_mutex_lock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return NULL;
- }
-
- table = g_hash_table_lookup(heart_memory_app_list, (gconstpointer)appid);
- if (!table)
- goto unlock_exit;
- md = malloc(sizeof(struct heart_memory_data));
- if (!md) {
- _E("malloc failed");
- goto unlock_exit;
- }
-
- if (snprintf(md->appid, MAX_APPID_LENGTH, "%s", table->appid) < 0) {
- _E("snprintf failed");
- free(md);
- goto unlock_exit;
- }
-
- if (snprintf(md->pkgid, MAX_PKGNAME_LENGTH, "%s", table->pkgid) < 0) {
- _E("snprintf failed");
- free(md);
- goto unlock_exit;
- }
-
- count = table->count;
- total_rss = table->total_rss;
- max_rss = table->max_rss;
- avg_rss = total_rss / count;
- time = 1;
-
- if (period != DATA_LATEST) {
- i = table->memory_info->len;
-
- if (i < index)
- index = i;
-
- for (i = 0; i < index; i++) {
- struct heart_memory_info *mi;
-
- mi = g_array_index(table->memory_info, struct heart_memory_info *, i);
-
- if (mi->max_rss || mi->avg_rss)
- time++;
-
- if (max_rss < mi->max_rss)
- max_rss = mi->max_rss;
-
- avg_rss += mi->avg_rss;
- }
-
- if (time)
- avg_rss /= time;
-
- }
-
- md->max_rss = max_rss;
- md->avg_rss = avg_rss;
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- free(md);
- return NULL;
- }
- return md;
-
-unlock_exit:
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return NULL;
- }
- return NULL;
-}
-
-int heart_memory_get_latest_data(char *appid, unsigned int *rss)
-{
- int ret;
- char *data;
- struct heart_memory_table *table;
-
- if (!appid) {
- _E("Wrong message arguments!");
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
-
- if (!heart_memory_app_list) {
- _E("hashtable heart_memory_app_list is NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- /* read from hash and make reply hash */
- /* loop in file read and make reply */
- ret = pthread_mutex_lock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
-
- table = g_hash_table_lookup(heart_memory_app_list, (gconstpointer)appid);
- if (!table) {
- _E("NOT found in table %s", appid);
-
- ret = logging_get_latest_in_cache(MEM_NAME, appid, &data);
-
- if (ret) {
- _E("logging_get_latest_in_cache failed");
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_FAIL;
- }
-
- if (sscanf(data, "%u", rss) < 0) {
- _E("sscanf failed");
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_FAIL;
- }
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_NONE;
- }
-
- if (table->latest_rss) {
- *rss = table->latest_rss;
- } else {
- ret = logging_get_latest_in_cache(MEM_NAME, appid, &data);
-
- if (ret) {
- _E("logging_get_latest_in_cache failed");
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_FAIL;
- }
-
- if (sscanf(data, "%u", rss) < 0) {
- _E("sscanf failed");
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_FAIL;
- }
- }
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-int heart_memory_get_table(GArray *arrays, enum heart_data_period period)
-{
- int index, i, ret, count, time;
- gpointer value;
- gpointer key;
- unsigned int max_rss = 0, avg_rss = 0, total_rss = 0;
- GHashTableIter h_iter;
- struct heart_memory_table *table;
- struct heart_memory_data *md;
-
- switch (period) {
- case DATA_LATEST:
- index = 0;
- break;
- case DATA_3HOUR:
- index = 3;
- break;
- case DATA_6HOUR:
- index = 6;
- break;
- case DATA_12HOUR:
- index = 12;
- break;
- case DATA_1DAY:
- index = 24;
- break;
- default:
- _E("Wrong message arguments! %d", period);
- return RESOURCED_ERROR_FAIL;
- }
-
- /* read from hash and make reply hash */
- /* loop in file read and make reply */
- ret = pthread_mutex_lock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
-
- g_hash_table_iter_init(&h_iter, heart_memory_app_list);
-
- while (g_hash_table_iter_next(&h_iter, &key, &value)) {
- table = (struct heart_memory_table *)value;
-
- md = malloc(sizeof(struct heart_memory_data));
- if (!md) {
- _E("malloc failed");
- goto unlock_out_of_memory_exit;
- }
-
- if (snprintf(md->appid, MAX_APPID_LENGTH, "%s", table->appid) < 0) {
- _E("snprintf failed");
- free(md);
- goto unlock_out_of_memory_exit;
- }
-
- if (snprintf(md->pkgid, MAX_PKGNAME_LENGTH, "%s", table->pkgid) < 0) {
- _E("snprintf failed");
- free(md);
- goto unlock_out_of_memory_exit;
- }
-
- count = table->count;
- total_rss = table->total_rss;
- max_rss = table->max_rss;
- avg_rss = total_rss / count;
- time = 1;
-
- if (period != DATA_LATEST) {
- i = table->memory_info->len;
-
- if (i < index)
- index = i;
-
- for (i = 0; i < index; i++) {
- struct heart_memory_info *mi;
-
- mi = g_array_index(table->memory_info, struct heart_memory_info *, i);
-
- if (mi->max_rss || mi->avg_rss)
- time++;
-
- if (max_rss < mi->max_rss)
- max_rss = mi->max_rss;
-
- avg_rss += mi->avg_rss;
- }
-
- if (time)
- avg_rss /= time;
- }
-
- md->max_rss = max_rss;
- md->avg_rss = avg_rss;
- g_array_append_val(arrays, md);
- }
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
-
- return RESOURCED_ERROR_NONE;
-
-unlock_out_of_memory_exit:
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_OUT_OF_MEMORY;
-}
-
-void heart_memory_update(struct logging_table_form *data, void *user_data)
-{
- int ret;
- unsigned int rss;
- time_t curr_time = logging_get_time(CLOCK_BOOTTIME);
- struct heart_memory_table *find;
- struct heart_memory_table *table;
-
- if (sscanf(data->data, "%u", &rss) < 0) {
- _E("sscanf failed");
- return;
- }
-
- find = heart_memory_find_info(heart_memory_app_list, data->appid);
-
- /* get last node and update it & re-insert to hash table */
- /* update */
- if (find) {
- ret = pthread_mutex_lock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return;
- }
-
- if (find->renew) {
- find->count = 0;
- find->max_rss = 0;
- find->total_rss = 0;
- find->renew = 0;
- }
-
- find->total_rss += rss;
-
- if (find->max_rss < rss)
- find->max_rss = rss;
-
- find->latest_rss = rss;
-
- find->count++;
-
- table = find;
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return;
- }
- } else {
- table = malloc(sizeof(struct heart_memory_table));
-
- if (!table) {
- _E("malloc failed");
- return;
- }
-
- if (snprintf(table->appid, MAX_APPID_LENGTH, "%s", data->appid) < 0) {
- free(table);
- _E("snprintf failed");
- return;
- }
-
- if (snprintf(table->pkgid, MAX_PKGNAME_LENGTH, "%s", data->pkgid) < 0) {
- free(table);
- _E("snprintf failed");
- return;
- }
-
- table->memory_info =
- g_array_new(false, false, sizeof(struct heart_memory_info *));
-
- table->total_rss = rss;
-
- table->max_rss = rss;
-
- table->latest_rss = rss;
-
- table->count = 1;
-
- ret = pthread_mutex_lock(&heart_memory_mutex);
- if (ret) {
- free(table);
- _E("pthread_mutex_lock() failed, %d", ret);
- return;
- }
-
- g_hash_table_insert(heart_memory_app_list, (gpointer)table->appid, (gpointer)table);
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return;
- }
- }
-
- if (last_file_update_time + HEART_MEMORY_SAVE_INTERVAL < curr_time) {
- /* all hash table update and make new array */
- gpointer value;
- gpointer key;
- GHashTableIter iter;
- struct heart_memory_table *search;
- struct heart_memory_info *new_memory_info;
-
- ret = pthread_mutex_lock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return;
- }
-
- g_hash_table_iter_init(&iter, heart_memory_app_list);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- search = (struct heart_memory_table *)value;
-
- new_memory_info = malloc(sizeof(struct heart_memory_info));
-
- if (!new_memory_info) {
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_lock() failed, %d", ret);
- return;
- }
- _E("malloc failed");
- return;
- }
-
- /* make new array node */
- new_memory_info->max_rss = search->max_rss;
-
- if (search->count)
- new_memory_info->avg_rss = search->total_rss / search->count;
- else
- new_memory_info->avg_rss = search->total_rss;
-
- new_memory_info->max_rss = search->max_rss;
-
- search->renew = 1;
-
- /* hashtable sliding : remove last node and make new one */
- g_array_remove_index(search->memory_info, MEM_ARRAY_MAX-1);
- g_array_prepend_val(search->memory_info, new_memory_info);
- }
-
- ret = pthread_mutex_unlock(&heart_memory_mutex);
- if (ret) {
- _E("pthread_mutex_unlock() failed, %d", ret);
- return;
- }
- /* rewrite hashtable list file */
- ret = heart_memory_save_to_file(heart_memory_app_list, HEART_MEMORY_FILE);
- if (ret) {
- _E("save to file failed");
- return;
- }
-
- last_file_update_time = curr_time;
- }
-}
-
-static int heart_memory_write(char *appid, char *pkgid, struct proc_status *p_data)
-{
- _cleanup_free_ char *info = NULL;
- unsigned int usage = 0;
- int ret;
- struct proc_app_info *pai = p_data->pai;
-
- /* For write to data crud during period */
- /* write memory usage in proc_list */
- ret = proc_get_mem_usage(p_data->pid, &usage);
- if (ret < 0) {
- _E("Failed to get PID(%d) rss: %m", p_data->pid);
- return ret;
- }
-
- if (pai && pai->childs) {
- unsigned int child_usage;
- GSList *iterchild;
-
- gslist_for_each_item(iterchild, pai->childs) {
- pid_t child = GPOINTER_TO_PID(iterchild->data);
- ret = proc_get_mem_usage(child, &child_usage);
- if (ret < 0) {
- _E("Failed to get PID(%d) rss: %m", child);
- continue;
- }
- usage += child_usage;
- }
- }
-
- _SD("memory write : %s(%d), usage %u", appid, p_data->pid, usage);
- ret = asprintf(&info, "%u", usage);
- if (ret < 0) {
- _E("Failed to allocate memory");
- return -ENOMEM;
- }
-
- ret = logging_write(p_data->pid, MEM_NAME, appid, pkgid, time(NULL), info);
-
- if (ret)
- _E("logging_write failed %d", ret);
-
- return ret;
-}
-
-static int heart_memory_state_cb(void *data)
-{
- int ret;
- char *appid, *pkgid;
- struct proc_status *ps = (struct proc_status *)data;
-
- ret = proc_get_id_info(ps, &appid, &pkgid);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to proc_get_id_info");
- return ret;
- }
-
- heart_memory_write(appid, pkgid, ps);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static gboolean heart_memory_notify(gpointer data)
-{
- resourced_notify(RESOURCED_NOTIFIER_LOGGING_START, NULL);
-
- return true;
-}
-
-static void dbus_get_memory_latest(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret;
- char *appid = NULL;
- unsigned int rss = 0;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(&s)", &appid);
- if (!appid) {
- _E("Wrong message arguments!");
- goto failure;
- }
-
- ret = heart_memory_get_latest_data(appid, &rss);
-
- if (ret) {
- _E("heart_memory_get_latest_data failed %d", ret);
- goto failure;
- }
-
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", rss));
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_get_memory_data(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int period = -1;
- char *appid = NULL;
- struct heart_memory_data *md;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(&si)", &appid, &period);
- if (!appid || period < 0) {
- _E("Wrong message arguments!");
- goto failure;
- }
-
- md = heart_memory_get_data(appid, period);
- if (!md) {
- _E("heart_memory_get_data failed");
- goto failure;
- }
-
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(uu)", md->max_rss, md->avg_rss));
-
- free(md);
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_get_memory_data_list(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int i, ret, period = -1;
- char *appid, *pkgid;
- GArray *temp_array;
- GVariantBuilder builder, *sub_builder;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &period);
- if (period < 0) {
- _E("Wrong message arguments!");
- goto failure;
- }
-
- temp_array = g_array_new(false, false, sizeof(struct heart_memory_data *));
-
- ret = heart_memory_get_table(temp_array, period);
-
- if (ret) {
- _E("heart_memory_get_table failed %d", ret);
- goto failure;
- }
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
- sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(ssuu)"));
-
- for (i = 0; i < temp_array->len; i++) {
- struct heart_memory_data *md;
-
- md = g_array_index(temp_array, struct heart_memory_data *, i);
-
- appid = md->appid;
- pkgid = md->pkgid;
-
- g_variant_builder_add(sub_builder, "(ssuu)", appid, pkgid, md->max_rss, md->avg_rss);
- }
- g_variant_builder_add_value(&builder, g_variant_new("a(ssuu)", sub_builder));
- g_variant_builder_unref(sub_builder);
-
- g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
-
- g_array_free(temp_array, true);
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_get_memorydb(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int i, period = -1;
- char *appid, *pkgid;
- GArray *temp_array;
- GVariantBuilder builder, *sub_builder;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &period);
- if (period < 0) {
- _E("Wrong message arguments!");
- goto failure;
- }
-
- temp_array = g_array_new(false, false, sizeof(struct heart_memory_data *));
- _E("start get read query!!! %ld", time(NULL));
- heart_memory_get_query(temp_array, period);
- _E("end get read query!!! %ld", time(NULL));
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
- sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(ssuu)"));
-
- for (i = 0; i < temp_array->len; i++) {
- struct heart_memory_data *md;
-
- md = g_array_index(temp_array, struct heart_memory_data *, i);
-
- appid = md->appid;
- pkgid = md->pkgid;
-
- g_variant_builder_add(sub_builder, "(ssuu)", appid, pkgid, md->max_rss, md->avg_rss);
- }
- g_variant_builder_add_value(&builder, g_variant_new("a(ssuu)", sub_builder));
- g_variant_builder_unref(sub_builder);
-
- g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
-
- g_array_free(temp_array, true);
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_get_memoryforeach(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int i, period = -1;
- char *appid, *pkgid;
- GArray *temp_array;
- GVariantBuilder builder, *sub_builder;
-
- do_expr_unless_g_variant_get_typechecked(goto failure, params, "(i)", &period);
- if (period < 0) {
- _E("Wrong message arguments!");
- goto failure;
- }
-
- /* read from query */
- temp_array = g_array_new(false, false, sizeof(struct heart_memory_data *));
- _E("start get read foreach!!! %ld", time(NULL));
- logging_memory_get_foreach(temp_array, period);
- _E("end get read foreach!!! %ld", time(NULL));
-
- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
- sub_builder = g_variant_builder_new(G_VARIANT_TYPE("a(ssuu)"));
-
- for (i = 0; i < temp_array->len; i++) {
- struct heart_memory_data *md;
-
- md = g_array_index(temp_array, struct heart_memory_data *, i);
-
- appid = md->appid;
- pkgid = md->pkgid;
-
- g_variant_builder_add(sub_builder, "(ssuu)", appid, pkgid, md->max_rss, md->avg_rss);
- }
- g_variant_builder_add_value(&builder, g_variant_new("a(ssuu)", sub_builder));
- g_variant_builder_unref(sub_builder);
-
- g_dbus_method_invocation_return_value(invocation, g_variant_builder_end(&builder));
-
- g_array_free(temp_array, true);
- return;
-
-failure:
- D_BUS_REPLY_ERR(invocation);
-}
-
-static void dbus_memory_save_to_file(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret;
-
- ret = heart_memory_save_to_file(heart_memory_app_list, HEART_MEMORY_FILE);
-
- if (ret) {
- _E("save to file failed");
- D_BUS_REPLY_ERR(invocation);
- return;
- }
-
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
-}
-
-static const char dbus_methods_xml[] =
-" <method name='GetMemoryLatest'>"
-" <arg type='s' name='Appid' direction='in'/>"
-" <arg type='u' name='Rss' direction='out'/>"
-" </method>"
-" <method name='GetMemoryData'>"
-" <arg type='s' name='Appid' direction='in'/>"
-" <arg type='i' name='Period' direction='in'/>"
-" <arg type='u' name='MaxRss' direction='out'/>"
-" <arg type='u' name='AvgRss' direction='out'/>"
-" </method>"
-" <method name='GetMemoryDataList'>"
-" <arg type='i' name='Period' direction='in'/>"
-" <arg type='a(ssuu)' name='MemoryUsagePerApp' direction='out'/>"
-" </method>"
-" <method name='GetMemoryDB'>"
-" <arg type='i' name='Period' direction='in'/>"
-" <arg type='a(ssuu)' name='MemoryUsagePerApp' direction='out'/>"
-" </method>"
-" <method name='GetMemoryforeach'>"
-" <arg type='i' name='Period' direction='in'/>"
-" <arg type='a(ssuu)' name='MemoryUsagePerApp' direction='out'/>"
-" </method>"
-" <method name='SaveMemoryData'>"
-" <arg type='i' name='ZeroOnSuccess' direction='out'/>"
-" </method>";
-
-static struct d_bus_method dbus_methods[] = {
- { "GetMemoryLatest", dbus_get_memory_latest },
- { "GetMemoryData", dbus_get_memory_data },
- { "GetMemoryDataList", dbus_get_memory_data_list },
- { "GetMemoryDB", dbus_get_memorydb },
- { "GetMemoryforeach", dbus_get_memoryforeach },
- { "SaveMemoryData", dbus_memory_save_to_file },
-};
-
-static int heart_memory_init(void *data)
-{
- int ret;
-
- ret = logging_module_init(MEM_NAME, ONE_DAY, TEN_MINUTE, heart_memory_update, TEN_MINUTE, USER_DEFAULT);
-
- if (ret != RESOURCED_ERROR_NONE) {
- _E("logging module init failed");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!heart_memory_app_list) {
- heart_memory_app_list = g_hash_table_new_full(
- g_str_hash,
- g_str_equal,
- NULL,
- heart_memory_free_value);
-
- /* make hash from file */
- ret = heart_memory_read_from_file(heart_memory_app_list, HEART_MEMORY_FILE);
-
- if (ret == RESOURCED_ERROR_OUT_OF_MEMORY) {
- _E("heart_memory_init failed");
- return ret;
- }
- }
-
- register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, heart_memory_state_cb);
- register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, heart_memory_state_cb);
- register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, heart_memory_state_cb);
-
- heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
-
- last_file_update_time = logging_get_time(CLOCK_BOOTTIME);
-
- if (heart_memory_update_timer == NULL) {
- _D("logging memory update timer start");
- heart_memory_update_timer = g_timeout_source_new_seconds(TEN_MINUTE);
- g_source_set_callback(heart_memory_update_timer, heart_memory_notify, NULL, NULL);
- g_source_attach(heart_memory_update_timer, NULL);
- }
-
- heart_memory_get_data_func = heart_memory_get_data;
-
- _D("heart memory init finished");
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_memory_exit(void *data)
-{
- int ret;
-
- /* update timer delete */
- g_source_destroy(heart_memory_update_timer);
- heart_memory_update_timer = NULL;
-
- unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, heart_memory_state_cb);
- unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, heart_memory_state_cb);
- unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, heart_memory_state_cb);
-
- if (heart_memory_app_list) {
- ret = heart_memory_save_to_file(heart_memory_app_list, HEART_MEMORY_FILE);
-
- if (ret)
- _E("save file failed %d", ret);
-
- if (heart_memory_app_list) {
- gpointer value;
- gpointer key;
- GHashTableIter iter;
-
- g_hash_table_iter_init(&iter, heart_memory_app_list);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- struct heart_memory_table *table = (struct heart_memory_table *)value;
-
- if (table->memory_info)
- g_array_free(table->memory_info, true);
- }
-
- g_hash_table_destroy(heart_memory_app_list);
- }
- }
-
- heart_memory_get_data_func = NULL;
-
- logging_module_exit();
- _D("heart memory exit");
- return RESOURCED_ERROR_NONE;
-}
-
-static const struct heart_module_ops heart_memory_ops = {
- .name = "MEMORY",
- .init = heart_memory_init,
- .exit = heart_memory_exit,
-};
-HEART_MODULE_REGISTER(&heart_memory_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- */
-
-/*
- * @file heart-storage.c
- *
- * @desc heart storage module
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <stdbool.h>
-#include <time.h>
-
-#include "resourced.h"
-#include "trace.h"
-#include "module.h"
-#include "macro.h"
-#include "notifier.h"
-#include "heart.h"
-#include "logging.h"
-#include "heart-common.h"
-#include "dbus-handler.h"
-#include "proc-common.h"
-
-#include <sqlite3.h>
-
-#define STORAGE_NAME "storage"
-
-static bool heart_storage_initailized = false;
-
-static void dbus_insert_log(GDBusMethodInvocation *invocation, GVariant *params)
-{
- int ret;
- int pid = 0;
- char *pkgid = NULL;
- char *data = NULL;
- struct proc_app_info *pai;
-
- do_expr_unless_g_variant_get_typechecked(goto finish, params, "(&s&s)", &pkgid, &data);
- if (!pkgid) {
- _E("Wrong message arguments!");
- goto finish;
- }
-
- pai = find_app_info_by_appid(pkgid);
- if (!pai) {
- _E("Failed to find the app info of %s", pkgid);
- goto finish;
- }
-
- pid = pai->main_pid;
-
- _SD("Insert record (%s, %s)", pkgid, data);
- ret = logging_write(pid, STORAGE_NAME, pkgid, pkgid, time(NULL), data);
- if (ret != RESOURCED_ERROR_NONE)
- _E("Write request failed");
-
-finish:
- g_dbus_method_invocation_return_value(invocation, NULL);
-}
-
-static const char dbus_methods_xml[] =
-" <method name='Insert'>"
-" <arg type='s' name='Pkgid' direction='in'/>"
-" <arg type='s' name='UserData' direction='in'/>"
-" </method>";
-
-static struct d_bus_method dbus_methods[] = {
- { "Insert", dbus_insert_log },
-};
-
-static bool is_storage_logging(void)
-{
- static const struct module_ops *block;
-
- if (!block) {
- block = find_module("block");
- if (block)
- heart_storage_initailized = true;
- }
-
- return heart_storage_initailized;
-}
-
-static int heart_storage_write(void *data)
-{
- int ret;
- struct logging_data *ld = (struct logging_data *)data;
-
- ret = logging_write(ld->pid, STORAGE_NAME, ld->appid, ld->pkgid, time(NULL), ld->data);
- return ret;
-}
-
-static int heart_storage_init(void *data)
-{
- int ret;
-
- if (!is_storage_logging())
- return RESOURCED_ERROR_UNINITIALIZED;
-
- ret = logging_module_init(STORAGE_NAME, FOUR_MONTH, FIVE_MINUTE, NULL, 0, USER_OWN);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("logging module init failed");
- return RESOURCED_ERROR_FAIL;
- }
-
- heart_dbus_declare_methods(dbus_methods_xml, dbus_methods, ARRAY_SIZE(dbus_methods));
-
- register_notifier(RESOURCED_NOTIFIER_LOGGING_WRITE, heart_storage_write);
- return RESOURCED_ERROR_NONE;
-}
-
-static int heart_storage_exit(void *data)
-{
- if (!heart_storage_initailized)
- return RESOURCED_ERROR_NONE;
-
- _D("heart_storage exit");
- unregister_notifier(RESOURCED_NOTIFIER_LOGGING_WRITE, heart_storage_write);
- logging_module_exit();
- return RESOURCED_ERROR_NONE;
-}
-
-static const struct heart_module_ops heart_storage_ops = {
- .name = "STORAGE",
- .init = heart_storage_init,
- .exit = heart_storage_exit,
-};
-HEART_MODULE_REGISTER(&heart_storage_ops)
--- /dev/null
+/*
+ * resourced:compaction
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <sys/syscall.h>
+
+#include "config-parser.h"
+#include "module.h"
+#include "macro.h"
+#include "memory-cgroup.h"
+#include "notifier.h"
+#include "procfs.h"
+#include "resourced.h"
+#include "trace.h"
+#include "util.h"
+#include "compact-common.h"
+
+/**
+ * State bit for zone's fragmentation warning
+ * ZONE_FRAG_WARN_RAISE bit is set for each zone
+ * when the fragmentation level reaches specified
+ * value for at least one of supported page orders.
+ */
+#define ZONE_FRAG_WARN_RAISE (0x1 << 0)
+
+/* Internal compaction module states */
+#define COMPACT_IDLE (0)
+/* State NOTIFIED is to eliminate spurious thread wakeups */
+#define COMPACT_NOTIFIED (1 << 0)
+/* Failed to write to procfs entry */
+#define COMPACT_FAILURE (1 << 1)
+/**
+ * Failed to perform one of the basic operations:
+ * like reading /proc/zoneinfo or /proc/pagetypeinfo
+ * Set to indicate that there is no point of return
+ * and that the compaction thread should/can safely
+ * clean things up and call it a day.
+ **/
+#define COMPACT_WITHDRAW (1 << 2)
+/**
+ * Set when compaction module has been explicitly
+ * requested to quit
+ */
+#define COMPACT_CANCEL (1 << 3)
+#define COMPACT_SKIP (COMPACT_WITHDRAW | COMPACT_CANCEL)
+
+#define MAX_PAGE_ORDER 0xa
+#define ZONE_MAX_NR 4
+
+#define PROC_COMPACT_ENTRY "/proc/sys/vm/compact_memory"
+#define COMPACT_CONF_FILE RD_CONFIG_FILE(optimizer)
+
+#define COMPACT_CONFIG_SECTION "Compaction"
+#define COMPACT_CONFIG_ENABLE "CompactEnable"
+#define COMPACT_CONFIG_FRAG "Fraglevel"
+
+/**
+ * Default frag level (percentage, order-based) which determines
+ * when to trigger compaction.
+ */
+#define COMPACT_DEF_FRAG_LEVEL 800 /* 80% */
+
+/*
+ * Note: Tightly coupled with corresponding ids.
+ * Mind while modifying.
+ */
+static const char *zone_names[] = {"Normal", "DMA", "HighMem", "DMA32"};
+
+struct parser_data {
+ struct memory_info *mem_info;
+ struct zone_info *zone;
+};
+
+struct zone_info {
+ unsigned int id;
+ unsigned long pages_per_order[MAX_PAGE_ORDER +1];
+ unsigned long free_pages;
+ unsigned long wm_min;
+ unsigned long wm_low;
+ unsigned long wm_high;
+ unsigned long managed;
+ unsigned int frag_map:MAX_PAGE_ORDER+1;
+ unsigned int frag_warn:2;
+};
+
+struct memory_info {
+ unsigned int zone_count;
+ struct zone_info zones[ZONE_MAX_NR];
+};
+
+struct compact_control {
+ struct memory_info *mem_info;
+ pthread_t compact_thread;
+ pthread_mutex_t lock;
+ int frag_level;
+ unsigned int status;
+ unsigned int compact_type;
+};
+
+#define PARSE_TAG(exp, fn, id) \
+ { \
+ .re_exp = exp, \
+ .callback = fn, \
+ .tag = PARSE_TAG_##id, \
+ }
+
+#define PARSE_TAG_EMPTY() {0,}
+
+/*
+ * @TODO: This should be attached to module ops
+ */
+struct compact_data {
+ struct compact_control *compact;
+ pthread_mutex_t notify_lock;
+ pthread_cond_t notify;
+ pthread_mutex_t drained_lock;
+ pthread_cond_t drained;
+};
+
+static struct compact_data compact_data = {
+ .notify_lock = PTHREAD_MUTEX_INITIALIZER,
+ .notify = PTHREAD_COND_INITIALIZER,
+ .drained_lock = PTHREAD_MUTEX_INITIALIZER,
+ .drained = PTHREAD_COND_INITIALIZER
+};
+
+static inline unsigned int get_zone_id(const char *zone_name, size_t len)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(zone_names); ++i) {
+ if (!strncmp(zone_name, zone_names[i], len))
+ return 1 << i;
+ }
+ return 0;
+}
+
+static inline const char *get_zone_name(unsigned int zone_id)
+{
+ unsigned int i = ffs(zone_id) - 1;
+
+ return (i < ARRAY_SIZE(zone_names)) ? zone_names[i] : NULL;
+}
+
+/*
+ * External fragmentation is an issue but one that mostly kernel
+ * should be concerned about, not the user space.
+ * Still though, fragmented *physical* memory may (but does not
+ * have to) lead to system getting less responsive - as the kernel
+ * might get trapped waiting for allocation of high-order
+ * physically-contiguous pages. The fragmentation issue gets more
+ * significant in case of huge pages - thought this is left aside
+ * due to not being relevant, in this particular case.
+ *
+ * Triggering the compaction from the user-space is a rather
+ * nasty hack. But if this is to be done, than...
+ * 1. There is not much point in triggering compaction if
+ * the system is already at a heavy memory pressure
+ * and it is struggling to satisfy 0-order allocations
+ * 2. Specifying the overall fragmentation level is quite tricky
+ * and without some decent background of what is/has been going
+ * on as far as memory allocations are being concern (both from
+ * user-space and from the kernel) is not really reliable, to say
+ * at least. All in all, what's the acceptable (whatever it means)
+ * level for external fragmentation? Having most of the available
+ * memory within the low-order page blocks should raise an alert,
+ * but that's only in theory. Things get more complicated when taking
+ * into consideration the migration types of available pages.
+ * This might go wrong in so many ways .....
+ * Shall this be continued ?
+ */
+static void compaction_start(struct compact_control *compact)
+{
+ struct memory_info *mem_info;
+ int current_status = COMPACT_IDLE;
+ _cleanup_close_ int fd = -1;
+ int n = 1;
+
+ pthread_mutex_lock(&compact->lock);
+
+ if (compact->status & COMPACT_SKIP)
+ current_status |= COMPACT_WITHDRAW;
+
+ pthread_mutex_unlock(&compact->lock);
+
+ if (current_status & COMPACT_WITHDRAW)
+ return;
+
+ mem_info = compact->mem_info;
+
+
+ fd = open(PROC_COMPACT_ENTRY, O_WRONLY);
+ if (fd < 0) {
+ if (errno == EACCES || errno == EFAULT || errno == ENOENT)
+ current_status |= COMPACT_WITHDRAW;
+ _E("Compaction: failed to open procfs entry [%d]\n", errno);
+ goto leave;
+ }
+ /*
+ * It doesn't really matter what gets written,
+ * as long as smth gets....
+ */
+ if (write(fd, &n, sizeof(n)) <= 0)
+ current_status |= COMPACT_FAILURE;
+ /*
+ * Reset the external fragmentation warnings.
+ * Locking is not required here as all updates will get suspended
+ * until the compaction status won't indicate all is done here
+ */
+ if (current_status & COMPACT_FAILURE)
+ goto leave;
+
+ for (n = 0; n < mem_info->zone_count; ++n)
+ mem_info->zones[n].frag_warn &= ~ZONE_FRAG_WARN_RAISE;
+leave:
+
+ pthread_mutex_lock(&compact->lock);
+ compact->status |= current_status;
+ pthread_mutex_unlock(&compact->lock);
+}
+
+static void compact_validate_zone(struct zone_info *zone,
+ unsigned int frag_level,
+ struct memory_info *mem_info)
+{
+ int order, req_order;
+ unsigned int current_frag_map = 0;
+ /*
+ * Skip compaction if the system is below the low watermark.
+ * It's gonna be done either way
+ */
+ if (zone->free_pages < zone->wm_low) {
+ _I("Skipping validation due to falling below the low watermark\n");
+ _I("Zone %s: number of free pages: %lu low watermark: %lu\n",
+ get_zone_name(zone->id),
+ zone->free_pages, zone->wm_low);
+ return;
+ }
+
+ for (req_order = 1; req_order <= MAX_PAGE_ORDER; ++req_order) {
+ unsigned long available_pages = 0;
+
+ for (order = req_order; order <= MAX_PAGE_ORDER; ++order)
+ available_pages += zone->pages_per_order[order] << order;
+
+ if (zone->free_pages > 0 && (1000 - (available_pages * 1000 / zone->free_pages)) >= frag_level)
+ current_frag_map |= 1 << req_order;
+ }
+
+ if (current_frag_map) {
+
+ if ((!zone->frag_map && current_frag_map) ||
+ ((zone->frag_map ^ current_frag_map) &&
+ !((zone->frag_map ^ current_frag_map) & zone->frag_map)))
+
+ zone->frag_warn |= ZONE_FRAG_WARN_RAISE;
+ }
+
+ zone->frag_map = current_frag_map;
+}
+
+static void compaction_verify_zone(struct compact_control *compact,
+ struct zone_info *zone)
+{
+ struct memory_info *mem_info = compact->mem_info;
+
+ /*
+ * Here comes the shady part:
+ * without some decent memory tracing here it is
+ * truly difficult to determine whether the compaction
+ * is required or not.
+ */
+ compact_validate_zone(zone, compact->frag_level, mem_info);
+}
+
+static void compaction_verify(struct compact_control *compact)
+{
+ /* Get the overall idea of current external fragmentation */
+ struct memory_info *mem_info = compact->mem_info;
+ unsigned int compact_targets = 0;
+ int n;
+
+ /*
+ * Verify each zone although the compaction can be
+ * triggered per node (or globally) only.
+ */
+ for (n = 0; n < mem_info->zone_count; ++n) {
+ struct zone_info *zone = &mem_info->zones[n];
+
+ /*
+ * Some devices make a zone but don't allocate any pages for it.
+ * We can ignore these empty zones.
+ */
+ if (zone->managed <= 0)
+ continue;
+
+ compaction_verify_zone(compact, zone);
+ if (zone->frag_warn & ZONE_FRAG_WARN_RAISE) {
+ /*
+ * As the compaction can be triggered either globally
+ * or on per-node it's enough to have at least one
+ * zone for which the external fragmentation got
+ * dangerously high. Still to have a minimum control
+ * over the whole process - validate all zones.
+ */
+ ++compact_targets;
+ }
+ }
+
+ if (compact_targets)
+ compaction_start(compact);
+}
+
+
+#define compact_zoneinfo_set(zone, _off, v) \
+ (*(typeof(v)*)(((char*)(zone)) + _off) = v)
+
+
+static int compact_parse_zone(const char *s, regmatch_t *match,
+ unsigned int parse_tag, void *data)
+{
+ struct parser_data *parser_data = (struct parser_data *)data;
+ unsigned int zone_id;
+ struct zone_info *zone;
+
+ if (parse_tag != PARSE_TAG_ZONE)
+ return -EINVAL;
+
+ zone_id = get_zone_id(s + match[1].rm_so,
+ match[1].rm_eo - match[1].rm_so);
+ zone = parser_data->mem_info->zones;
+
+ if (!zone_id)
+ return -EINVAL;
+
+ while (zone->id && zone->id != zone_id)
+ ++zone;
+
+ if (!zone->id) {
+ ++parser_data->mem_info->zone_count;
+ zone->id = zone_id;
+ }
+
+ parser_data->zone = zone;
+ return 0;
+}
+
+static int compact_parse_zoneinfo(const char *s, regmatch_t *match,
+ unsigned int parse_tag,
+ void *data)
+{
+ struct parser_data *parser_data = (struct parser_data *)data;
+ char *e;
+ unsigned long v;
+
+ v = strtoul(s + match[1].rm_so, &e, 0);
+ if (!(s != e))
+ return -EINVAL;
+
+ switch (parse_tag) {
+ case PARSE_TAG_WM_MIN:
+ compact_zoneinfo_set(parser_data->zone,
+ offsetof(struct zone_info, wm_min), v);
+ break;
+ case PARSE_TAG_WM_LOW:
+ compact_zoneinfo_set(parser_data->zone,
+ offsetof(struct zone_info, wm_low), v);
+
+ break;
+ case PARSE_TAG_WM_HIGH:
+ compact_zoneinfo_set(parser_data->zone,
+ offsetof(struct zone_info, wm_high), v);
+ break;
+ case PARSE_TAG_MANAGED:
+ compact_zoneinfo_set(parser_data->zone,
+ offsetof(struct zone_info, managed), v);
+ break;
+ }
+ return 0;
+}
+
+static int compact_parse_pages(const char *s, regmatch_t *match,
+ unsigned int parse_tag, void *data)
+{
+ struct parser_data *parser_data = (struct parser_data *)data;
+ char *e;
+ unsigned long v, page_count = 0;
+ int order;
+
+ if (parse_tag != PARSE_TAG_PAGE_COUNT)
+ return -EINVAL;
+
+ for (order = 0; order < MAX_PAGE_ORDER; ++order) {
+
+ v = strtoul(s, &e, 0);
+ if (!(s != e))
+ return -EINVAL;
+ parser_data->zone->pages_per_order[order] = v;
+ page_count += v << order;
+ s = e;
+ }
+
+ if (parser_data->zone->free_pages != page_count) {
+ /*
+ * The drop of number of available pages is being handled
+ * on a per-order basis, thought this might be a good point
+ * to validate the zone's watermarks
+ */
+ parser_data->zone->free_pages = page_count;
+ }
+ return 0;
+}
+
+static int compact_get_buddyinfo(struct compact_control *compact)
+{
+ const struct parse_arg args[] = {
+ PARSE_TAG("zone[[:blank:]]+(Normal|DMA|DMA32|HighMem)",
+ compact_parse_zone, ZONE),
+ PARSE_TAG("([[:blank:]]+([0-9]+))+",
+ compact_parse_pages, PAGE_COUNT),
+ PARSE_TAG_EMPTY(),
+ };
+
+ struct parser_data parser_data = {
+ .mem_info = compact->mem_info,
+ .zone = &compact->mem_info->zones[0],
+ };
+
+ return proc_parse_buddyinfo(args, &parser_data);
+}
+
+static int compact_get_zoneinfo(struct compact_control *compact)
+{
+ const struct parse_arg args[] = {
+ PARSE_TAG("zone[[:blank:]]+(Normal|DMA|DMA32|HighMem)",
+ compact_parse_zone, ZONE),
+ PARSE_TAG("min[[:blank:]]+([0-9]+)\n",
+ compact_parse_zoneinfo, WM_MIN),
+ PARSE_TAG("low[[:blank:]]+([0-9]+)\n",
+ compact_parse_zoneinfo, WM_LOW),
+ PARSE_TAG("high[[:blank:]]+([0-9]+)\n",
+ compact_parse_zoneinfo, WM_HIGH),
+ PARSE_TAG("managed[[:blank:]]+([0-9]+)\n",
+ compact_parse_zoneinfo, MANAGED),
+ PARSE_TAG_EMPTY(),
+ };
+
+ struct parser_data parser_data = {
+ .mem_info = compact->mem_info,
+ .zone = &compact->mem_info->zones[0],
+ };
+ return proc_parse_zoneinfo(args, &parser_data);
+}
+
+static void compact_track_frag_level(struct compact_control *compact)
+{
+ int woken = 1;
+
+ do {
+ /* Eliminate updates on spurious wake-ups */
+ if (woken) {
+ compact_get_buddyinfo(compact);
+ compaction_verify(compact);
+ }
+
+ pthread_mutex_lock(&compact_data.notify_lock);
+ pthread_cond_wait(&compact_data.notify,
+ &compact_data.notify_lock);
+ pthread_mutex_unlock(&compact_data.notify_lock);
+
+ pthread_mutex_lock(&compact->lock);
+ woken = compact->status & COMPACT_NOTIFIED ? 1 : 0;
+ compact->status &= ~COMPACT_NOTIFIED;
+ pthread_mutex_unlock(&compact->lock);
+
+ } while (!(compact->status & COMPACT_SKIP));
+
+}
+
+static int compact_mem_state_changed(void *data)
+{
+ struct compact_control *compact;
+ struct memory_info *mem_info;
+ int result = RESOURCED_ERROR_NONE;
+
+ pthread_mutex_lock(&compact_data.drained_lock);
+ compact = compact_data.compact;
+ mem_info = compact ? compact->mem_info : NULL;
+ if (mem_info) {
+ int new_state = *((int *)data);
+
+ if (new_state < MEM_LEVEL_HIGH || new_state >= MEM_LEVEL_MAX) {
+ result = RESOURCED_ERROR_FAIL;
+ goto leave;
+ }
+
+ pthread_mutex_lock(&compact_data.compact->lock);
+ if (!(compact->status & COMPACT_SKIP)) {
+ compact->status |= COMPACT_NOTIFIED;
+ pthread_cond_signal(&compact_data.notify);
+ }
+ pthread_mutex_unlock(&compact_data.compact->lock);
+ }
+leave:
+ pthread_mutex_unlock(&compact_data.drained_lock);
+ return result;
+}
+
+static void compact_cleanup(struct compact_control *compact)
+{
+ struct memory_info *mem_info = compact->mem_info;
+
+ if (!(compact->status & COMPACT_SKIP))
+ _E("Invalid compact thread state [%d]\n", compact->status);
+
+ unregister_notifier(RESOURCED_NOTIFIER_MEM_LEVEL_CHANGED,
+ compact_mem_state_changed);
+
+ (void) pthread_mutex_destroy(&compact->lock);
+
+ free(mem_info);
+ free(compact);
+}
+
+static void *compact_tracer(void *arg)
+{
+ struct compact_data *cdata = (struct compact_data *)arg;
+ struct compact_control *compact = cdata->compact;
+
+ if (compact_get_zoneinfo(compact) == RESOURCED_ERROR_NONE)
+ compact_track_frag_level(compact);
+
+ /* Dropped - so clean-up */
+ pthread_mutex_lock(&compact->lock);
+ compact->status |= COMPACT_WITHDRAW;
+ pthread_mutex_unlock(&compact->lock);
+
+ pthread_mutex_lock(&cdata->drained_lock);
+ compact_cleanup(compact);
+ cdata->compact = NULL;
+ pthread_mutex_unlock(&cdata->drained_lock);
+
+ pthread_cond_signal(&cdata->drained);
+
+ pthread_exit(NULL);
+}
+
+static int compact_parse_config_file(struct compact_control *compact)
+{
+ struct compact_conf *compact_conf = get_compact_conf();
+ if (!compact_conf) {
+ _E("Compact configuration should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (!compact_conf->enable) {
+ (void) pthread_mutex_lock(&compact->lock);
+ compact->status |= COMPACT_SKIP;
+ (void) pthread_mutex_unlock(&compact->lock);
+
+ goto free_compact_conf;
+ }
+
+ if (compact_conf->frag_level > 0)
+ compact->frag_level = compact_conf->frag_level;
+
+ _I("[COMPACTION] compact status: %d", compact->status);
+ _I("[COMPACTION] compact frag_level: %d", compact->frag_level);
+
+free_compact_conf:
+ free_compact_conf();
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int compact_init(void *data)
+{
+ struct memory_info *mem_info;
+ struct compact_control *compact;
+ int result = RESOURCED_ERROR_OUT_OF_MEMORY;
+
+ _I("[COMPACTION] compact init");
+
+ pthread_mutex_lock(&compact_data.drained_lock);
+ if (compact_data.compact) {
+ _E("[COMPACTION] Unbalanced calls to compact module load/unload\n");
+ result = RESOURCED_ERROR_NONE;
+ goto leave;
+ }
+
+ compact = calloc(1, sizeof(*compact));
+ if (!compact)
+ goto leave;
+
+ mem_info = calloc(1, sizeof(*mem_info));
+ if (!mem_info)
+ goto cleanup;
+
+ compact->mem_info = mem_info;
+ compact->frag_level = COMPACT_DEF_FRAG_LEVEL;
+
+ result = pthread_mutex_init(&compact->lock, NULL);
+ if (result) {
+ _E("[COMPACTION] Failed to init compact lock: %m");
+ goto cleanup_all;
+ }
+
+ /* Load configuration */
+ compact_parse_config_file(compact);
+
+ if (compact->status & COMPACT_SKIP) {
+ _I("[COMPACTION] Compaction module disabled.");
+ result = RESOURCED_ERROR_FAIL;
+ goto cleanup_all;
+ }
+
+ compact_data.compact = compact;
+
+ result = pthread_create(&compact->compact_thread, NULL,
+ compact_tracer, (void*)&compact_data);
+ if (result) {
+ compact_data.compact = NULL;
+ goto cleanup_all;
+ }
+
+ pthread_detach(compact->compact_thread);
+ pthread_mutex_unlock(&compact_data.drained_lock);
+
+ register_notifier(RESOURCED_NOTIFIER_MEM_LEVEL_CHANGED,
+ compact_mem_state_changed);
+ return RESOURCED_ERROR_NONE;
+
+cleanup_all:
+ free(mem_info);
+cleanup:
+ free(compact);
+leave:
+ pthread_mutex_unlock(&compact_data.drained_lock);
+ return result;
+}
+
+static int compact_exit(void *data)
+{
+ struct compact_control *compact;
+
+ pthread_mutex_lock(&compact_data.drained_lock);
+ compact = compact_data.compact;
+ compact_data.compact = NULL;
+
+ if (!compact)
+ goto leave;
+
+ pthread_mutex_lock(&compact->lock);
+ compact->status |= COMPACT_CANCEL;
+ pthread_mutex_unlock(&compact->lock);
+
+ pthread_cond_signal(&compact_data.notify);
+ pthread_cond_wait(&compact_data.drained, &compact_data.drained_lock);
+leave:
+ pthread_mutex_unlock(&compact_data.drained_lock);
+ return 0;
+}
+
+static int compact_runtime_support(void *data)
+{
+ _cleanup_close_ int fd = -1;
+
+ fd = open(PROC_COMPACT_ENTRY, O_WRONLY);
+ if (fd < 0) {
+ _E("Unable to open compaction procfs entry\n");
+ return RESOURCED_ERROR_NO_DATA;
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
+static struct module_ops compact_module_ops = {
+ .priority = MODULE_PRIORITY_LATE,
+ .name = "compact",
+ .init = compact_init,
+ .exit = compact_exit,
+ .check_runtime_support = compact_runtime_support,
+};
+
+MODULE_REGISTER(&compact_module_ops)
+
+++ /dev/null
-/*
- * resourced:compaction
- *
- * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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 <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <glib.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <sys/syscall.h>
-
-#include "config-parser.h"
-#include "module.h"
-#include "macro.h"
-#include "memory-cgroup.h"
-#include "notifier.h"
-#include "procfs.h"
-#include "resourced.h"
-#include "trace.h"
-#include "util.h"
-#include "compact-common.h"
-
-/**
- * State bit for zone's fragmentation warning
- * ZONE_FRAG_WARN_RAISE bit is set for each zone
- * when the fragmentation level reaches specified
- * value for at least one of supported page orders.
- */
-#define ZONE_FRAG_WARN_RAISE (0x1 << 0)
-
-/* Internal compaction module states */
-#define COMPACT_IDLE (0)
-/* State NOTIFIED is to eliminate spurious thread wakeups */
-#define COMPACT_NOTIFIED (1 << 0)
-/* Failed to write to procfs entry */
-#define COMPACT_FAILURE (1 << 1)
-/**
- * Failed to perform one of the basic operations:
- * like reading /proc/zoneinfo or /proc/pagetypeinfo
- * Set to indicate that there is no point of return
- * and that the compaction thread should/can safely
- * clean things up and call it a day.
- **/
-#define COMPACT_WITHDRAW (1 << 2)
-/**
- * Set when compaction module has been explicitly
- * requested to quit
- */
-#define COMPACT_CANCEL (1 << 3)
-#define COMPACT_SKIP (COMPACT_WITHDRAW | COMPACT_CANCEL)
-
-#define MAX_PAGE_ORDER 0xa
-#define ZONE_MAX_NR 4
-
-#define PROC_COMPACT_ENTRY "/proc/sys/vm/compact_memory"
-#define COMPACT_CONF_FILE RD_CONFIG_FILE(optimizer)
-
-#define COMPACT_CONFIG_SECTION "Compaction"
-#define COMPACT_CONFIG_ENABLE "CompactEnable"
-#define COMPACT_CONFIG_FRAG "Fraglevel"
-
-/**
- * Default frag level (percentage, order-based) which determines
- * when to trigger compaction.
- */
-#define COMPACT_DEF_FRAG_LEVEL 800 /* 80% */
-
-/*
- * Note: Tightly coupled with corresponding ids.
- * Mind while modifying.
- */
-static const char *zone_names[] = {"Normal", "DMA", "HighMem", "DMA32"};
-
-struct parser_data {
- struct memory_info *mem_info;
- struct zone_info *zone;
-};
-
-struct zone_info {
- unsigned int id;
- unsigned long pages_per_order[MAX_PAGE_ORDER +1];
- unsigned long free_pages;
- unsigned long wm_min;
- unsigned long wm_low;
- unsigned long wm_high;
- unsigned long managed;
- unsigned int frag_map:MAX_PAGE_ORDER+1;
- unsigned int frag_warn:2;
-};
-
-struct memory_info {
- unsigned int zone_count;
- struct zone_info zones[ZONE_MAX_NR];
-};
-
-struct compact_control {
- struct memory_info *mem_info;
- pthread_t compact_thread;
- pthread_mutex_t lock;
- int frag_level;
- unsigned int status;
- unsigned int compact_type;
-};
-
-#define PARSE_TAG(exp, fn, id) \
- { \
- .re_exp = exp, \
- .callback = fn, \
- .tag = PARSE_TAG_##id, \
- }
-
-#define PARSE_TAG_EMPTY() {0,}
-
-/*
- * @TODO: This should be attached to module ops
- */
-struct compact_data {
- struct compact_control *compact;
- pthread_mutex_t notify_lock;
- pthread_cond_t notify;
- pthread_mutex_t drained_lock;
- pthread_cond_t drained;
-};
-
-static struct compact_data compact_data = {
- .notify_lock = PTHREAD_MUTEX_INITIALIZER,
- .notify = PTHREAD_COND_INITIALIZER,
- .drained_lock = PTHREAD_MUTEX_INITIALIZER,
- .drained = PTHREAD_COND_INITIALIZER
-};
-
-static inline unsigned int get_zone_id(const char *zone_name, size_t len)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(zone_names); ++i) {
- if (!strncmp(zone_name, zone_names[i], len))
- return 1 << i;
- }
- return 0;
-}
-
-static inline const char *get_zone_name(unsigned int zone_id)
-{
- unsigned int i = ffs(zone_id) - 1;
-
- return (i < ARRAY_SIZE(zone_names)) ? zone_names[i] : NULL;
-}
-
-/*
- * External fragmentation is an issue but one that mostly kernel
- * should be concerned about, not the user space.
- * Still though, fragmented *physical* memory may (but does not
- * have to) lead to system getting less responsive - as the kernel
- * might get trapped waiting for allocation of high-order
- * physically-contiguous pages. The fragmentation issue gets more
- * significant in case of huge pages - thought this is left aside
- * due to not being relevant, in this particular case.
- *
- * Triggering the compaction from the user-space is a rather
- * nasty hack. But if this is to be done, than...
- * 1. There is not much point in triggering compaction if
- * the system is already at a heavy memory pressure
- * and it is struggling to satisfy 0-order allocations
- * 2. Specifying the overall fragmentation level is quite tricky
- * and without some decent background of what is/has been going
- * on as far as memory allocations are being concern (both from
- * user-space and from the kernel) is not really reliable, to say
- * at least. All in all, what's the acceptable (whatever it means)
- * level for external fragmentation? Having most of the available
- * memory within the low-order page blocks should raise an alert,
- * but that's only in theory. Things get more complicated when taking
- * into consideration the migration types of available pages.
- * This might go wrong in so many ways .....
- * Shall this be continued ?
- */
-static void compaction_start(struct compact_control *compact)
-{
- struct memory_info *mem_info;
- int current_status = COMPACT_IDLE;
- _cleanup_close_ int fd = -1;
- int n = 1;
-
- pthread_mutex_lock(&compact->lock);
-
- if (compact->status & COMPACT_SKIP)
- current_status |= COMPACT_WITHDRAW;
-
- pthread_mutex_unlock(&compact->lock);
-
- if (current_status & COMPACT_WITHDRAW)
- return;
-
- mem_info = compact->mem_info;
-
-
- fd = open(PROC_COMPACT_ENTRY, O_WRONLY);
- if (fd < 0) {
- if (errno == EACCES || errno == EFAULT || errno == ENOENT)
- current_status |= COMPACT_WITHDRAW;
- _E("Compaction: failed to open procfs entry [%d]\n", errno);
- goto leave;
- }
- /*
- * It doesn't really matter what gets written,
- * as long as smth gets....
- */
- if (write(fd, &n, sizeof(n)) <= 0)
- current_status |= COMPACT_FAILURE;
- /*
- * Reset the external fragmentation warnings.
- * Locking is not required here as all updates will get suspended
- * until the compaction status won't indicate all is done here
- */
- if (current_status & COMPACT_FAILURE)
- goto leave;
-
- for (n = 0; n < mem_info->zone_count; ++n)
- mem_info->zones[n].frag_warn &= ~ZONE_FRAG_WARN_RAISE;
-leave:
-
- pthread_mutex_lock(&compact->lock);
- compact->status |= current_status;
- pthread_mutex_unlock(&compact->lock);
-}
-
-static void compact_validate_zone(struct zone_info *zone,
- unsigned int frag_level,
- struct memory_info *mem_info)
-{
- int order, req_order;
- unsigned int current_frag_map = 0;
- /*
- * Skip compaction if the system is below the low watermark.
- * It's gonna be done either way
- */
- if (zone->free_pages < zone->wm_low) {
- _I("Skipping validation due to falling below the low watermark\n");
- _I("Zone %s: number of free pages: %lu low watermark: %lu\n",
- get_zone_name(zone->id),
- zone->free_pages, zone->wm_low);
- return;
- }
-
- for (req_order = 1; req_order <= MAX_PAGE_ORDER; ++req_order) {
- unsigned long available_pages = 0;
-
- for (order = req_order; order <= MAX_PAGE_ORDER; ++order)
- available_pages += zone->pages_per_order[order] << order;
-
- if (zone->free_pages > 0 && (1000 - (available_pages * 1000 / zone->free_pages)) >= frag_level)
- current_frag_map |= 1 << req_order;
- }
-
- if (current_frag_map) {
-
- if ((!zone->frag_map && current_frag_map) ||
- ((zone->frag_map ^ current_frag_map) &&
- !((zone->frag_map ^ current_frag_map) & zone->frag_map)))
-
- zone->frag_warn |= ZONE_FRAG_WARN_RAISE;
- }
-
- zone->frag_map = current_frag_map;
-}
-
-static void compaction_verify_zone(struct compact_control *compact,
- struct zone_info *zone)
-{
- struct memory_info *mem_info = compact->mem_info;
-
- /*
- * Here comes the shady part:
- * without some decent memory tracing here it is
- * truly difficult to determine whether the compaction
- * is required or not.
- */
- compact_validate_zone(zone, compact->frag_level, mem_info);
-}
-
-static void compaction_verify(struct compact_control *compact)
-{
- /* Get the overall idea of current external fragmentation */
- struct memory_info *mem_info = compact->mem_info;
- unsigned int compact_targets = 0;
- int n;
-
- /*
- * Verify each zone although the compaction can be
- * triggered per node (or globally) only.
- */
- for (n = 0; n < mem_info->zone_count; ++n) {
- struct zone_info *zone = &mem_info->zones[n];
-
- /*
- * Some devices make a zone but don't allocate any pages for it.
- * We can ignore these empty zones.
- */
- if (zone->managed <= 0)
- continue;
-
- compaction_verify_zone(compact, zone);
- if (zone->frag_warn & ZONE_FRAG_WARN_RAISE) {
- /*
- * As the compaction can be triggered either globally
- * or on per-node it's enough to have at least one
- * zone for which the external fragmentation got
- * dangerously high. Still to have a minimum control
- * over the whole process - validate all zones.
- */
- ++compact_targets;
- }
- }
-
- if (compact_targets)
- compaction_start(compact);
-}
-
-
-#define compact_zoneinfo_set(zone, _off, v) \
- (*(typeof(v)*)(((char*)(zone)) + _off) = v)
-
-
-static int compact_parse_zone(const char *s, regmatch_t *match,
- unsigned int parse_tag, void *data)
-{
- struct parser_data *parser_data = (struct parser_data *)data;
- unsigned int zone_id;
- struct zone_info *zone;
-
- if (parse_tag != PARSE_TAG_ZONE)
- return -EINVAL;
-
- zone_id = get_zone_id(s + match[1].rm_so,
- match[1].rm_eo - match[1].rm_so);
- zone = parser_data->mem_info->zones;
-
- if (!zone_id)
- return -EINVAL;
-
- while (zone->id && zone->id != zone_id)
- ++zone;
-
- if (!zone->id) {
- ++parser_data->mem_info->zone_count;
- zone->id = zone_id;
- }
-
- parser_data->zone = zone;
- return 0;
-}
-
-static int compact_parse_zoneinfo(const char *s, regmatch_t *match,
- unsigned int parse_tag,
- void *data)
-{
- struct parser_data *parser_data = (struct parser_data *)data;
- char *e;
- unsigned long v;
-
- v = strtoul(s + match[1].rm_so, &e, 0);
- if (!(s != e))
- return -EINVAL;
-
- switch (parse_tag) {
- case PARSE_TAG_WM_MIN:
- compact_zoneinfo_set(parser_data->zone,
- offsetof(struct zone_info, wm_min), v);
- break;
- case PARSE_TAG_WM_LOW:
- compact_zoneinfo_set(parser_data->zone,
- offsetof(struct zone_info, wm_low), v);
-
- break;
- case PARSE_TAG_WM_HIGH:
- compact_zoneinfo_set(parser_data->zone,
- offsetof(struct zone_info, wm_high), v);
- break;
- case PARSE_TAG_MANAGED:
- compact_zoneinfo_set(parser_data->zone,
- offsetof(struct zone_info, managed), v);
- break;
- }
- return 0;
-}
-
-static int compact_parse_pages(const char *s, regmatch_t *match,
- unsigned int parse_tag, void *data)
-{
- struct parser_data *parser_data = (struct parser_data *)data;
- char *e;
- unsigned long v, page_count = 0;
- int order;
-
- if (parse_tag != PARSE_TAG_PAGE_COUNT)
- return -EINVAL;
-
- for (order = 0; order < MAX_PAGE_ORDER; ++order) {
-
- v = strtoul(s, &e, 0);
- if (!(s != e))
- return -EINVAL;
- parser_data->zone->pages_per_order[order] = v;
- page_count += v << order;
- s = e;
- }
-
- if (parser_data->zone->free_pages != page_count) {
- /*
- * The drop of number of available pages is being handled
- * on a per-order basis, thought this might be a good point
- * to validate the zone's watermarks
- */
- parser_data->zone->free_pages = page_count;
- }
- return 0;
-}
-
-static int compact_get_buddyinfo(struct compact_control *compact)
-{
- const struct parse_arg args[] = {
- PARSE_TAG("zone[[:blank:]]+(Normal|DMA|DMA32|HighMem)",
- compact_parse_zone, ZONE),
- PARSE_TAG("([[:blank:]]+([0-9]+))+",
- compact_parse_pages, PAGE_COUNT),
- PARSE_TAG_EMPTY(),
- };
-
- struct parser_data parser_data = {
- .mem_info = compact->mem_info,
- .zone = &compact->mem_info->zones[0],
- };
-
- return proc_parse_buddyinfo(args, &parser_data);
-}
-
-static int compact_get_zoneinfo(struct compact_control *compact)
-{
- const struct parse_arg args[] = {
- PARSE_TAG("zone[[:blank:]]+(Normal|DMA|DMA32|HighMem)",
- compact_parse_zone, ZONE),
- PARSE_TAG("min[[:blank:]]+([0-9]+)\n",
- compact_parse_zoneinfo, WM_MIN),
- PARSE_TAG("low[[:blank:]]+([0-9]+)\n",
- compact_parse_zoneinfo, WM_LOW),
- PARSE_TAG("high[[:blank:]]+([0-9]+)\n",
- compact_parse_zoneinfo, WM_HIGH),
- PARSE_TAG("managed[[:blank:]]+([0-9]+)\n",
- compact_parse_zoneinfo, MANAGED),
- PARSE_TAG_EMPTY(),
- };
-
- struct parser_data parser_data = {
- .mem_info = compact->mem_info,
- .zone = &compact->mem_info->zones[0],
- };
- return proc_parse_zoneinfo(args, &parser_data);
-}
-
-static void compact_track_frag_level(struct compact_control *compact)
-{
- int woken = 1;
-
- do {
- /* Eliminate updates on spurious wake-ups */
- if (woken) {
- compact_get_buddyinfo(compact);
- compaction_verify(compact);
- }
-
- pthread_mutex_lock(&compact_data.notify_lock);
- pthread_cond_wait(&compact_data.notify,
- &compact_data.notify_lock);
- pthread_mutex_unlock(&compact_data.notify_lock);
-
- pthread_mutex_lock(&compact->lock);
- woken = compact->status & COMPACT_NOTIFIED ? 1 : 0;
- compact->status &= ~COMPACT_NOTIFIED;
- pthread_mutex_unlock(&compact->lock);
-
- } while (!(compact->status & COMPACT_SKIP));
-
-}
-
-static int compact_mem_state_changed(void *data)
-{
- struct compact_control *compact;
- struct memory_info *mem_info;
- int result = RESOURCED_ERROR_NONE;
-
- pthread_mutex_lock(&compact_data.drained_lock);
- compact = compact_data.compact;
- mem_info = compact ? compact->mem_info : NULL;
- if (mem_info) {
- int new_state = *((int *)data);
-
- if (new_state < MEM_LEVEL_HIGH || new_state >= MEM_LEVEL_MAX) {
- result = RESOURCED_ERROR_FAIL;
- goto leave;
- }
-
- pthread_mutex_lock(&compact_data.compact->lock);
- if (!(compact->status & COMPACT_SKIP)) {
- compact->status |= COMPACT_NOTIFIED;
- pthread_cond_signal(&compact_data.notify);
- }
- pthread_mutex_unlock(&compact_data.compact->lock);
- }
-leave:
- pthread_mutex_unlock(&compact_data.drained_lock);
- return result;
-}
-
-static void compact_cleanup(struct compact_control *compact)
-{
- struct memory_info *mem_info = compact->mem_info;
-
- if (!(compact->status & COMPACT_SKIP))
- _E("Invalid compact thread state [%d]\n", compact->status);
-
- unregister_notifier(RESOURCED_NOTIFIER_MEM_LEVEL_CHANGED,
- compact_mem_state_changed);
-
- (void) pthread_mutex_destroy(&compact->lock);
-
- free(mem_info);
- free(compact);
-}
-
-static void *compact_tracer(void *arg)
-{
- struct compact_data *cdata = (struct compact_data *)arg;
- struct compact_control *compact = cdata->compact;
-
- if (compact_get_zoneinfo(compact) == RESOURCED_ERROR_NONE)
- compact_track_frag_level(compact);
-
- /* Dropped - so clean-up */
- pthread_mutex_lock(&compact->lock);
- compact->status |= COMPACT_WITHDRAW;
- pthread_mutex_unlock(&compact->lock);
-
- pthread_mutex_lock(&cdata->drained_lock);
- compact_cleanup(compact);
- cdata->compact = NULL;
- pthread_mutex_unlock(&cdata->drained_lock);
-
- pthread_cond_signal(&cdata->drained);
-
- pthread_exit(NULL);
-}
-
-static int compact_parse_config_file(struct compact_control *compact)
-{
- struct compact_conf *compact_conf = get_compact_conf();
- if (!compact_conf) {
- _E("Compact configuration should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- if (!compact_conf->enable) {
- (void) pthread_mutex_lock(&compact->lock);
- compact->status |= COMPACT_SKIP;
- (void) pthread_mutex_unlock(&compact->lock);
-
- goto free_compact_conf;
- }
-
- if (compact_conf->frag_level > 0)
- compact->frag_level = compact_conf->frag_level;
-
- _I("[COMPACTION] compact status: %d", compact->status);
- _I("[COMPACTION] compact frag_level: %d", compact->frag_level);
-
-free_compact_conf:
- free_compact_conf();
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int compact_init(void *data)
-{
- struct memory_info *mem_info;
- struct compact_control *compact;
- int result = RESOURCED_ERROR_OUT_OF_MEMORY;
-
- _I("[COMPACTION] compact init");
-
- pthread_mutex_lock(&compact_data.drained_lock);
- if (compact_data.compact) {
- _E("[COMPACTION] Unbalanced calls to compact module load/unload\n");
- result = RESOURCED_ERROR_NONE;
- goto leave;
- }
-
- compact = calloc(1, sizeof(*compact));
- if (!compact)
- goto leave;
-
- mem_info = calloc(1, sizeof(*mem_info));
- if (!mem_info)
- goto cleanup;
-
- compact->mem_info = mem_info;
- compact->frag_level = COMPACT_DEF_FRAG_LEVEL;
-
- result = pthread_mutex_init(&compact->lock, NULL);
- if (result) {
- _E("[COMPACTION] Failed to init compact lock: %m");
- goto cleanup_all;
- }
-
- /* Load configuration */
- compact_parse_config_file(compact);
-
- if (compact->status & COMPACT_SKIP) {
- _I("[COMPACTION] Compaction module disabled.");
- result = RESOURCED_ERROR_FAIL;
- goto cleanup_all;
- }
-
- compact_data.compact = compact;
-
- result = pthread_create(&compact->compact_thread, NULL,
- compact_tracer, (void*)&compact_data);
- if (result) {
- compact_data.compact = NULL;
- goto cleanup_all;
- }
-
- pthread_detach(compact->compact_thread);
- pthread_mutex_unlock(&compact_data.drained_lock);
-
- register_notifier(RESOURCED_NOTIFIER_MEM_LEVEL_CHANGED,
- compact_mem_state_changed);
- return RESOURCED_ERROR_NONE;
-
-cleanup_all:
- free(mem_info);
-cleanup:
- free(compact);
-leave:
- pthread_mutex_unlock(&compact_data.drained_lock);
- return result;
-}
-
-static int compact_exit(void *data)
-{
- struct compact_control *compact;
-
- pthread_mutex_lock(&compact_data.drained_lock);
- compact = compact_data.compact;
- compact_data.compact = NULL;
-
- if (!compact)
- goto leave;
-
- pthread_mutex_lock(&compact->lock);
- compact->status |= COMPACT_CANCEL;
- pthread_mutex_unlock(&compact->lock);
-
- pthread_cond_signal(&compact_data.notify);
- pthread_cond_wait(&compact_data.drained, &compact_data.drained_lock);
-leave:
- pthread_mutex_unlock(&compact_data.drained_lock);
- return 0;
-}
-
-static int compact_runtime_support(void *data)
-{
- _cleanup_close_ int fd = -1;
-
- fd = open(PROC_COMPACT_ENTRY, O_WRONLY);
- if (fd < 0) {
- _E("Unable to open compaction procfs entry\n");
- return RESOURCED_ERROR_NO_DATA;
- }
- return RESOURCED_ERROR_NONE;
-}
-
-static struct module_ops compact_module_ops = {
- .priority = MODULE_PRIORITY_LATE,
- .name = "compact",
- .init = compact_init,
- .exit = compact_exit,
- .check_runtime_support = compact_runtime_support,
-};
-
-MODULE_REGISTER(&compact_module_ops)
-
--- /dev/null
+/*
+ * resourced
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+*/
+
+/*
+ * @file dedup.c
+ * @desc dedup process
+ */
+#include <trace.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include <sys/sysinfo.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <memory-cgroup.h>
+#include <linux/loop.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+
+#include "macro.h"
+#include "util.h"
+#include "module.h"
+#include "module-data.h"
+#include "dedup-common.h"
+#include "config-parser.h"
+#include "lowmem-handler.h"
+#include "notifier.h"
+#include "const.h"
+#include "file-helper.h"
+
+#define DEDUP_PRIORITY 20
+#define DEDUP_ON_BOOT_TIME 60
+#define DEDUP_FULL_SCAN_INTERVAL 60
+#define DEDUP_INIT_SCAN_INTERVAL 300
+#define DEDUP_STAT_INTERVAL 60
+
+enum dedup_thread_op {
+ DEDUP_OP_ACTIVATE,
+ DEDUP_OP_SCANONCE,
+ DEDUP_OP_STAT,
+ DEDUP_OP_DEACTIVATE,
+ DEDUP_OP_MAX,
+};
+
+struct dedup_thread_bundle {
+ enum dedup_thread_op op;
+ enum ksm_scan_mode mode;
+};
+
+static struct module_ops dedup_module_ops;
+
+//static enum dedup_state dedup_state; /* see src/common/dedup-common.h */
+static bool dedup_activated = false;
+
+static bool dedup_enable = false;
+static bool dedup_at_boot_enable = false;
+static enum dedup_mode dedup_mode = DEDUP_MODE_PERIODIC;
+static bool dedup_on_lowmem = false;
+
+static int dedup_at_boot_delay_sec = 60;
+static int dedup_full_scan_interval_sec = 600;
+static int dedup_stat_interval_sec = 60;
+static int dedup_partial_scan_interval_sec = 10;
+
+static GSource *dedup_activating_timer = NULL;
+static GSource *dedup_scanning_timer = NULL;
+static GSource *dedup_stat_timer = NULL;
+
+static int dedup_do_scan(enum ksm_scan_mode);
+static int dedup_do_stat(void);
+
+/* dedup module parameters */
+enum dedup_param {
+ DEDUP_PARAM_ENABLE = 0,
+ DEDUP_PARAM_AT_BOOT,
+ DEDUP_PARAM_AT_BOOT_DELAY,
+ DEDUP_PARAM_ON_LOWMEM,
+ DEDUP_PARAM_STAT_INTERVAL,
+ DEDUP_PARAM_FULL_SCAN_INTERVAL,
+ DEDUP_PARAM_PARTIAL_SCAN_INTERVAL,
+ DEDUP_PARAM_MAX,
+};
+
+/* ksm param types & value ranges & pathes */
+enum ksm_param {
+ KSM_PARAM_PAGES_TO_SCAN = 0,
+ KSM_PARAM_SLEEP_MSECS,
+ KSM_PARAM_FULL_SCAN_INTERVAL_MSECS,
+ KSM_PARAM_SCAN_BOOST,
+ KSM_PARAM_MAX,
+};
+
+static int ksm_param_ranges[KSM_PARAM_MAX][2] = {
+ {0, 10000}, /* KSM_PARAM_PAGES_TO_SCAN */
+ {0, 1000}, /* KSM_PARAM_SLEEP_MSECS */
+ {0, INT_MAX}, /* KSM_PARAM_FULL_SCAN_INTERVAL_MSECS */
+ {100, 10000}, /* KSM_PARAM_SCAN_BOOST */
+};
+static unsigned int ksm_params[KSM_PARAM_MAX];
+static const char *ksm_param_path[KSM_PARAM_MAX] = {
+ "/sys/kernel/mm/ksm/pages_to_scan",
+ "/sys/kernel/mm/ksm/sleep_millisecs",
+ "/sys/kernel/mm/ksm/full_scan_interval",
+ "/sys/kernel/mm/ksm/scan_boost",
+};
+
+/* ksm statistics */
+#define KSM_STAT_WINDOW_MAX 10
+static int ksm_stat_window;
+static unsigned int ksm_stats[KSM_STAT_MAX][KSM_STAT_WINDOW_MAX];
+static const char *ksm_stat_path[2] = {
+ "/sys/kernel/mm/ksm/pages_sharing",
+ "/sys/kernel/mm/ksm/pages_shared",
+};
+
+enum ksm_sysfs_state_val {
+ DEDUP_SYSFS_STOP = 0,
+ DEDUP_SYSFS_RUN = 1,
+ DEDUP_SYSFS_ONE_SHOT = 8,
+};
+
+static inline int dedup_set_ksm_state(enum dedup_state state)
+{
+ int val;
+
+ if (state == DEDUP_ON)
+ val = DEDUP_SYSFS_RUN;
+ else if (state == DEDUP_ONE_SHOT)
+ val = DEDUP_SYSFS_ONE_SHOT;
+ else
+ val = DEDUP_SYSFS_STOP;
+ /* write value to /sys/kernel/mm/ksm/run */
+ return fwrite_int(DEDUP_SYSFS_KSM_RUN, val);
+}
+
+static inline int dedup_set_ksm_param(int param_num, unsigned int value)
+{
+ return fwrite_uint(ksm_param_path[param_num], value);
+}
+
+static void dedup_set_ksm_params(void)
+{
+ int i;
+ for (i = KSM_PARAM_PAGES_TO_SCAN; i < KSM_PARAM_MAX; i++)
+ dedup_set_ksm_param(i, ksm_params[i]);
+}
+
+static int dedup_check_and_scanning_once(enum ksm_scan_mode mode)
+{
+ int val;
+ fread_int(DEDUP_SYSFS_KSM_ONESHOT, &val);
+ if (val == KSM_SCAN_NONE)
+ return fwrite_int(DEDUP_SYSFS_KSM_ONESHOT, mode);
+ return 0;
+}
+
+static int dedup_scanning_once(enum ksm_scan_mode mode)
+{
+ int ret;
+ _D("[DEDUP] Invoke scanning once to KSM (mode: %d)", mode);
+ ret = dedup_check_and_scanning_once(mode);
+
+ return ret;
+}
+
+unsigned int dedup_get_ksm_stat(enum ksm_stat stat_type)
+{
+ int last;
+ if (stat_type < KSM_STAT_PAGES_SHARING || stat_type >= KSM_STAT_MAX)
+ return 0;
+ last = (ksm_stat_window == 0) ? KSM_STAT_WINDOW_MAX - 1 : ksm_stat_window - 1;
+ return ksm_stats[stat_type][last];
+}
+
+static int dedup_record_stat(void)
+{
+ int val, ret;
+
+ ret = fread_int(ksm_stat_path[KSM_STAT_PAGES_SHARING], &val);
+ if (!ret)
+ ksm_stats[KSM_STAT_PAGES_SHARING][ksm_stat_window] = val;
+ ret = fread_int(ksm_stat_path[KSM_STAT_PAGES_SHARED], &val);
+ if (!ret)
+ ksm_stats[KSM_STAT_PAGES_SHARED][ksm_stat_window] = val;
+
+ _I("read ksm stat: pages_sharing: %d pages_shared: %d",
+ ksm_stats[KSM_STAT_PAGES_SHARING][ksm_stat_window],
+ ksm_stats[KSM_STAT_PAGES_SHARED][ksm_stat_window]);
+ ksm_stat_window = (ksm_stat_window + 1) % KSM_STAT_WINDOW_MAX;
+ return RESOURCED_ERROR_NONE;
+}
+
+static gboolean dedup_scanning_timer_cb(gpointer data)
+{
+ dedup_scanning_timer = NULL;
+ if (dedup_get_state() == DEDUP_ONE_SHOT)
+ dedup_do_scan(KSM_SCAN_FULL);
+ return false;
+}
+
+static gboolean dedup_stat_timer_cb(gpointer data)
+{
+ dedup_stat_timer = NULL;
+ dedup_do_stat();
+ return false;
+}
+
+static void dedup_reset_scanning_timer(void)
+{
+ _D("reset scan-timer %d seconds", dedup_full_scan_interval_sec);
+ dedup_scanning_timer =
+ g_timeout_source_new_seconds(dedup_full_scan_interval_sec);
+ g_source_set_callback(dedup_scanning_timer,
+ dedup_scanning_timer_cb, NULL, NULL);
+ g_source_attach(dedup_scanning_timer, NULL);
+}
+
+static void dedup_reset_stat_timer(void)
+{
+ _D("reset stat-timer %d seconds", dedup_stat_interval_sec);
+ dedup_stat_timer =
+ g_timeout_source_new_seconds(dedup_stat_interval_sec);
+ g_source_set_callback(dedup_stat_timer,
+ dedup_stat_timer_cb, NULL, NULL);
+ g_source_attach(dedup_stat_timer, NULL);
+}
+
+static void dedup_deactivate_in_module(void)
+{
+ if (dedup_activating_timer) {
+ g_source_destroy(dedup_activating_timer);
+ dedup_activating_timer = NULL;
+ }
+
+ if (dedup_scanning_timer) {
+ g_source_destroy(dedup_scanning_timer);
+ dedup_scanning_timer = NULL;
+ }
+
+ if (dedup_stat_timer) {
+ g_source_destroy(dedup_stat_timer);
+ dedup_stat_timer = NULL;
+ }
+
+ _D("stop KSM thread");
+
+ dedup_set_ksm_state(DEDUP_OFF);
+}
+
+static enum dedup_state parse_dedup_state(enum dedup_mode mode)
+{
+ if (mode == DEDUP_MODE_PERIODIC)
+ return DEDUP_ON;
+ else if (mode == DEDUP_MODE_ONESHOT)
+ return DEDUP_ONE_SHOT;
+ else
+ return DEDUP_OFF;
+}
+
+static void dedup_activate_in_module(void)
+{
+ enum dedup_state state;
+
+ if (dedup_get_state() == DEDUP_ON
+ || dedup_get_state() == DEDUP_ONE_SHOT)
+ return;
+
+ if (dedup_activated)
+ return;
+
+ /* make ksm activate */
+ state = parse_dedup_state(dedup_mode);
+ dedup_set_state(state);
+ dedup_set_ksm_params();
+ dedup_set_ksm_state(state);
+ _I("kernel deduplication thread is enabled");
+
+ if (dedup_activating_timer) {
+ g_source_destroy(dedup_activating_timer);
+ dedup_activating_timer = NULL;
+ }
+
+ if (!dedup_on_lowmem) {
+ dedup_scanning_timer = g_timeout_source_new_seconds(dedup_full_scan_interval_sec);
+ g_source_set_callback(dedup_scanning_timer, dedup_scanning_timer_cb, NULL, NULL);
+ g_source_attach(dedup_scanning_timer, NULL);
+ }
+
+ dedup_stat_timer = g_timeout_source_new_seconds(dedup_stat_interval_sec);
+ g_source_set_callback(dedup_stat_timer, dedup_stat_timer_cb, NULL, NULL);
+ g_source_attach(dedup_stat_timer, NULL);
+
+ dedup_activated = true;
+}
+
+#define DEDUP_ACT_MSTOS 1000
+#define DEDUP_ACT_NSTOMS 1000000
+
+static bool dedup_check_scan_interval
+(struct timespec *now, struct timespec *old, unsigned long interval_ms)
+{
+ unsigned long diff_ms;
+ diff_ms = (now->tv_sec - old->tv_sec) * DEDUP_ACT_MSTOS;
+ diff_ms += (now->tv_nsec - old->tv_nsec) / DEDUP_ACT_NSTOMS;
+ return (diff_ms >= (interval_ms * DEDUP_ACT_MSTOS));
+}
+
+/* used in dedup_do_scan */
+static struct timespec now, partial_begin, full_begin;
+static int nr_dedup;
+
+static int dedup_do_scan(enum ksm_scan_mode scan_mode)
+{
+ enum ksm_scan_mode mode = KSM_SCAN_NONE;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ if (scan_mode == KSM_SCAN_FULL) {
+ /* if full scan is requested frequently, it can be
+ * substituted by partial scan
+ */
+ if (dedup_check_scan_interval(&now, &full_begin,
+ dedup_full_scan_interval_sec))
+ mode = KSM_SCAN_FULL;
+ else if (dedup_on_lowmem &&
+ dedup_check_scan_interval(&now, &partial_begin,
+ dedup_partial_scan_interval_sec))
+ mode = KSM_SCAN_PARTIAL;
+ } else if (scan_mode == KSM_SCAN_PARTIAL) {
+ if (dedup_check_scan_interval(&now, &partial_begin,
+ dedup_partial_scan_interval_sec))
+ mode = KSM_SCAN_PARTIAL;
+ }
+
+ if (mode != KSM_SCAN_NONE) {
+ _I("[DEDUP] dedup: %d-th %s deduplication triggering", nr_dedup++,
+ (mode == KSM_SCAN_FULL ? "FULL" : "PARTIAL"));
+ if (!dedup_on_lowmem) {
+ dedup_scanning_once(KSM_SCAN_FULL);
+ dedup_reset_scanning_timer();
+ } else
+ dedup_scanning_once(mode);
+
+ if (mode == KSM_SCAN_FULL)
+ full_begin = now;
+ else
+ partial_begin = now;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int dedup_do_stat(void)
+{
+ dedup_record_stat();
+ dedup_reset_stat_timer();
+ return RESOURCED_ERROR_NONE;
+}
+
+static int dedup_start_handler(void *data)
+{
+ if (!data)
+ return RESOURCED_ERROR_NO_DATA;
+
+ dedup_activate_in_module();
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int dedup_scan_handler(void *data)
+{
+ int *scan_mode;
+
+ if (dedup_get_state() != DEDUP_ONE_SHOT)
+ return 0;
+
+ if (dedup_scanning_timer) {
+ g_source_destroy(dedup_scanning_timer);
+ dedup_scanning_timer = NULL;
+ }
+
+ scan_mode = data;
+ return dedup_do_scan(*scan_mode);
+}
+
+static int dedup_stop_handler(void *data)
+{
+ if (!data)
+ return RESOURCED_ERROR_NO_DATA;
+
+ dedup_deactivate_in_module();
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static gboolean dedup_activate_timer_cb(gpointer data)
+{
+ dedup_activating_timer = NULL;
+ _D("[DEDUP] dedup activating callback called");
+ dedup_activate_in_module();
+ return false;
+}
+
+static int dedup_booting_done(void *data)
+{
+ if (dedup_activated)
+ return RESOURCED_ERROR_NONE;
+
+ if (dedup_at_boot_enable) {
+ /* if dedup_at_boot_enable is disabled,
+ * other daemon should activate dedup */
+ _D("[DEDUP] dedup booting done is called");
+ if (dedup_at_boot_delay_sec > 0)
+ dedup_activating_timer =
+ g_timeout_source_new_seconds(dedup_at_boot_delay_sec);
+ else
+ dedup_activating_timer =
+ g_timeout_source_new_seconds(DEDUP_ON_BOOT_TIME);
+ g_source_set_callback(dedup_activating_timer,
+ dedup_activate_timer_cb, NULL, NULL);
+ g_source_attach(dedup_activating_timer, NULL);
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static int dedup_parse_config_file(void)
+{
+ int arg_ksm_pages_to_scan = 100;
+ int arg_ksm_sleep_ms = 20; // 20 msecs
+ int arg_ksm_full_scan_interval_ms = 60000; // 60 seconds
+ int arg_ksm_scan_boost = 1000;
+
+ struct dedup_conf *dedup_conf = get_dedup_conf();
+ if (!dedup_conf) {
+ _E("Dedup configuration should not be NULL");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ dedup_enable = dedup_conf->enable;
+ if (!dedup_enable)
+ goto free_dedup_conf;
+
+ if (!strncmp(dedup_conf->ksm.mode, "oneshot", 8))
+ dedup_mode = DEDUP_MODE_ONESHOT;
+ else if(!strncmp(dedup_conf->ksm.mode, "periodic", 9))
+ dedup_mode = DEDUP_MODE_PERIODIC;
+ else {
+ dedup_enable = false;
+ goto free_dedup_conf;
+ }
+
+ dedup_at_boot_enable = dedup_conf->boot_dedup_enable;
+ dedup_on_lowmem = dedup_conf->scan_on_lowmem;
+
+ if (dedup_conf->ksm.pages > ksm_param_ranges[KSM_PARAM_PAGES_TO_SCAN][0] &&
+ dedup_conf->ksm.pages <= ksm_param_ranges[KSM_PARAM_PAGES_TO_SCAN][1])
+ ksm_params[KSM_PARAM_PAGES_TO_SCAN] = dedup_conf->ksm.pages;
+ else
+ ksm_params[KSM_PARAM_PAGES_TO_SCAN] = arg_ksm_pages_to_scan;
+
+ if (dedup_conf->ksm.boost_pages > ksm_param_ranges[KSM_PARAM_SCAN_BOOST][0] &&
+ dedup_conf->ksm.boost_pages <= ksm_param_ranges[KSM_PARAM_SCAN_BOOST][1])
+ ksm_params[KSM_PARAM_SCAN_BOOST] = dedup_conf->ksm.boost_pages;
+ else
+ ksm_params[KSM_PARAM_SCAN_BOOST] = arg_ksm_scan_boost;
+
+ ksm_params[KSM_PARAM_SLEEP_MSECS] = arg_ksm_sleep_ms;
+ ksm_params[KSM_PARAM_FULL_SCAN_INTERVAL_MSECS] = arg_ksm_full_scan_interval_ms;
+
+ _I("[DEDUP] deduplication mode: %s", dedup_mode == DEDUP_MODE_PERIODIC ?
+ "kernel-managed" : "resourced-triggered");
+ _I("[DEDUP] deduplication on boot: %s", dedup_at_boot_enable ? "true" : "false");
+ _I("[DEDUP] scanning is invoked by %s", dedup_on_lowmem ?
+ "LOWMEM event" : "periodic timer");
+ _I("[DEDUP] full scan interval: %d sec", dedup_full_scan_interval_sec);
+ _I("[DEDUP] stat monitoring interval: %d sec", dedup_stat_interval_sec);
+
+ _I("[DEDUP] ksm pages to scan: %d", ksm_params[KSM_PARAM_PAGES_TO_SCAN]);
+ _I("[DEDUP] ksm sleep time: %d ms", ksm_params[KSM_PARAM_SLEEP_MSECS]);
+ _I("[DEDUP] ksm full scan interval: %d ms", ksm_params[KSM_PARAM_FULL_SCAN_INTERVAL_MSECS]);
+ _I("[DEDUP] ksm scan boost: %d", ksm_params[KSM_PARAM_SCAN_BOOST]);
+
+free_dedup_conf:
+ free_dedup_conf();
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static inline void init_dedup_stat(void)
+{
+ int i, j;
+ for (i = KSM_STAT_PAGES_SHARING; i < KSM_STAT_MAX; i++)
+ for (j = 0; j < KSM_STAT_WINDOW_MAX; j++)
+ ksm_stats[i][j] = 0;
+ ksm_stat_window = 0;
+}
+
+static int dedup_init(void)
+{
+ int ret;
+
+ init_dedup_stat();
+ ret = dedup_parse_config_file();
+ if (ret < 0)
+ return ret;
+
+ if (!dedup_enable)
+ return -ENODEV;
+
+ /* initialize time variables */
+ if (!clock_gettime(CLOCK_MONOTONIC, &now)) {
+ partial_begin = now;
+ full_begin = now;
+ } else {
+ _I("Time initialization failed");
+ memset(&partial_begin, 0, sizeof(struct timespec));
+ memset(&full_begin, 0, sizeof(struct timespec));
+ }
+
+ return ret;
+}
+
+static int resourced_dedup_check_runtime_support(void *data)
+{
+ /*
+ * Check whether CONFIG_LKSM is enabled in kernel.
+ */
+ if (access("/sys/kernel/mm/ksm/run", R_OK) != 0) {
+ _I("the kernel doesn't support KSM, please check kernel configuration");
+ return -ENOENT;
+ }
+ if (access("/sys/kernel/mm/ksm/one_shot_scanning", R_OK) != 0) {
+ _I("the kernel support KSM but not LKSM, please check kernel configuration");
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int resourced_dedup_init(void *data)
+{
+ int ret;
+
+ dedup_set_state(DEDUP_OFF);
+
+ ret = dedup_init();
+ if (ret != RESOURCED_ERROR_NONE)
+ return ret;
+ _I("resourced dedup module is initialized");
+ register_notifier(RESOURCED_NOTIFIER_DEDUP_START, dedup_start_handler);
+ register_notifier(RESOURCED_NOTIFIER_DEDUP_SCAN, dedup_scan_handler);
+ register_notifier(RESOURCED_NOTIFIER_DEDUP_STOP, dedup_stop_handler);
+ register_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, dedup_booting_done);
+
+ return ret;
+}
+
+static int resourced_dedup_finalize(void *data)
+{
+ unregister_notifier(RESOURCED_NOTIFIER_DEDUP_START, dedup_start_handler);
+ unregister_notifier(RESOURCED_NOTIFIER_DEDUP_SCAN, dedup_scan_handler);
+ unregister_notifier(RESOURCED_NOTIFIER_DEDUP_STOP, dedup_stop_handler);
+ unregister_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, dedup_booting_done);
+
+ dedup_deactivate_in_module();
+
+ _I("dedup module will be finalized");
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static struct module_ops dedup_module_ops = {
+ .priority = MODULE_PRIORITY_NORMAL,
+ .name = "dedup",
+ .init = resourced_dedup_init,
+ .exit = resourced_dedup_finalize,
+ .check_runtime_support = resourced_dedup_check_runtime_support,
+};
+
+MODULE_REGISTER(&dedup_module_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * 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.
- *
-*/
-
-/*
- * @file dedup.c
- * @desc dedup process
- */
-#include <trace.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/vfs.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <pthread.h>
-#include <sys/sysinfo.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <memory-cgroup.h>
-#include <linux/loop.h>
-#include <fcntl.h>
-#include <string.h>
-#include <time.h>
-
-#include "macro.h"
-#include "util.h"
-#include "module.h"
-#include "module-data.h"
-#include "dedup-common.h"
-#include "config-parser.h"
-#include "lowmem-handler.h"
-#include "notifier.h"
-#include "const.h"
-#include "file-helper.h"
-
-#define DEDUP_PRIORITY 20
-#define DEDUP_ON_BOOT_TIME 60
-#define DEDUP_FULL_SCAN_INTERVAL 60
-#define DEDUP_INIT_SCAN_INTERVAL 300
-#define DEDUP_STAT_INTERVAL 60
-
-enum dedup_thread_op {
- DEDUP_OP_ACTIVATE,
- DEDUP_OP_SCANONCE,
- DEDUP_OP_STAT,
- DEDUP_OP_DEACTIVATE,
- DEDUP_OP_MAX,
-};
-
-struct dedup_thread_bundle {
- enum dedup_thread_op op;
- enum ksm_scan_mode mode;
-};
-
-static struct module_ops dedup_module_ops;
-
-//static enum dedup_state dedup_state; /* see src/common/dedup-common.h */
-static bool dedup_activated = false;
-
-static bool dedup_enable = false;
-static bool dedup_at_boot_enable = false;
-static enum dedup_mode dedup_mode = DEDUP_MODE_PERIODIC;
-static bool dedup_on_lowmem = false;
-
-static int dedup_at_boot_delay_sec = 60;
-static int dedup_full_scan_interval_sec = 600;
-static int dedup_stat_interval_sec = 60;
-static int dedup_partial_scan_interval_sec = 10;
-
-static GSource *dedup_activating_timer = NULL;
-static GSource *dedup_scanning_timer = NULL;
-static GSource *dedup_stat_timer = NULL;
-
-static int dedup_do_scan(enum ksm_scan_mode);
-static int dedup_do_stat(void);
-
-/* dedup module parameters */
-enum dedup_param {
- DEDUP_PARAM_ENABLE = 0,
- DEDUP_PARAM_AT_BOOT,
- DEDUP_PARAM_AT_BOOT_DELAY,
- DEDUP_PARAM_ON_LOWMEM,
- DEDUP_PARAM_STAT_INTERVAL,
- DEDUP_PARAM_FULL_SCAN_INTERVAL,
- DEDUP_PARAM_PARTIAL_SCAN_INTERVAL,
- DEDUP_PARAM_MAX,
-};
-
-/* ksm param types & value ranges & pathes */
-enum ksm_param {
- KSM_PARAM_PAGES_TO_SCAN = 0,
- KSM_PARAM_SLEEP_MSECS,
- KSM_PARAM_FULL_SCAN_INTERVAL_MSECS,
- KSM_PARAM_SCAN_BOOST,
- KSM_PARAM_MAX,
-};
-
-static int ksm_param_ranges[KSM_PARAM_MAX][2] = {
- {0, 10000}, /* KSM_PARAM_PAGES_TO_SCAN */
- {0, 1000}, /* KSM_PARAM_SLEEP_MSECS */
- {0, INT_MAX}, /* KSM_PARAM_FULL_SCAN_INTERVAL_MSECS */
- {100, 10000}, /* KSM_PARAM_SCAN_BOOST */
-};
-static unsigned int ksm_params[KSM_PARAM_MAX];
-static const char *ksm_param_path[KSM_PARAM_MAX] = {
- "/sys/kernel/mm/ksm/pages_to_scan",
- "/sys/kernel/mm/ksm/sleep_millisecs",
- "/sys/kernel/mm/ksm/full_scan_interval",
- "/sys/kernel/mm/ksm/scan_boost",
-};
-
-/* ksm statistics */
-#define KSM_STAT_WINDOW_MAX 10
-static int ksm_stat_window;
-static unsigned int ksm_stats[KSM_STAT_MAX][KSM_STAT_WINDOW_MAX];
-static const char *ksm_stat_path[2] = {
- "/sys/kernel/mm/ksm/pages_sharing",
- "/sys/kernel/mm/ksm/pages_shared",
-};
-
-enum ksm_sysfs_state_val {
- DEDUP_SYSFS_STOP = 0,
- DEDUP_SYSFS_RUN = 1,
- DEDUP_SYSFS_ONE_SHOT = 8,
-};
-
-static inline int dedup_set_ksm_state(enum dedup_state state)
-{
- int val;
-
- if (state == DEDUP_ON)
- val = DEDUP_SYSFS_RUN;
- else if (state == DEDUP_ONE_SHOT)
- val = DEDUP_SYSFS_ONE_SHOT;
- else
- val = DEDUP_SYSFS_STOP;
- /* write value to /sys/kernel/mm/ksm/run */
- return fwrite_int(DEDUP_SYSFS_KSM_RUN, val);
-}
-
-static inline int dedup_set_ksm_param(int param_num, unsigned int value)
-{
- return fwrite_uint(ksm_param_path[param_num], value);
-}
-
-static void dedup_set_ksm_params(void)
-{
- int i;
- for (i = KSM_PARAM_PAGES_TO_SCAN; i < KSM_PARAM_MAX; i++)
- dedup_set_ksm_param(i, ksm_params[i]);
-}
-
-static int dedup_check_and_scanning_once(enum ksm_scan_mode mode)
-{
- int val;
- fread_int(DEDUP_SYSFS_KSM_ONESHOT, &val);
- if (val == KSM_SCAN_NONE)
- return fwrite_int(DEDUP_SYSFS_KSM_ONESHOT, mode);
- return 0;
-}
-
-static int dedup_scanning_once(enum ksm_scan_mode mode)
-{
- int ret;
- _D("[DEDUP] Invoke scanning once to KSM (mode: %d)", mode);
- ret = dedup_check_and_scanning_once(mode);
-
- return ret;
-}
-
-unsigned int dedup_get_ksm_stat(enum ksm_stat stat_type)
-{
- int last;
- if (stat_type < KSM_STAT_PAGES_SHARING || stat_type >= KSM_STAT_MAX)
- return 0;
- last = (ksm_stat_window == 0) ? KSM_STAT_WINDOW_MAX - 1 : ksm_stat_window - 1;
- return ksm_stats[stat_type][last];
-}
-
-static int dedup_record_stat(void)
-{
- int val, ret;
-
- ret = fread_int(ksm_stat_path[KSM_STAT_PAGES_SHARING], &val);
- if (!ret)
- ksm_stats[KSM_STAT_PAGES_SHARING][ksm_stat_window] = val;
- ret = fread_int(ksm_stat_path[KSM_STAT_PAGES_SHARED], &val);
- if (!ret)
- ksm_stats[KSM_STAT_PAGES_SHARED][ksm_stat_window] = val;
-
- _I("read ksm stat: pages_sharing: %d pages_shared: %d",
- ksm_stats[KSM_STAT_PAGES_SHARING][ksm_stat_window],
- ksm_stats[KSM_STAT_PAGES_SHARED][ksm_stat_window]);
- ksm_stat_window = (ksm_stat_window + 1) % KSM_STAT_WINDOW_MAX;
- return RESOURCED_ERROR_NONE;
-}
-
-static gboolean dedup_scanning_timer_cb(gpointer data)
-{
- dedup_scanning_timer = NULL;
- if (dedup_get_state() == DEDUP_ONE_SHOT)
- dedup_do_scan(KSM_SCAN_FULL);
- return false;
-}
-
-static gboolean dedup_stat_timer_cb(gpointer data)
-{
- dedup_stat_timer = NULL;
- dedup_do_stat();
- return false;
-}
-
-static void dedup_reset_scanning_timer(void)
-{
- _D("reset scan-timer %d seconds", dedup_full_scan_interval_sec);
- dedup_scanning_timer =
- g_timeout_source_new_seconds(dedup_full_scan_interval_sec);
- g_source_set_callback(dedup_scanning_timer,
- dedup_scanning_timer_cb, NULL, NULL);
- g_source_attach(dedup_scanning_timer, NULL);
-}
-
-static void dedup_reset_stat_timer(void)
-{
- _D("reset stat-timer %d seconds", dedup_stat_interval_sec);
- dedup_stat_timer =
- g_timeout_source_new_seconds(dedup_stat_interval_sec);
- g_source_set_callback(dedup_stat_timer,
- dedup_stat_timer_cb, NULL, NULL);
- g_source_attach(dedup_stat_timer, NULL);
-}
-
-static void dedup_deactivate_in_module(void)
-{
- if (dedup_activating_timer) {
- g_source_destroy(dedup_activating_timer);
- dedup_activating_timer = NULL;
- }
-
- if (dedup_scanning_timer) {
- g_source_destroy(dedup_scanning_timer);
- dedup_scanning_timer = NULL;
- }
-
- if (dedup_stat_timer) {
- g_source_destroy(dedup_stat_timer);
- dedup_stat_timer = NULL;
- }
-
- _D("stop KSM thread");
-
- dedup_set_ksm_state(DEDUP_OFF);
-}
-
-static enum dedup_state parse_dedup_state(enum dedup_mode mode)
-{
- if (mode == DEDUP_MODE_PERIODIC)
- return DEDUP_ON;
- else if (mode == DEDUP_MODE_ONESHOT)
- return DEDUP_ONE_SHOT;
- else
- return DEDUP_OFF;
-}
-
-static void dedup_activate_in_module(void)
-{
- enum dedup_state state;
-
- if (dedup_get_state() == DEDUP_ON
- || dedup_get_state() == DEDUP_ONE_SHOT)
- return;
-
- if (dedup_activated)
- return;
-
- /* make ksm activate */
- state = parse_dedup_state(dedup_mode);
- dedup_set_state(state);
- dedup_set_ksm_params();
- dedup_set_ksm_state(state);
- _I("kernel deduplication thread is enabled");
-
- if (dedup_activating_timer) {
- g_source_destroy(dedup_activating_timer);
- dedup_activating_timer = NULL;
- }
-
- if (!dedup_on_lowmem) {
- dedup_scanning_timer = g_timeout_source_new_seconds(dedup_full_scan_interval_sec);
- g_source_set_callback(dedup_scanning_timer, dedup_scanning_timer_cb, NULL, NULL);
- g_source_attach(dedup_scanning_timer, NULL);
- }
-
- dedup_stat_timer = g_timeout_source_new_seconds(dedup_stat_interval_sec);
- g_source_set_callback(dedup_stat_timer, dedup_stat_timer_cb, NULL, NULL);
- g_source_attach(dedup_stat_timer, NULL);
-
- dedup_activated = true;
-}
-
-#define DEDUP_ACT_MSTOS 1000
-#define DEDUP_ACT_NSTOMS 1000000
-
-static bool dedup_check_scan_interval
-(struct timespec *now, struct timespec *old, unsigned long interval_ms)
-{
- unsigned long diff_ms;
- diff_ms = (now->tv_sec - old->tv_sec) * DEDUP_ACT_MSTOS;
- diff_ms += (now->tv_nsec - old->tv_nsec) / DEDUP_ACT_NSTOMS;
- return (diff_ms >= (interval_ms * DEDUP_ACT_MSTOS));
-}
-
-/* used in dedup_do_scan */
-static struct timespec now, partial_begin, full_begin;
-static int nr_dedup;
-
-static int dedup_do_scan(enum ksm_scan_mode scan_mode)
-{
- enum ksm_scan_mode mode = KSM_SCAN_NONE;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- if (scan_mode == KSM_SCAN_FULL) {
- /* if full scan is requested frequently, it can be
- * substituted by partial scan
- */
- if (dedup_check_scan_interval(&now, &full_begin,
- dedup_full_scan_interval_sec))
- mode = KSM_SCAN_FULL;
- else if (dedup_on_lowmem &&
- dedup_check_scan_interval(&now, &partial_begin,
- dedup_partial_scan_interval_sec))
- mode = KSM_SCAN_PARTIAL;
- } else if (scan_mode == KSM_SCAN_PARTIAL) {
- if (dedup_check_scan_interval(&now, &partial_begin,
- dedup_partial_scan_interval_sec))
- mode = KSM_SCAN_PARTIAL;
- }
-
- if (mode != KSM_SCAN_NONE) {
- _I("[DEDUP] dedup: %d-th %s deduplication triggering", nr_dedup++,
- (mode == KSM_SCAN_FULL ? "FULL" : "PARTIAL"));
- if (!dedup_on_lowmem) {
- dedup_scanning_once(KSM_SCAN_FULL);
- dedup_reset_scanning_timer();
- } else
- dedup_scanning_once(mode);
-
- if (mode == KSM_SCAN_FULL)
- full_begin = now;
- else
- partial_begin = now;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int dedup_do_stat(void)
-{
- dedup_record_stat();
- dedup_reset_stat_timer();
- return RESOURCED_ERROR_NONE;
-}
-
-static int dedup_start_handler(void *data)
-{
- if (!data)
- return RESOURCED_ERROR_NO_DATA;
-
- dedup_activate_in_module();
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int dedup_scan_handler(void *data)
-{
- int *scan_mode;
-
- if (dedup_get_state() != DEDUP_ONE_SHOT)
- return 0;
-
- if (dedup_scanning_timer) {
- g_source_destroy(dedup_scanning_timer);
- dedup_scanning_timer = NULL;
- }
-
- scan_mode = data;
- return dedup_do_scan(*scan_mode);
-}
-
-static int dedup_stop_handler(void *data)
-{
- if (!data)
- return RESOURCED_ERROR_NO_DATA;
-
- dedup_deactivate_in_module();
-
- return RESOURCED_ERROR_NONE;
-}
-
-static gboolean dedup_activate_timer_cb(gpointer data)
-{
- dedup_activating_timer = NULL;
- _D("[DEDUP] dedup activating callback called");
- dedup_activate_in_module();
- return false;
-}
-
-static int dedup_booting_done(void *data)
-{
- if (dedup_activated)
- return RESOURCED_ERROR_NONE;
-
- if (dedup_at_boot_enable) {
- /* if dedup_at_boot_enable is disabled,
- * other daemon should activate dedup */
- _D("[DEDUP] dedup booting done is called");
- if (dedup_at_boot_delay_sec > 0)
- dedup_activating_timer =
- g_timeout_source_new_seconds(dedup_at_boot_delay_sec);
- else
- dedup_activating_timer =
- g_timeout_source_new_seconds(DEDUP_ON_BOOT_TIME);
- g_source_set_callback(dedup_activating_timer,
- dedup_activate_timer_cb, NULL, NULL);
- g_source_attach(dedup_activating_timer, NULL);
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int dedup_parse_config_file(void)
-{
- int arg_ksm_pages_to_scan = 100;
- int arg_ksm_sleep_ms = 20; // 20 msecs
- int arg_ksm_full_scan_interval_ms = 60000; // 60 seconds
- int arg_ksm_scan_boost = 1000;
-
- struct dedup_conf *dedup_conf = get_dedup_conf();
- if (!dedup_conf) {
- _E("Dedup configuration should not be NULL");
- return RESOURCED_ERROR_FAIL;
- }
-
- dedup_enable = dedup_conf->enable;
- if (!dedup_enable)
- goto free_dedup_conf;
-
- if (!strncmp(dedup_conf->ksm.mode, "oneshot", 8))
- dedup_mode = DEDUP_MODE_ONESHOT;
- else if(!strncmp(dedup_conf->ksm.mode, "periodic", 9))
- dedup_mode = DEDUP_MODE_PERIODIC;
- else {
- dedup_enable = false;
- goto free_dedup_conf;
- }
-
- dedup_at_boot_enable = dedup_conf->boot_dedup_enable;
- dedup_on_lowmem = dedup_conf->scan_on_lowmem;
-
- if (dedup_conf->ksm.pages > ksm_param_ranges[KSM_PARAM_PAGES_TO_SCAN][0] &&
- dedup_conf->ksm.pages <= ksm_param_ranges[KSM_PARAM_PAGES_TO_SCAN][1])
- ksm_params[KSM_PARAM_PAGES_TO_SCAN] = dedup_conf->ksm.pages;
- else
- ksm_params[KSM_PARAM_PAGES_TO_SCAN] = arg_ksm_pages_to_scan;
-
- if (dedup_conf->ksm.boost_pages > ksm_param_ranges[KSM_PARAM_SCAN_BOOST][0] &&
- dedup_conf->ksm.boost_pages <= ksm_param_ranges[KSM_PARAM_SCAN_BOOST][1])
- ksm_params[KSM_PARAM_SCAN_BOOST] = dedup_conf->ksm.boost_pages;
- else
- ksm_params[KSM_PARAM_SCAN_BOOST] = arg_ksm_scan_boost;
-
- ksm_params[KSM_PARAM_SLEEP_MSECS] = arg_ksm_sleep_ms;
- ksm_params[KSM_PARAM_FULL_SCAN_INTERVAL_MSECS] = arg_ksm_full_scan_interval_ms;
-
- _I("[DEDUP] deduplication mode: %s", dedup_mode == DEDUP_MODE_PERIODIC ?
- "kernel-managed" : "resourced-triggered");
- _I("[DEDUP] deduplication on boot: %s", dedup_at_boot_enable ? "true" : "false");
- _I("[DEDUP] scanning is invoked by %s", dedup_on_lowmem ?
- "LOWMEM event" : "periodic timer");
- _I("[DEDUP] full scan interval: %d sec", dedup_full_scan_interval_sec);
- _I("[DEDUP] stat monitoring interval: %d sec", dedup_stat_interval_sec);
-
- _I("[DEDUP] ksm pages to scan: %d", ksm_params[KSM_PARAM_PAGES_TO_SCAN]);
- _I("[DEDUP] ksm sleep time: %d ms", ksm_params[KSM_PARAM_SLEEP_MSECS]);
- _I("[DEDUP] ksm full scan interval: %d ms", ksm_params[KSM_PARAM_FULL_SCAN_INTERVAL_MSECS]);
- _I("[DEDUP] ksm scan boost: %d", ksm_params[KSM_PARAM_SCAN_BOOST]);
-
-free_dedup_conf:
- free_dedup_conf();
-
- return RESOURCED_ERROR_NONE;
-}
-
-static inline void init_dedup_stat(void)
-{
- int i, j;
- for (i = KSM_STAT_PAGES_SHARING; i < KSM_STAT_MAX; i++)
- for (j = 0; j < KSM_STAT_WINDOW_MAX; j++)
- ksm_stats[i][j] = 0;
- ksm_stat_window = 0;
-}
-
-static int dedup_init(void)
-{
- int ret;
-
- init_dedup_stat();
- ret = dedup_parse_config_file();
- if (ret < 0)
- return ret;
-
- if (!dedup_enable)
- return -ENODEV;
-
- /* initialize time variables */
- if (!clock_gettime(CLOCK_MONOTONIC, &now)) {
- partial_begin = now;
- full_begin = now;
- } else {
- _I("Time initialization failed");
- memset(&partial_begin, 0, sizeof(struct timespec));
- memset(&full_begin, 0, sizeof(struct timespec));
- }
-
- return ret;
-}
-
-static int resourced_dedup_check_runtime_support(void *data)
-{
- /*
- * Check whether CONFIG_LKSM is enabled in kernel.
- */
- if (access("/sys/kernel/mm/ksm/run", R_OK) != 0) {
- _I("the kernel doesn't support KSM, please check kernel configuration");
- return -ENOENT;
- }
- if (access("/sys/kernel/mm/ksm/one_shot_scanning", R_OK) != 0) {
- _I("the kernel support KSM but not LKSM, please check kernel configuration");
- return -ENOENT;
- }
-
- return 0;
-}
-
-static int resourced_dedup_init(void *data)
-{
- int ret;
-
- dedup_set_state(DEDUP_OFF);
-
- ret = dedup_init();
- if (ret != RESOURCED_ERROR_NONE)
- return ret;
- _I("resourced dedup module is initialized");
- register_notifier(RESOURCED_NOTIFIER_DEDUP_START, dedup_start_handler);
- register_notifier(RESOURCED_NOTIFIER_DEDUP_SCAN, dedup_scan_handler);
- register_notifier(RESOURCED_NOTIFIER_DEDUP_STOP, dedup_stop_handler);
- register_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, dedup_booting_done);
-
- return ret;
-}
-
-static int resourced_dedup_finalize(void *data)
-{
- unregister_notifier(RESOURCED_NOTIFIER_DEDUP_START, dedup_start_handler);
- unregister_notifier(RESOURCED_NOTIFIER_DEDUP_SCAN, dedup_scan_handler);
- unregister_notifier(RESOURCED_NOTIFIER_DEDUP_STOP, dedup_stop_handler);
- unregister_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, dedup_booting_done);
-
- dedup_deactivate_in_module();
-
- _I("dedup module will be finalized");
-
- return RESOURCED_ERROR_NONE;
-}
-
-static struct module_ops dedup_module_ops = {
- .priority = MODULE_PRIORITY_NORMAL,
- .name = "dedup",
- .init = resourced_dedup_init,
- .exit = resourced_dedup_finalize,
- .check_runtime_support = resourced_dedup_check_runtime_support,
-};
-
-MODULE_REGISTER(&dedup_module_ops)